@brainervirus/workit-cursor 0.9.2 → 0.11.0

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": "OpenCode-style verify, PR, changelog, commit, and session handoff for Cursor",
5
- "version": "0.9.2",
5
+ "version": "0.11.0",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
package/README.md CHANGED
@@ -46,7 +46,7 @@ npx @brainervirus/workit-cli init
46
46
 
47
47
  ## Host limitations
48
48
 
49
- Cursor adapts workit through policy-only confirmation: approvals and lifecycle transitions are recorded as policy decisions (`attested: false`) rather than fabricated delegated identity, and subagent-driven plan execution is not supported on this host. Cursor consumes the same core outcomes but stays inline-only (the subagent-driven menu choice returns `unsupported_mode`); model selection remains a host-native action. Approvals bind to the document's exact SHA-256 digest — editing an approved spec/plan invalidates the approval and forces a fresh reapproval. OpenCode records native `question` receipts and runs delegated tasks; see the root [README](../../README.md#host-capabilities) for the full host-capability matrix.
49
+ Cursor adapts workit through policy-only confirmation: approvals and lifecycle transitions are recorded as policy decisions (`attested: false`) rather than fabricated delegated identity; model selection remains a host-native action. Both execution modes are supported: **Subagent-driven** `workit_plan_menu` returns a one-time `coordinator_lease`, `workit_delegate` mints a task-scoped `delegation_token` per task (fail-closed validation; only hashes persist), and the coordinator dispatches Cursor-native subagents that pass the token as `delegation_token` on mutation calls (the task token is revoked when the worker's progress line lands); **Inline** `executing-plans` runs every task single-agent in the current session with no dispatch and no token minting. Approvals bind to the document's exact SHA-256 digest — editing an approved spec/plan invalidates the approval and forces a fresh reapproval. OpenCode records native `question` receipts and derives delegated status from session parentage (`parentID`), which Cursor does not have; see the root [README](../../README.md#host-capabilities) for the full host-capability matrix.
50
50
 
51
51
  ## Configuration
52
52
 
@@ -24,10 +24,10 @@ This session is a handoff destination for a continued plan. The originating sess
24
24
  - Working state, briefs, ledgers, and review diffs live only under gitignored `<SDD_DIR>` in `docs/<slug>/sdd/` and use `workit_sdd_*` tools.
25
25
  - Use native `todowrite` for visible task state as well as the gitignored ledger.
26
26
  - Use native `question` for branch/stash choices and guarded external mutations; call mutation tools only after approval with `confirmed: true` (grounded in the recorded NativeChoiceEvidence).
27
- - Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`) and subagent-driven execution is rejected as unsupported.
27
+ - Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`), Subagent-driven execution is supported through the one-time `coordinator_lease` and per-task `delegation_token` minted by `workit_delegate` (fail-closed validation; no `parentID` identity exists on Cursor), and Inline runs single-agent in the current session.
28
28
  - Delegated authority is direct-child-only: a worker is the session whose host `parentID` exactly equals the activating coordinator's recorded `coordinator_session_id`; missing, mismatched, or multi-owner lineage fails closed with `delegation_lineage_denied`, and nested `opencode` launches are denied during active delegated work. An authorized child receives only the compact worker contract (execute the supplied brief, follow TDD, land one contiguous non-empty commit range, report results) — never coordinator guidance, `wk-implement`, or ledger management; coordinator bookkeeping via `workit_sdd_*` stays with the coordinator session.
29
29
  - On Cursor, for every repository-scoped `workit_*` call, pass the active Cursor workspace as `workspace_root`; never rely on the MCP process default.
30
- - Use native `task` with only the built-in `explore` and `general` agents.
30
+ - Use native `task` with only the built-in `explore` and `general` agents (OpenCode); on Cursor, Subagent-driven dispatches Cursor-native subagents with a task `delegation_token`, Inline runs single-agent in the current session.
31
31
 
32
32
  ## Flow gates (HARD)
33
33
 
@@ -51,7 +51,7 @@ For each top-level task absent from `completed_task_ids`:
51
51
 
52
52
  1. Mark it `in_progress` with `todowrite`.
53
53
  2. Create a working-state brief with `workit_sdd_task_brief` and `confirmed: true`.
54
- 3. Delegate read-only discovery, when needed, to an `explore` agent. Delegate implementation to a fresh `general` agent. Product changes follow TDD.
54
+ 3. Route by the approved execution mode: **Subagent-driven** delegates read-only discovery to an `explore` (OpenCode) agent, delegates implementation to a fresh `general` (OpenCode) agent (on Cursor, the coordinator mints a `delegation_token` with `workit_delegate` and the subagent prompt carries the raw token — the worker passes it as `delegation_token` on its mutation calls, and appending progress revokes it), and the coordinator never edits product code; **Inline** executes every task in the current agent with no dispatch and no token minting. Product changes follow TDD.
55
55
  4. Create a working-state diff with `workit_sdd_review_package` and `confirmed: true`.
56
56
  5. Delegate spec-compliance review and code-quality review to separate `general` agents.
57
57
  6. **Blocking** findings (Critical, Important, or spec-compliance) may trigger at most **two** fix+re-review rounds per task. **Advisory** findings (Minor, style, YAGNI, taste) never pause the loop — append them with `workit_sdd_append_advisory` (`--task <id> --text <text>`, `confirmed: true`) instead of an unrestricted file edit.
@@ -1,6 +1,6 @@
1
1
  # <Feature> Implementation Plan
2
2
 
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. On Cursor the two paths are: **Subagent-driven** — Cursor-native subagents dispatched by the coordinator, each carrying a task-scoped `delegation_token` minted with `workit_delegate` from the one-time `coordinator_lease`; **Inline** — `executing-plans` in the current session, single-agent, no dispatch, no token minting. Steps use checkbox (`- [ ]`) syntax for tracking.
4
4
 
5
5
  **Spec:** `docs/<slug>/spec.md`
6
6
  **Branch:** `feature/<slug>`
@@ -1,6 +1,6 @@
1
1
  # Superpowers document contract
2
2
 
3
- Use OpenCode's native `question` for every bounded user choice. Give concise choices and allow a custom answer; if the tool is unavailable, ask one concise plain-text question. Use `skill` to load workflow and Superpowers skills, `todowrite` for task state, and `task` for delegated work.
3
+ Use OpenCode's native `question` for every bounded user choice. Give concise choices and allow a custom answer; if the tool is unavailable, ask one concise plain-text question. Use `skill` to load workflow and Superpowers skills, `todowrite` for task state, and `task` for delegated work (OpenCode) or the host-native equivalent — on Cursor, Subagent-driven dispatches Cursor-native subagents with a task `delegation_token`, Inline runs single-agent in the current session.
4
4
 
5
5
  ## Tracked document layout
6
6
 
@@ -35,7 +35,7 @@ Before writing **Branch:** into a new spec or plan, call `workit_docs_branch` an
35
35
  - Commits use `wk-commit` after its native `question` confirmation.
36
36
  - Continuation uses `wk-handoff`, whose `workit_handoff_session` creates and seeds the OpenCode session automatically.
37
37
  - Never use worktrees. Resolve the declared branch with `workit_resolve_branch`, preview dirty-tree stash choices with `question`, and apply an approved in-place checkout through `workit_branch_setup` with `confirmed: true` (grounded in the recorded NativeChoiceEvidence).
38
- - Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`) and subagent-driven execution is rejected as unsupported.
38
+ - Flow-tool confirmations are never agent-typed booleans and never caller-supplied evidence objects: on OpenCode the plugin records the user's native-`question` answer as a host-observed one-use receipt (`attested: true`, `callID`, `selectedLabel`, `recordedAt`) consumed by `workit_spec_approve` / `workit_plan_approve` / `workit_plan_menu` — no evidence argument exists, and delegated worker status comes from host session parentage (`parentID`), never a caller `role` field. On Cursor, confirmations are policy-only (`attested: false`), Subagent-driven execution is supported through the one-time `coordinator_lease` and per-task `delegation_token` minted by `workit_delegate` (fail-closed validation; no `parentID` identity exists on Cursor), and Inline runs single-agent in the current session.
39
39
  - Keep all SDD state under the gitignored `docs/<slug>/sdd/`; use `workit_sdd_context` and the registered `workit_sdd_*` tools.
40
40
  - After implementation, use `question` before an approved stash reapply through `workit_branch_setup` with `confirmed: true`.
41
41
 
@@ -20376,7 +20376,7 @@ var init_config = __esm(() => {
20376
20376
  "trunk-based": { allowed: ["*"], protected: ["main"] },
20377
20377
  custom: { allowed: [], protected: [] }
20378
20378
  };
20379
- LOCALE_RE = /^[a-z]{2,3}(-[A-Z]{2})?$/;
20379
+ LOCALE_RE = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
20380
20380
  DEFAULTS = {
20381
20381
  locale: "en",
20382
20382
  localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
@@ -24576,7 +24576,7 @@ import {
24576
24576
  unlinkSync as unlinkSync3,
24577
24577
  writeFileSync as writeFileSync6
24578
24578
  } from "node:fs";
24579
- import { createHash as createHash2 } from "node:crypto";
24579
+ import { createHash as createHash2, randomBytes } from "node:crypto";
24580
24580
  import path20 from "node:path";
24581
24581
 
24582
24582
  class HostReceiptStore {
@@ -24666,7 +24666,7 @@ class HostReceiptStore {
24666
24666
  return { ok: true, receipt };
24667
24667
  }
24668
24668
  }
24669
- var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, err2 = (code, error2, details) => ({
24669
+ var COORDINATOR_RECOVERY_TEXT, MENU_CHOICES, err2 = (code, error2, details) => ({
24670
24670
  ok: false,
24671
24671
  code,
24672
24672
  error: error2,
@@ -24714,18 +24714,39 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
24714
24714
  status: execution.status ?? "pending",
24715
24715
  mode: execution.mode ?? null,
24716
24716
  evidence: execution.evidence ?? null,
24717
- coordinator_session_id: execution.coordinator_session_id ?? null
24717
+ coordinator_session_id: execution.coordinator_session_id ?? null,
24718
+ ...execution.delegation !== undefined ? { delegation: normalizeDelegation(execution.delegation) } : {}
24718
24719
  },
24719
24720
  handoff_destination: p.handoff_destination ?? false,
24720
24721
  updated_at: p.updated_at ?? Date.now()
24721
24722
  };
24722
- }, emptyState = (slug) => ({
24723
+ }, normalizeDelegation = (v) => {
24724
+ if (v === null || v === undefined)
24725
+ return null;
24726
+ if (!isRecord(v))
24727
+ return null;
24728
+ const hash = (x) => typeof x === "string" && HEX64_RE.test(x) ? x : null;
24729
+ return {
24730
+ coordinator_lease_hash: hash(v.coordinator_lease_hash),
24731
+ active_task_id: typeof v.active_task_id === "number" && Number.isSafeInteger(v.active_task_id) ? v.active_task_id : null,
24732
+ token_hash: hash(v.token_hash),
24733
+ token_workspace: typeof v.token_workspace === "string" ? v.token_workspace : null,
24734
+ token_slug: typeof v.token_slug === "string" ? v.token_slug : null,
24735
+ status: v.status === "active" ? "active" : "revoked"
24736
+ };
24737
+ }, delegationHash = (raw) => createHash2("sha256").update(raw).digest("hex"), emptyState = (slug) => ({
24723
24738
  slug,
24724
24739
  activated: false,
24725
24740
  spec: { path: "", status: "draft", evidence: null, approved_digest: null },
24726
24741
  plan: { path: "", status: "draft", evidence: null, approved_digest: null },
24727
24742
  menu: { presented: false, chosen: "", evidence: null },
24728
- execution: { status: "pending", mode: null, evidence: null, coordinator_session_id: null },
24743
+ execution: {
24744
+ status: "pending",
24745
+ mode: null,
24746
+ evidence: null,
24747
+ coordinator_session_id: null,
24748
+ delegation: null
24749
+ },
24729
24750
  handoff_destination: false,
24730
24751
  updated_at: Date.now()
24731
24752
  }), readFlowState = (root, slug) => {
@@ -24856,7 +24877,8 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
24856
24877
  status: execRaw?.status ?? "pending",
24857
24878
  mode: execRaw?.mode ?? null,
24858
24879
  evidence: execRaw?.evidence ?? null,
24859
- coordinator_session_id: execRaw?.coordinator_session_id ?? null
24880
+ coordinator_session_id: execRaw?.coordinator_session_id ?? null,
24881
+ ...execRaw?.delegation !== undefined ? { delegation: normalizeDelegation(execRaw.delegation) } : {}
24860
24882
  },
24861
24883
  handoff_destination: parsed.handoff_destination ?? false,
24862
24884
  updated_at: parsed.updated_at ?? Date.now()
@@ -24983,7 +25005,13 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
24983
25005
  spec: { ...state.spec, status: "draft", evidence: null, approved_digest: null },
24984
25006
  plan: { ...state.plan, status: "draft", evidence: null, approved_digest: null },
24985
25007
  menu: { presented: false, chosen: "", evidence: null },
24986
- execution: { status: "pending", mode: null, evidence: null, coordinator_session_id: null },
25008
+ execution: {
25009
+ status: "pending",
25010
+ mode: null,
25011
+ evidence: null,
25012
+ coordinator_session_id: null,
25013
+ ...state.execution.delegation !== undefined ? { delegation: null } : {}
25014
+ },
24987
25015
  handoff_destination: false,
24988
25016
  updated_at: Date.now()
24989
25017
  }), resetForPlanDrift = (state) => ({
@@ -25029,7 +25057,12 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
25029
25057
  coordinator_session_id: null
25030
25058
  };
25031
25059
  }
25032
- return { status: "pending", mode: null, evidence: null, coordinator_session_id: null };
25060
+ return {
25061
+ status: "pending",
25062
+ mode: null,
25063
+ evidence: null,
25064
+ coordinator_session_id: null
25065
+ };
25033
25066
  }, normalizeCompatibility = (root, slug, parsed, state) => {
25034
25067
  if (!isRecord(parsed) || !("execution" in parsed)) {
25035
25068
  const derived = deriveLegacyExecution(root, slug, state);
@@ -25310,7 +25343,12 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
25310
25343
  spec: { path: specPath, status: "draft", evidence: null, approved_digest: null },
25311
25344
  plan: { path: planPath, status: "draft", evidence: null, approved_digest: null },
25312
25345
  menu: { presented: false, chosen: "", evidence: null },
25313
- execution: { status: "pending", mode: null, evidence: null, coordinator_session_id: null },
25346
+ execution: {
25347
+ status: "pending",
25348
+ mode: null,
25349
+ evidence: null,
25350
+ coordinator_session_id: null
25351
+ },
25314
25352
  handoff_destination: false,
25315
25353
  updated_at: Date.now()
25316
25354
  });
@@ -25435,16 +25473,16 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
25435
25473
  if (typeof choice !== "string" || !MENU_CHOICES.includes(choice)) {
25436
25474
  return err2("menu_choice_invalid", `invalid menu choice: ${JSON.stringify(choice)}`);
25437
25475
  }
25438
- if (recorded.evidence.host === "cursor" && choice === "subagent-driven") {
25439
- return err2("unsupported_mode", CURSOR_SUBAGENT_UNSUPPORTED_TEXT);
25440
- }
25441
25476
  if (recorded.evidence.host === "opencode" && !sameChoiceLabel(recorded.evidence.selectedLabel, choice)) {
25442
25477
  return err2("evidence_mismatch", `evidence selectedLabel ${JSON.stringify(recorded.evidence.selectedLabel)} does not match choice ${JSON.stringify(choice)}`);
25443
25478
  }
25444
25479
  const doc2 = resolveDoc(root, slug, planPath, "plan");
25445
25480
  if (!doc2.ok)
25446
25481
  return err2("path_invalid", doc2.error);
25447
- return readModifyWrite(root, slug, (state) => {
25482
+ const cursorSubagent = recorded.evidence.host === "cursor" && choice === "subagent-driven";
25483
+ const lease = cursorSubagent ? randomBytes(32).toString("hex") : null;
25484
+ const leaseHash = lease === null ? null : delegationHash(lease);
25485
+ const result = readModifyWrite(root, slug, (state) => {
25448
25486
  if (state.spec.status !== "approved")
25449
25487
  return err2("spec_not_approved", "spec must be approved before the execution menu");
25450
25488
  if (state.plan.status !== "approved")
@@ -25454,6 +25492,14 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
25454
25492
  }
25455
25493
  const executing = choice === "subagent-driven" || choice === "inline";
25456
25494
  const coordinatorSessionId = choice === "subagent-driven" && recorded.evidence.host === "opencode" ? ctx?.sessionId ?? null : null;
25495
+ const delegation = cursorSubagent ? {
25496
+ coordinator_lease_hash: leaseHash,
25497
+ active_task_id: null,
25498
+ token_hash: null,
25499
+ token_workspace: null,
25500
+ token_slug: null,
25501
+ status: "active"
25502
+ } : state.execution.delegation;
25457
25503
  return {
25458
25504
  ok: true,
25459
25505
  next: {
@@ -25464,17 +25510,133 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
25464
25510
  status: "active",
25465
25511
  mode: choice,
25466
25512
  evidence: recorded.evidence,
25467
- coordinator_session_id: coordinatorSessionId
25513
+ coordinator_session_id: coordinatorSessionId,
25514
+ delegation
25468
25515
  } : {
25469
25516
  status: "pending",
25470
25517
  mode: null,
25471
25518
  evidence: recorded.evidence,
25472
- coordinator_session_id: null
25519
+ coordinator_session_id: null,
25520
+ delegation
25521
+ },
25522
+ updated_at: Date.now()
25523
+ }
25524
+ };
25525
+ });
25526
+ if (!result.ok)
25527
+ return result;
25528
+ return cursorSubagent && lease !== null ? { ok: true, coordinator_lease: lease } : { ok: true };
25529
+ }, mintDelegateToken = (root, slug, planPath, taskId, coordinatorLease) => {
25530
+ if (typeof taskId !== "number" || !Number.isSafeInteger(taskId) || taskId <= 0) {
25531
+ return err2("task_invalid", `task id must be a positive safe integer: ${JSON.stringify(taskId)}`);
25532
+ }
25533
+ if (typeof coordinatorLease !== "string" || coordinatorLease === "") {
25534
+ return err2("coordinator_lease_invalid", "a coordinator lease is required to mint a delegation token");
25535
+ }
25536
+ const doc2 = resolveDoc(root, slug, planPath, "plan");
25537
+ if (!doc2.ok)
25538
+ return err2("path_invalid", doc2.error);
25539
+ const token = randomBytes(32).toString("hex");
25540
+ const tokenHash = delegationHash(token);
25541
+ const result = readModifyWrite(root, slug, (state) => {
25542
+ const exec = state.execution;
25543
+ if (exec.status !== "active" || exec.mode !== "subagent-driven") {
25544
+ return err2("flow_not_active", "a delegation token requires an active subagent-driven execution");
25545
+ }
25546
+ const delegation = exec.delegation;
25547
+ if (!delegation || delegation.status !== "active" || !delegation.coordinator_lease_hash) {
25548
+ return err2("coordinator_lease_invalid", "this flow has no active coordinator lease — record the execution menu with Cursor subagent-driven first");
25549
+ }
25550
+ if (delegation.coordinator_lease_hash !== delegationHash(coordinatorLease)) {
25551
+ return err2("coordinator_lease_invalid", "the supplied coordinator lease does not match the flow's recorded lease");
25552
+ }
25553
+ if (state.plan.status !== "approved") {
25554
+ return err2("plan_not_approved", "plan must be approved before delegating a task");
25555
+ }
25556
+ let planText;
25557
+ try {
25558
+ planText = readFileSync13(doc2.path, "utf8");
25559
+ } catch {
25560
+ return err2("plan_missing", `plan not found: ${planPath}`);
25561
+ }
25562
+ if (!parseTasksFromPlan(planText).some((t) => t.id === taskId)) {
25563
+ return err2("task_invalid", `task ${taskId} does not exist in the approved plan`);
25564
+ }
25565
+ if (ledgerCompletion(root, slug).completed.includes(taskId)) {
25566
+ return err2("task_completed", `task ${taskId} is already completed in the SDD ledger`);
25567
+ }
25568
+ return {
25569
+ ok: true,
25570
+ next: {
25571
+ ...state,
25572
+ execution: {
25573
+ ...exec,
25574
+ delegation: {
25575
+ ...delegation,
25576
+ active_task_id: taskId,
25577
+ token_hash: tokenHash,
25578
+ token_workspace: root,
25579
+ token_slug: slug,
25580
+ status: "active"
25581
+ }
25473
25582
  },
25474
25583
  updated_at: Date.now()
25475
25584
  }
25476
25585
  };
25477
25586
  });
25587
+ if (!result.ok)
25588
+ return result;
25589
+ return { ok: true, token };
25590
+ }, validateDelegateToken = (root, token) => {
25591
+ if (typeof token !== "string" || token === "") {
25592
+ return err2("delegation_token_invalid", "a delegation token is required");
25593
+ }
25594
+ const hash = delegationHash(token);
25595
+ let entries = [];
25596
+ try {
25597
+ entries = readdirSync7(path20.join(root, "docs"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
25598
+ } catch {
25599
+ return err2("delegation_token_invalid", `no flows exist under ${JSON.stringify(root)}`);
25600
+ }
25601
+ for (const slug of entries) {
25602
+ try {
25603
+ const state = readFlowState(root, slug);
25604
+ const delegation = state.execution.delegation;
25605
+ if (!delegation || !delegation.token_hash)
25606
+ continue;
25607
+ if (delegation.token_hash !== hash)
25608
+ continue;
25609
+ if (delegation.token_workspace !== root || delegation.token_slug !== slug)
25610
+ continue;
25611
+ if (delegation.status !== "active" || state.execution.status !== "active" || state.execution.mode !== "subagent-driven" || delegation.active_task_id === null) {
25612
+ return err2("delegation_token_revoked", "the delegation token is no longer active for this flow");
25613
+ }
25614
+ return {
25615
+ ok: true,
25616
+ context: { slug, taskId: delegation.active_task_id, hostWorkspace: root }
25617
+ };
25618
+ } catch {}
25619
+ }
25620
+ return err2("delegation_token_invalid", "the delegation token does not match any active flow token in this workspace");
25621
+ }, revokeDelegateToken = (root, slug, taskId) => {
25622
+ if (typeof taskId !== "number" || !Number.isSafeInteger(taskId) || taskId <= 0) {
25623
+ return err2("task_invalid", `task id must be a positive safe integer: ${JSON.stringify(taskId)}`);
25624
+ }
25625
+ return readModifyWrite(root, slug, (state) => {
25626
+ const exec = state.execution;
25627
+ const delegation = exec.delegation;
25628
+ if (!delegation || delegation.status !== "active" || delegation.active_task_id !== taskId || !delegation.token_hash) {
25629
+ return err2("delegation_token_not_active", `no active delegation token for task ${taskId} in ${slug}`);
25630
+ }
25631
+ return {
25632
+ ok: true,
25633
+ next: {
25634
+ ...state,
25635
+ execution: { ...exec, delegation: { ...delegation, status: "revoked" } },
25636
+ updated_at: Date.now()
25637
+ }
25638
+ };
25639
+ });
25478
25640
  }, markHandoffDestination = (root, slug, planPath) => {
25479
25641
  const doc2 = resolveDoc(root, slug, planPath, "plan");
25480
25642
  if (!doc2.ok)
@@ -25656,7 +25818,6 @@ var init_flow_state = __esm(() => {
25656
25818
  init_verify_project();
25657
25819
  init_menu();
25658
25820
  COORDINATOR_RECOVERY_TEXT = "A subagent-driven plan is active: coordinator product edits are blocked. " + "Delegate product mutations to an authenticated delegated worker via `task` / `wk-implement` instead of " + "editing in the coordinator session.";
25659
- CURSOR_SUBAGENT_UNSUPPORTED_TEXT = "Cursor cannot execute subagent-driven plans: the MCP has no child-session " + "support. Choose Inline, Handoff, or a review option in this session, or " + "run the plan in OpenCode with `wk-implement`.";
25660
25821
  MENU_CHOICES = [
25661
25822
  "subagent-driven",
25662
25823
  "inline",
@@ -25810,12 +25971,30 @@ var init_flow_state = __esm(() => {
25810
25971
  });
25811
25972
 
25812
25973
  // packages/workit-cursor/mcp/flow-evidence.ts
25813
- var cursorQuestionEvidence = () => createCursorConfirmation(), CURSOR_HOST = "cursor", cursorMutationContext = (workspaceRoot) => ({
25974
+ var cursorQuestionEvidence = () => createCursorConfirmation(), CURSOR_HOST = "cursor", cursorCoordinatorContext = (workspaceRoot) => ({
25814
25975
  hostWorkspace: workspaceRoot,
25815
25976
  role: "coordinator",
25816
25977
  sessionId: `${CURSOR_HOST}:${workspaceRoot}`,
25817
25978
  taskIdentity: undefined
25818
- });
25979
+ }), cursorMutationContext = (workspaceRoot, delegationToken) => {
25980
+ if (delegationToken === undefined) {
25981
+ return { ok: true, context: cursorCoordinatorContext(workspaceRoot) };
25982
+ }
25983
+ const validated = validateDelegateToken(workspaceRoot, delegationToken);
25984
+ if (!validated.ok) {
25985
+ return { ok: false, code: validated.code, error: validated.error };
25986
+ }
25987
+ return {
25988
+ ok: true,
25989
+ slug: validated.context.slug,
25990
+ context: {
25991
+ hostWorkspace: workspaceRoot,
25992
+ role: "delegated",
25993
+ sessionId: `${CURSOR_HOST}:${workspaceRoot}:task-${validated.context.taskId}`,
25994
+ taskIdentity: String(validated.context.taskId)
25995
+ }
25996
+ };
25997
+ };
25819
25998
  var init_flow_evidence = __esm(() => {
25820
25999
  init_flow_state();
25821
26000
  });
@@ -27874,7 +28053,7 @@ var logger, readServerVersion = () => {
27874
28053
  if (!result.ok)
27875
28054
  throw new Error(result.error);
27876
28055
  return result.evidence;
27877
- }, workspaceRootSchema, server, registerTool = (name, config2, cb) => {
28056
+ }, workspaceRootSchema, delegationTokenSchema, server, registerTool = (name, config2, cb) => {
27878
28057
  server.registerTool(name, config2, async (args) => {
27879
28058
  try {
27880
28059
  return await cb(args);
@@ -27901,7 +28080,7 @@ var logger, readServerVersion = () => {
27901
28080
  return jsonResult(withWorkspace(workspace_root, { error: resolved.error }));
27902
28081
  }
27903
28082
  const { workspace, slug } = resolved.layout;
27904
- const result = transitionExecution(workspace, slug, plan_path, action, cursorConfirmation(), cursorMutationContext(workspace));
28083
+ const result = transitionExecution(workspace, slug, plan_path, action, cursorConfirmation(), cursorCoordinatorContext(workspace));
27905
28084
  if (result.ok === false) {
27906
28085
  return jsonResult(withWorkspace(workspace_root, {
27907
28086
  error: result.error,
@@ -27965,6 +28144,7 @@ var init_server3 = __esm(async () => {
27965
28144
  process.exit(1);
27966
28145
  });
27967
28146
  workspaceRootSchema = exports_external.string().optional().default(() => process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd()).describe("Git repository root. Defaults to the launcher workspace (WORKFLOW_WORKSPACE_ROOT), then the Cursor workspace folder (${workspaceFolder}), then the process cwd.");
28147
+ delegationTokenSchema = exports_external.string().optional().describe("Task-scoped delegation token from workit_delegate for delegated workers.");
27968
28148
  server = new McpServer({
27969
28149
  name: "workit",
27970
28150
  version: VERSION
@@ -28067,9 +28247,13 @@ var init_server3 = __esm(async () => {
28067
28247
  body: exports_external.string().optional(),
28068
28248
  draft: exports_external.boolean().optional(),
28069
28249
  target_branch: exports_external.string().optional(),
28250
+ delegation_token: delegationTokenSchema,
28070
28251
  workspace_root: workspaceRootSchema
28071
28252
  }
28072
- }, async ({ confirmed, title, body, draft, target_branch, workspace_root }) => {
28253
+ }, async ({ confirmed, title, body, draft, target_branch, delegation_token, workspace_root }) => {
28254
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28255
+ if (!identity.ok)
28256
+ return jsonResult({ error: identity.error, code: identity.code });
28073
28257
  if (!confirmed)
28074
28258
  return jsonResult({ error: "confirmed: true required" });
28075
28259
  const data = prCreate({
@@ -28131,9 +28315,13 @@ var init_server3 = __esm(async () => {
28131
28315
  ]).optional(),
28132
28316
  normalize_only: exports_external.boolean().optional().describe("If true, only collapse duplicate ### headings under [Unreleased] (no new bullets)."),
28133
28317
  path: exports_external.string().optional().describe("Defaults to CHANGELOG.md"),
28318
+ delegation_token: delegationTokenSchema,
28134
28319
  workspace_root: workspaceRootSchema
28135
28320
  }
28136
- }, async ({ entries, normalize_only, path: changelogPath, workspace_root }) => {
28321
+ }, async ({ entries, normalize_only, path: changelogPath, delegation_token, workspace_root }) => {
28322
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28323
+ if (!identity.ok)
28324
+ return jsonResult({ error: identity.error, code: identity.code });
28137
28325
  const data = changelogApply({
28138
28326
  entries,
28139
28327
  path: changelogPath,
@@ -28221,9 +28409,13 @@ var init_server3 = __esm(async () => {
28221
28409
  sdd_dir: exports_external.string().optional(),
28222
28410
  target_branch: exports_external.string().optional(),
28223
28411
  stash: exports_external.enum(["yes", "no"]).optional(),
28412
+ delegation_token: delegationTokenSchema,
28224
28413
  workspace_root: workspaceRootSchema
28225
28414
  }
28226
- }, async ({ action, sdd_dir, target_branch, stash, workspace_root }) => {
28415
+ }, async ({ action, sdd_dir, target_branch, stash, delegation_token, workspace_root }) => {
28416
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28417
+ if (!identity.ok)
28418
+ return jsonResult({ error: identity.error, code: identity.code });
28227
28419
  const data = branchSetup({
28228
28420
  action,
28229
28421
  sdd_dir,
@@ -28255,13 +28447,23 @@ var init_server3 = __esm(async () => {
28255
28447
  sdd_dir: exports_external.string(),
28256
28448
  task_id: exports_external.number(),
28257
28449
  section_text: exports_external.string(),
28450
+ delegation_token: delegationTokenSchema,
28258
28451
  workspace_root: workspaceRootSchema
28259
28452
  }
28260
- }, async ({ sdd_dir, task_id, section_text, workspace_root }) => {
28453
+ }, async ({ sdd_dir, task_id, section_text, delegation_token, workspace_root }) => {
28454
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28455
+ if (!identity.ok)
28456
+ return jsonResult({ error: identity.error, code: identity.code });
28261
28457
  const slug = slugFromSddPath(sdd_dir);
28262
28458
  if (!slug)
28263
28459
  return jsonResult({ error: "could not derive slug — expected docs/<slug>/sdd/..." });
28264
- const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, cursorMutationContext(workspace_root));
28460
+ if (identity.slug !== undefined && identity.slug !== slug) {
28461
+ return jsonResult({
28462
+ error: `delegation token is bound to flow ${JSON.stringify(identity.slug)}, not ${JSON.stringify(slug)}`,
28463
+ code: "slug_mismatch"
28464
+ });
28465
+ }
28466
+ const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, identity.context);
28265
28467
  if (!gate.ok)
28266
28468
  return jsonResult({ error: gate.error, code: gate.code });
28267
28469
  const data = sddTaskBrief({
@@ -28278,13 +28480,23 @@ var init_server3 = __esm(async () => {
28278
28480
  sdd_dir: exports_external.string(),
28279
28481
  base_sha: exports_external.string(),
28280
28482
  head_sha: exports_external.string(),
28483
+ delegation_token: delegationTokenSchema,
28281
28484
  workspace_root: workspaceRootSchema
28282
28485
  }
28283
- }, async ({ sdd_dir, base_sha, head_sha, workspace_root }) => {
28486
+ }, async ({ sdd_dir, base_sha, head_sha, delegation_token, workspace_root }) => {
28487
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28488
+ if (!identity.ok)
28489
+ return jsonResult({ error: identity.error, code: identity.code });
28284
28490
  const slug = slugFromSddPath(sdd_dir);
28285
28491
  if (!slug)
28286
28492
  return jsonResult({ error: "could not derive slug — expected docs/<slug>/sdd/..." });
28287
- const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, cursorMutationContext(workspace_root));
28493
+ if (identity.slug !== undefined && identity.slug !== slug) {
28494
+ return jsonResult({
28495
+ error: `delegation token is bound to flow ${JSON.stringify(identity.slug)}, not ${JSON.stringify(slug)}`,
28496
+ code: "slug_mismatch"
28497
+ });
28498
+ }
28499
+ const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, identity.context);
28288
28500
  if (!gate.ok)
28289
28501
  return jsonResult({ error: gate.error, code: gate.code });
28290
28502
  const data = sddReviewPackage({
@@ -28302,18 +28514,31 @@ var init_server3 = __esm(async () => {
28302
28514
  inputSchema: {
28303
28515
  progress_path: exports_external.string(),
28304
28516
  line: exports_external.string(),
28517
+ delegation_token: delegationTokenSchema,
28305
28518
  workspace_root: workspaceRootSchema
28306
28519
  }
28307
- }, async ({ progress_path, line, workspace_root }) => {
28520
+ }, async ({ progress_path, line, delegation_token, workspace_root }) => {
28521
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28522
+ if (!identity.ok)
28523
+ return jsonResult({ error: identity.error, code: identity.code });
28308
28524
  const slug = slugFromSddPath(progress_path);
28309
28525
  if (!slug)
28310
28526
  return jsonResult({ error: "could not derive slug — expected docs/<slug>/sdd/..." });
28311
- const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, cursorMutationContext(workspace_root));
28527
+ if (identity.slug !== undefined && identity.slug !== slug) {
28528
+ return jsonResult({
28529
+ error: `delegation token is bound to flow ${JSON.stringify(identity.slug)}, not ${JSON.stringify(slug)}`,
28530
+ code: "slug_mismatch"
28531
+ });
28532
+ }
28533
+ const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, identity.context);
28312
28534
  if (!gate.ok)
28313
28535
  return jsonResult({ error: gate.error, code: gate.code });
28314
28536
  const data = sddAppendProgress({ progress_path, line, workspace_root });
28315
28537
  if (data.error)
28316
28538
  return jsonResult({ error: data.error });
28539
+ if (identity.context.role === "delegated" && identity.context.taskIdentity) {
28540
+ revokeDelegateToken(workspace_root, slug, Number(identity.context.taskIdentity));
28541
+ }
28317
28542
  return jsonResult(withWorkspace(workspace_root, data));
28318
28543
  });
28319
28544
  registerTool("workit_sdd_append_advisory", {
@@ -28328,7 +28553,7 @@ var init_server3 = __esm(async () => {
28328
28553
  const slug = slugFromSddPath(advisories_path);
28329
28554
  if (!slug)
28330
28555
  return jsonResult({ error: "could not derive slug — expected docs/<slug>/sdd/..." });
28331
- const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, cursorMutationContext(workspace_root));
28556
+ const gate = assertSddControlGates(workspace_root, slug, { requireMenu: true, requireDocs: true }, cursorCoordinatorContext(workspace_root));
28332
28557
  if (!gate.ok)
28333
28558
  return jsonResult({ error: gate.error, code: gate.code });
28334
28559
  const data = sddAppendAdvisory({ advisories_path, task_id, text, workspace_root });
@@ -28357,9 +28582,13 @@ var init_server3 = __esm(async () => {
28357
28582
  spec_path: exports_external.string().optional(),
28358
28583
  plan_path: exports_external.string().optional(),
28359
28584
  confirmed: exports_external.boolean().optional(),
28585
+ delegation_token: delegationTokenSchema,
28360
28586
  workspace_root: workspaceRootSchema
28361
28587
  }
28362
- }, async ({ action, slug, spec_path, plan_path, confirmed, workspace_root }) => {
28588
+ }, async ({ action, slug, spec_path, plan_path, confirmed, delegation_token, workspace_root }) => {
28589
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28590
+ if (!identity.ok)
28591
+ return jsonResult({ error: identity.error, code: identity.code });
28363
28592
  if (action === "migrate") {
28364
28593
  const detect = detectLegacyDocs(workspace_root);
28365
28594
  if (confirmed === undefined) {
@@ -28579,7 +28808,7 @@ var init_server3 = __esm(async () => {
28579
28808
  return jsonResult(result);
28580
28809
  }
28581
28810
  if (action === "config") {
28582
- if (locale !== undefined && !/^[a-z]{2,3}(-[A-Z]{2})?$/.test(locale)) {
28811
+ if (locale !== undefined && !/^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/.test(locale)) {
28583
28812
  return jsonResult({
28584
28813
  error: `invalid locale: ${JSON.stringify(locale)} — expected BCP-47 like en or es-CL`
28585
28814
  });
@@ -28690,9 +28919,13 @@ var init_server3 = __esm(async () => {
28690
28919
  minutes: exports_external.number(),
28691
28920
  text: exports_external.string().optional(),
28692
28921
  dateMs: exports_external.number().optional().describe("Epoch ms for work item date; omit for today in config timezone"),
28922
+ delegation_token: delegationTokenSchema,
28693
28923
  workspace_root: workspaceRootSchema
28694
28924
  }
28695
- }, async ({ issueId, minutes, text, dateMs, workspace_root }) => {
28925
+ }, async ({ issueId, minutes, text, dateMs, delegation_token, workspace_root }) => {
28926
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28927
+ if (!identity.ok)
28928
+ return jsonResult({ error: identity.error, code: identity.code });
28696
28929
  const data = await logTime({
28697
28930
  issueId,
28698
28931
  minutes,
@@ -28723,9 +28956,13 @@ var init_server3 = __esm(async () => {
28723
28956
  issueId: exports_external.string(),
28724
28957
  markdown: exports_external.string(),
28725
28958
  minutes: exports_external.number().optional(),
28959
+ delegation_token: delegationTokenSchema,
28726
28960
  workspace_root: workspaceRootSchema
28727
28961
  }
28728
- }, async ({ confirmed, issueId, markdown, minutes, workspace_root }) => {
28962
+ }, async ({ confirmed, issueId, markdown, minutes, delegation_token, workspace_root }) => {
28963
+ const identity = cursorMutationContext(workspace_root, delegation_token);
28964
+ if (!identity.ok)
28965
+ return jsonResult({ error: identity.error, code: identity.code });
28729
28966
  const data = await postUpdate({
28730
28967
  confirmed,
28731
28968
  issueId,
@@ -28790,7 +29027,7 @@ var init_server3 = __esm(async () => {
28790
29027
  const { workspace, slug } = resolved.layout;
28791
29028
  let effective = readEffectiveFlowState(workspace, slug);
28792
29029
  if (!effective.ok && effective.code === "flow_not_activated") {
28793
- const prepared = prepareFlowState(workspace, slug, { spec_path, plan_path }, cursorMutationContext(workspace));
29030
+ const prepared = prepareFlowState(workspace, slug, { spec_path, plan_path }, cursorCoordinatorContext(workspace));
28794
29031
  if (!prepared.ok)
28795
29032
  return jsonResult({ error: prepared.error, code: prepared.code });
28796
29033
  effective = readEffectiveFlowState(workspace, slug);
@@ -28819,7 +29056,7 @@ var init_server3 = __esm(async () => {
28819
29056
  if (!resolved.ok)
28820
29057
  return jsonResult(withWorkspace(workspace_root, { error: resolved.error }));
28821
29058
  const { workspace, slug } = resolved.layout;
28822
- const result = transitionSpec(workspace, slug, spec_path, cursorConfirmation(), cursorMutationContext(workspace));
29059
+ const result = transitionSpec(workspace, slug, spec_path, cursorConfirmation(), cursorCoordinatorContext(workspace));
28823
29060
  if (result.ok === false)
28824
29061
  return jsonResult({ error: result.error, code: result.code });
28825
29062
  return jsonResult({ spec: spec_path, status: readFlowState(workspace, slug).spec.status });
@@ -28835,13 +29072,13 @@ var init_server3 = __esm(async () => {
28835
29072
  if (!resolved.ok)
28836
29073
  return jsonResult(withWorkspace(workspace_root, { error: resolved.error }));
28837
29074
  const { workspace, slug } = resolved.layout;
28838
- const result = transitionPlan(workspace, slug, plan_path, cursorConfirmation(), cursorMutationContext(workspace));
29075
+ const result = transitionPlan(workspace, slug, plan_path, cursorConfirmation(), cursorCoordinatorContext(workspace));
28839
29076
  if (result.ok === false)
28840
29077
  return jsonResult({ error: result.error, code: result.code });
28841
29078
  return jsonResult({ plan: plan_path, status: readFlowState(workspace, slug).plan.status });
28842
29079
  });
28843
29080
  registerTool("workit_plan_menu", {
28844
- description: "Record the answered post-plan choice menu with the Cursor policy-only confirmation. subagent-driven is rejected as unsupported on Cursor (CA-42); there is no evidence argument.",
29081
+ description: "Record the answered post-plan choice menu with the Cursor policy-only confirmation. An accepted Cursor subagent-driven choice activates execution and returns a coordinator_lease (mint delegation tokens with it); there is no evidence argument.",
28845
29082
  inputSchema: {
28846
29083
  plan_path: exports_external.string(),
28847
29084
  choice: exports_external.enum(["subagent-driven", "inline", "handoff", "review-spec", "review-plan"]),
@@ -28852,10 +29089,28 @@ var init_server3 = __esm(async () => {
28852
29089
  if (!resolved.ok)
28853
29090
  return jsonResult(withWorkspace(workspace_root, { error: resolved.error }));
28854
29091
  const { workspace, slug } = resolved.layout;
28855
- const result = recordMenuChoice(workspace, slug, plan_path, choice, cursorConfirmation(), cursorMutationContext(workspace));
29092
+ const result = recordMenuChoice(workspace, slug, plan_path, choice, cursorConfirmation(), cursorCoordinatorContext(workspace));
28856
29093
  if (result.ok === false)
28857
29094
  return jsonResult({ error: result.error, code: result.code });
28858
- return jsonResult({ menu: { presented: true, chosen: choice } });
29095
+ return jsonResult({
29096
+ menu: { presented: true, chosen: choice },
29097
+ ...result.coordinator_lease !== undefined ? { coordinator_lease: result.coordinator_lease } : {}
29098
+ });
29099
+ });
29100
+ registerTool("workit_delegate", {
29101
+ description: "Mint a task-scoped delegation token for a Cursor-native subagent. Requires the coordinator_lease returned once by workit_plan_menu with choice subagent-driven. Pass the returned delegation_token to the subagent; mutation tools accept it as delegation_token.",
29102
+ inputSchema: {
29103
+ slug: exports_external.string(),
29104
+ plan_path: exports_external.string(),
29105
+ task_id: exports_external.number(),
29106
+ coordinator_lease: exports_external.string(),
29107
+ workspace_root: workspaceRootSchema
29108
+ }
29109
+ }, async ({ slug, plan_path, task_id, coordinator_lease, workspace_root }) => {
29110
+ const minted = mintDelegateToken(workspace_root, slug, plan_path, task_id, coordinator_lease);
29111
+ if (!minted.ok)
29112
+ return jsonResult({ error: minted.error, code: minted.code });
29113
+ return jsonResult({ delegation_token: minted.token, slug, task_id });
28859
29114
  });
28860
29115
  lifecycleTool("pause", "Pause a running plan with the Cursor policy-only confirmation: active -> paused. The MCP cannot observe AskQuestion results, so it records attested: false; there is no evidence argument (CA-42). Requires plan_path and workspace_root.");
28861
29116
  lifecycleTool("resume", "Resume a paused plan with the Cursor policy-only confirmation: paused -> active. The MCP cannot observe AskQuestion results, so it records attested: false; there is no evidence argument (CA-42). Requires plan_path and workspace_root.");
@@ -28864,9 +29119,13 @@ var init_server3 = __esm(async () => {
28864
29119
  description: "Link the component docs repo in the toolkit config",
28865
29120
  inputSchema: {
28866
29121
  path: exports_external.string(),
28867
- confirmed: exports_external.boolean()
29122
+ confirmed: exports_external.boolean(),
29123
+ delegation_token: delegationTokenSchema
28868
29124
  }
28869
- }, async ({ path: docsPath, confirmed }) => {
29125
+ }, async ({ path: docsPath, confirmed, delegation_token }) => {
29126
+ const identity = cursorMutationContext(process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), delegation_token);
29127
+ if (!identity.ok)
29128
+ return jsonResult({ error: identity.error, code: identity.code });
28870
29129
  const result = linkDocsRepo(docsPath, confirmed);
28871
29130
  if (!result.ok)
28872
29131
  return jsonResult({ error: result.error });
@@ -28882,9 +29141,13 @@ var init_server3 = __esm(async () => {
28882
29141
  slug: exports_external.string(),
28883
29142
  confirmed: exports_external.boolean(),
28884
29143
  force: exports_external.boolean().optional(),
29144
+ delegation_token: delegationTokenSchema,
28885
29145
  workspace_root: workspaceRootSchema
28886
29146
  }
28887
- }, async ({ slug, confirmed, force, workspace_root }) => {
29147
+ }, async ({ slug, confirmed, force, delegation_token, workspace_root }) => {
29148
+ const identity = cursorMutationContext(workspace_root, delegation_token);
29149
+ if (!identity.ok)
29150
+ return jsonResult({ error: identity.error, code: identity.code });
28888
29151
  const result = promoteSpec(workspace_root, slug, { confirmed, force });
28889
29152
  if (!result.ok)
28890
29153
  return jsonResult({ error: result.error, findings: result.findings ?? [] });
@@ -28903,9 +29166,13 @@ var init_server3 = __esm(async () => {
28903
29166
  inputSchema: {
28904
29167
  name: exports_external.enum(["issue-update", "greeting", "headers"]),
28905
29168
  content: exports_external.string(),
28906
- confirmed: exports_external.boolean()
29169
+ confirmed: exports_external.boolean(),
29170
+ delegation_token: delegationTokenSchema
28907
29171
  }
28908
- }, async ({ name, content, confirmed }) => {
29172
+ }, async ({ name, content, confirmed, delegation_token }) => {
29173
+ const identity = cursorMutationContext(process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), delegation_token);
29174
+ if (!identity.ok)
29175
+ return jsonResult({ error: identity.error, code: identity.code });
28909
29176
  const result = writeTemplate(name, content, confirmed);
28910
29177
  if (!result.ok)
28911
29178
  return jsonResult({ error: result.error });
@@ -28922,9 +29189,13 @@ var init_server3 = __esm(async () => {
28922
29189
  description: exports_external.string(),
28923
29190
  platforms: exports_external.array(exports_external.enum(["cursor", "opencode"])),
28924
29191
  body: exports_external.string(),
28925
- confirmed: exports_external.boolean()
29192
+ confirmed: exports_external.boolean(),
29193
+ delegation_token: delegationTokenSchema
28926
29194
  }
28927
- }, async ({ name, description, platforms, body, confirmed }) => {
29195
+ }, async ({ name, description, platforms, body, confirmed, delegation_token }) => {
29196
+ const identity = cursorMutationContext(process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), delegation_token);
29197
+ if (!identity.ok)
29198
+ return jsonResult({ error: identity.error, code: identity.code });
28928
29199
  const result = writeRule({ name, description, platforms, body }, confirmed);
28929
29200
  if (!result.ok)
28930
29201
  return jsonResult({ error: result.error });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "0.9.2",
3
+ "version": "0.11.0",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin: MCP server, hooks, rules, marketplace manifest (thin over @brainervirus/workit-core)",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "build": "bun scripts/build.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@brainervirus/workit-core": "^0.9.2",
42
+ "@brainervirus/workit-core": "^0.11.0",
43
43
  "@modelcontextprotocol/sdk": "^1.12.0",
44
44
  "zod": "^3.24.0"
45
45
  },
@@ -39,7 +39,7 @@ After writing a plan, **do not emit** Superpowers' inline text beginning “Two
39
39
 
40
40
  After `workit_docs_validate` succeeds on the saved spec/plan pair, call Cursor `AskQuestion` with exactly:
41
41
 
42
- - Subagent-driven → **unsupported on Cursor** (the MCP rejects it as `unsupported_mode`; use OpenCode `wk-implement`)
42
+ - Subagent-driven → dispatches Cursor-native subagents: `workit_plan_menu` returns a one-time `coordinator_lease`, `workit_delegate` mints a task-scoped `delegation_token` per task, and the worker passes it as `delegation_token` on mutation calls
43
43
  - Inline → execute in this session
44
44
  - Handoff → `/wk-handoff` (new session only)
45
45
  - Review spec first
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: wk-implement
3
- description: Execute an approved Superpowers plan on Cursor as the coordinator session (inline only). subagent-driven is unsupported on Cursor and the MCP rejects that menu choice. Use for /wk-implement or "implement from plan".
3
+ description: Execute an approved Superpowers plan on Cursor as the coordinator session in either approved execution mode. Subagent-driven dispatches Cursor-native subagents through a lease/token capability; Inline executes every task in this session. Use for /wk-implement or "implement from plan".
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
7
7
  # Implement
8
8
 
9
- Execute the plan **inline in this coordinator session**. subagent-driven execution is unsupported on Cursor: the MCP rejects the subagent-driven menu choice (`unsupported_mode`) — Cursor has no child sessions. Plan-level edits stay coordinator-gated.
9
+ Execute the plan in the **approved execution mode** recorded by `workit_plan_menu` (call `workit_flow_status` to read it). In Subagent-driven mode this session never edits product code dispatch Cursor-native subagents; in Inline mode it executes every task itself. Plan-level edits stay coordinator-gated.
10
10
 
11
11
  ## Step 1 — Gather facts (required)
12
12
 
@@ -20,11 +20,11 @@ Use the returned `tasks[]` as ground truth. Cache each `section_text` for subage
20
20
 
21
21
  Resolve plugin root: `WORKFLOW_TOOLKIT_ROOT` env or `~/.cursor/plugins/local/workit/`.
22
22
 
23
- Load `templates/execution-contract.md`. Substitute `<SPEC_PATH>`, `<PLAN_PATH>`, `<BRANCH>`, `<SDD_DIR>`, `<TASK_LIST>` from MCP. OMIT the `## Handoff destination` section and its `<workflow-handoff-destination>` marker line — that section is only for sessions started from a `workit_handoff_prompt` destination prompt. This inline executor is NOT a destination and must never present itself as one (five-choice source menu, Handoff still available). If template missing, stop with error.
23
+ Load `templates/execution-contract.md`. Substitute `<SPEC_PATH>`, `<PLAN_PATH>`, `<BRANCH>`, `<SDD_DIR>`, `<TASK_LIST>` from MCP. OMIT the `## Handoff destination` section and its `<workflow-handoff-destination>` marker line — that section is only for sessions started from a `workit_handoff_prompt` destination prompt. This executor is NOT a destination and must never present itself as one (five-choice source menu, Handoff still available). If template missing, stop with error.
24
24
 
25
- ## Step 3 — Follow contract
25
+ ## Step 3 — Route by execution mode
26
26
 
27
- Announce: "Using implement + inline."
27
+ Announce: "Using implement + <mode>."
28
28
 
29
29
  **Before Task 1 — validate + SDD + TodoWrite UI + branch (no worktrees):**
30
30
 
@@ -41,4 +41,18 @@ Each task lands exactly one contiguous non-empty commit range (`base..head`): fi
41
41
 
42
42
  Do not emit a handoff fence — this is in-session execution.
43
43
 
44
+ ### Subagent-driven
45
+
46
+ Requires the flow's execution mode `subagent-driven` (set by `workit_plan_menu`).
47
+
48
+ 1. `workit_plan_menu` returned the raw **`coordinator_lease`** exactly once — use that stored value; the flow state persists only its hash.
49
+ 2. Per task: call MCP `workit_delegate` with `{slug, plan_path, task_id, coordinator_lease, workspace_root}` to mint a task-scoped **`delegation_token`**.
50
+ 3. Dispatch a Cursor-native subagent whose prompt includes the task brief and the raw `delegation_token`; the worker passes it as `delegation_token` on its mutation calls (`workit_sdd_task_brief`, `workit_sdd_review_package`, `workit_sdd_append_progress`, `workit_branch_setup`, `workit_pr_create`, …). The MCP validates the token against the flow state and fails closed on invalid, wrong-task, wrong-workspace, or revoked tokens.
51
+ 4. Coordinator product edits stay blocked — implementation, reviews, and fix rounds happen in the dispatched subagents.
52
+ 5. Appending the task's progress line with the worker's token via `workit_sdd_append_progress` revokes that task's token; mint a fresh token per task.
53
+
54
+ ### Inline
55
+
56
+ Load and follow `executing-plans` in the current session. Every task runs in this agent — single-agent, no dispatch, no token minting.
57
+
44
58
  **Mandatory:** end the run by calling MCP `workit_plan_complete` after the final task once the SDD ledger is complete (all task IDs appended) and `workit_verify` passes — a complete ledger and green verification are the tool's gates. Never finish the run while the plan is still `active`.
@@ -7,11 +7,11 @@ description: Use when you have a written implementation plan to execute in a sep
7
7
 
8
8
  ## Overview
9
9
 
10
- Load plan, review critically, execute all tasks, report when complete.
10
+ Load plan, review critically, execute all tasks in the current session, report when complete. This is the single-agent Inline execution path.
11
11
 
12
12
  **Announce at start:** "I'm using the executing-plans skill to implement this plan."
13
13
 
14
- **Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (Claude Code, Codex CLI, Codex App, and Copilot CLI all qualify; see the per-platform tool refs in `../using-superpowers/references/`). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
14
+ **Note:** This skill is the single-agent Inline execution path: every task runs in the current session — no token minting, no subagent dispatching. Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (Claude Code, Codex CLI, Codex App, and Copilot CLI all qualify; see the per-platform tool refs in `../using-superpowers/references/`). If subagents are available and the plan's approved execution mode is Subagent-driven, use superpowers:subagent-driven-development instead of this skill.
15
15
 
16
16
  ## The Process
17
17
 
@@ -11,6 +11,8 @@ Execute plan by dispatching a fresh implementer subagent per task, a task review
11
11
 
12
12
  **Core principle:** Fresh subagent per task + task review (spec + quality) + broad final review = high quality, fast iteration
13
13
 
14
+ On Cursor, the coordinator mints a task-scoped delegation token via `workit_delegate` (from the `workit_plan_menu` coordinator lease) and the subagent prompt must carry it as `delegation_token` for mutation calls.
15
+
14
16
  **Narration:** between tool calls, narrate at most one short line — the
15
17
  ledger and the tool results carry the record.
16
18