@brainervirus/workit-cursor 8.29.1 → 8.29.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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": "8.29.1",
5
+ "version": "8.29.2",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -15689,13 +15689,13 @@ Autonomy contract:
15689
15689
  or an unresolved blocker; report open gaps and uncertain workers.
15690
15690
  - No endpoint named: stop at a local commit on a policy-compliant branch and
15691
15691
  state the next command. If the request implies delivery (fix, implement,
15692
- ship), go to the effective endpoint in \`workit grant show\`: \`pr\` opens
15693
- the PR; \`green\` babysits it without asking (workit-ship) to merge-ready,
15694
- never merging; \`merged\` also lands it with \`workit pr merge\`.
15695
- Merge and release need a workspace grant only the user raises from their
15696
- own terminal (a blocked verb names how); never edit workspaces.json or route
15697
- around grant_required. Release: \`workit release start <v>\`, commits,
15698
- \`finish\`; \`publish\` if asked.
15692
+ ship), go to the effective endpoint in \`workit grant show\`: \`pr\` stops
15693
+ at the PR even with merge granted; \`green\` babysits it (workit-ship) to
15694
+ merge-ready, never merging; \`merged\` lands it with \`workit pr merge\`.
15695
+ Only the user raises a grant or the endpoint, in a terminal outside the agent
15696
+ host (\`workit grant set <ws> defaultEndpoint=merged\`); never edit
15697
+ workspaces.json or route around grant_required. Release: \`workit release
15698
+ start <v>\`, commits, \`finish\`; \`publish\` if asked.
15699
15699
  - Ask only for a product or preference choice, or for authority you lack, with
15700
15700
  your recommended answer. Facts are yours: read, run or prototype.
15701
15701
  - Label claims measured (run and seen this session), inferred, or guess.
@@ -15709,9 +15709,8 @@ Autonomy contract:
15709
15709
  is not evidence of a requested remote push. Before reporting delivery,
15710
15710
  reconcile every requested item and observe it (\`workit verify-delivery\`).
15711
15711
 
15712
- CLI first: if a step has one right answer, use the \`workit\` verb instead of
15713
- hand-running git, gh or glab (\`workit git|pr|ci|check|help\`;
15714
- else \`npx -y @brainervirus/workit-cli\`).
15712
+ Read-only git and gh run raw; mutations go through workit verbs
15713
+ (\`workit git|pr|ci|check|help\`; else \`npx -y @brainervirus/workit-cli\`).
15715
15714
  Other checkout: \`workit <verb> --cwd <dir> …\` (verb first: host rules match it); one workit
15716
15715
  verb per shell call, never \`cd <dir> && workit\`. zsh-safe: no \`echo =====\`
15717
15716
  (\`printf '%s\\n' ---\`), quote globs and URLs, no variable named \`status\` or \`path\`.
@@ -17699,12 +17698,36 @@ ${invariantBootstrap()}${compact}${offer ? `
17699
17698
  ${offer}` : ""}${options.addendum ? `
17700
17699
  ${options.addendum}` : ""}
17701
17700
  </workit-contract>`;
17701
+ }, checkoutAt = (cwd) => {
17702
+ for (let dir = path20.resolve(cwd);; dir = path20.dirname(dir)) {
17703
+ const dotGit = path20.join(dir, ".git");
17704
+ if (fs15.existsSync(dotGit)) {
17705
+ const admin = fs15.statSync(dotGit).isFile() ? path20.resolve(dir, /^gitdir:\s*(.+)$/mu.exec(fs15.readFileSync(dotGit, "utf8"))?.[1]?.trim() ?? "") : dotGit;
17706
+ const head = fs15.readFileSync(path20.join(admin, "HEAD"), "utf8").trim();
17707
+ return { root: dir, branch: /^ref: refs\/heads\/(.+)$/u.exec(head)?.[1] ?? null };
17708
+ }
17709
+ if (path20.dirname(dir) === dir)
17710
+ return null;
17711
+ }
17712
+ }, whereLine = (cwd) => {
17713
+ try {
17714
+ const checkout = checkoutAt(cwd);
17715
+ if (!checkout)
17716
+ return null;
17717
+ const allowed = branchPolicySnapshotFor(cwd).namePolicy.allowed;
17718
+ const kinds = allowed.some((pattern) => pattern.source === "^.*$") ? "any" : allowedKinds(allowed).join(", ") || "see `workit help git`";
17719
+ const place = checkout.root === path20.resolve(cwd) ? "" : ` in ${checkout.root}`;
17720
+ return `cwd ${cwd}${place} on ${checkout.branch ?? "detached HEAD"}; branch kinds: ${kinds}`;
17721
+ } catch {
17722
+ return null;
17723
+ }
17702
17724
  }, turnContextText = (input, descriptor) => {
17703
17725
  try {
17704
17726
  const text = sessionCompactContext(new TaskStore(input.cwd), { host: input.host, handle: input.session.id }, hookOperationContext(input, descriptor), descriptor.context.task);
17705
17727
  if (text === MIGRATION_PENDING_NOTE)
17706
17728
  return text;
17707
- return text ? `<workit-task-context>${text}</workit-task-context>` : null;
17729
+ return text ? `<workit-task-context>${[whereLine(input.cwd), text].filter(Boolean).join(`
17730
+ `)}</workit-task-context>` : null;
17708
17731
  } catch {
17709
17732
  return null;
17710
17733
  }
@@ -17770,6 +17793,7 @@ ${options.addendum}` : ""}
17770
17793
  clearTurnDigest(file);
17771
17794
  };
17772
17795
  var init_context = __esm(() => {
17796
+ init_branch();
17773
17797
  init_methods();
17774
17798
  init_paths();
17775
17799
  init_task_contract();
@@ -19440,7 +19464,6 @@ var NONE2, SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLA
19440
19464
  case "pr-create":
19441
19465
  return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
19442
19466
  case "pr-read":
19443
- return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
19444
19467
  case "merge":
19445
19468
  return null;
19446
19469
  }
@@ -22511,6 +22534,31 @@ var init_worktree_confine = __esm(() => {
22511
22534
  CONFIG_VALUE = /^(?:--file|-f|--blob|--type|--default|--comment)$/;
22512
22535
  });
22513
22536
 
22537
+ // packages/workit-core/src/hooks/steering.ts
22538
+ var ROLES, workitRole = (descriptor, agentType) => {
22539
+ const prefix = descriptor.subagents.agentPrefix;
22540
+ const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
22541
+ return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
22542
+ }, CLAUDE_WORKTREE, roleSteering = (role, isolated) => ({
22543
+ role,
22544
+ isolated,
22545
+ git: role === "implementer" ? isolated ? "plain" : "workit" : null,
22546
+ nudges: role === null
22547
+ }), agentSteering = (descriptor, cwd, agent) => {
22548
+ const role = agent.type ? workitRole(descriptor, agent.type) : null;
22549
+ const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(cwd, agent.id) : CLAUDE_WORKTREE.test(cwd));
22550
+ return roleSteering(role, isolated);
22551
+ };
22552
+ var init_steering = __esm(() => {
22553
+ init_worktree_confine();
22554
+ ROLES = {
22555
+ implementer: "implementer",
22556
+ verifier: "judge",
22557
+ reviewer: "judge"
22558
+ };
22559
+ CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
22560
+ });
22561
+
22514
22562
  // packages/workit-core/src/hooks/handle.ts
22515
22563
  function handleHook(input, deps) {
22516
22564
  const decision = decide(input, deps);
@@ -22596,7 +22644,12 @@ function decide(input, deps) {
22596
22644
  } : NONE6;
22597
22645
  if (descriptor.transport !== "hook-process")
22598
22646
  return rewritten(null);
22599
- const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE6, aside), shipNudge(input, event.command));
22647
+ const { nudges } = agentSteering(descriptor, input.cwd, {
22648
+ type: input.session.agentType,
22649
+ id: input.session.agentId
22650
+ });
22651
+ const nudge = canDeny ? rawGitPre(input, event.command, { nudge: nudges }) : NONE6;
22652
+ const nudged = withContextLine(withContextLine(nudge, aside), shipNudge(input, event.command));
22600
22653
  if (!lease)
22601
22654
  return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
22602
22655
  return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
@@ -22644,22 +22697,20 @@ function decide(input, deps) {
22644
22697
  return NONE6;
22645
22698
  }
22646
22699
  }
22647
- var usable2 = (value) => value === "native" || value === "partial", NONE6, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, ROLES, workitRole = (descriptor, agentType) => {
22648
- const prefix = descriptor.subagents.agentPrefix;
22649
- const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
22650
- return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
22651
- }, implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer", subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), CLAUDE_WORKTREE, isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`, subagentStartText = (input, descriptor, event) => {
22700
+ var usable2 = (value) => value === "native" || value === "partial", NONE6, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer", subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`, subagentStartText = (input, descriptor, event) => {
22652
22701
  const session = input.session.id ?? null;
22653
- const role = workitRole(descriptor, event.agentType);
22702
+ const { role, isolated, git } = agentSteering(descriptor, input.cwd, {
22703
+ type: event.agentType,
22704
+ id: event.agentId
22705
+ });
22654
22706
  const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
22655
- const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
22656
22707
  const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
22657
- if (role === "implementer" && isolated)
22708
+ if (git === "plain")
22658
22709
  return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${isolatedGit(input.cwd)} Plain git is expected here, and the branch name is still policy-checked: a raw \`git switch -c\`, \`git checkout -b\`, \`git branch\` or \`git worktree add -b\` onto a protected or non-compliant name is denied, so use a policy-compliant branch.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
22659
22710
  if (isolated)
22660
22711
  return `${isolatedGit(input.cwd)}
22661
22712
  ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
22662
- if (role === "implementer")
22713
+ if (git === "workit")
22663
22714
  return `Workit observed ${who} as an implementer: it edits and commits only in its own git worktree, the one its brief names (the lead makes it with \`workit fanout worktree create <slice>\` before spawning), never in the lead's checkout, within its brief's scope. Workit binds it to the first Workit worktree it changes: from then on an edit or a mutating git command outside that worktree is denied, and before then so is one outside every Workit worktree. Run Workit against the worktree one verb per call, never \`cd … &&\` chains or \`$VAR\` paths: \`workit git --cwd <worktree> commit -m "<message>" -- <paths>\`, \`workit check --cwd <worktree> <name>\` (verb first, so host allow rules match). The worktree is on the brief's branch once the lead made it; otherwise switch with \`workit git --cwd <worktree> branch <branch> --base <base>\` (or \`--kind <kind> --slug <slug>\`, which picks the base); branch policy hooks still deny protected or non-compliant branches, raw git included.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
22664
22715
  const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
22665
22716
  if (role !== "judge" || !event.agentId)
@@ -22722,14 +22773,9 @@ var init_handle = __esm(() => {
22722
22773
  init_live_session();
22723
22774
  init_write_gate();
22724
22775
  init_worktree_confine();
22776
+ init_steering();
22725
22777
  NONE6 = { kind: "none" };
22726
22778
  offered = new Set;
22727
- ROLES = {
22728
- implementer: "implementer",
22729
- verifier: "judge",
22730
- reviewer: "judge"
22731
- };
22732
- CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
22733
22779
  PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
22734
22780
  });
22735
22781
 
@@ -15735,13 +15735,13 @@ Autonomy contract:
15735
15735
  or an unresolved blocker; report open gaps and uncertain workers.
15736
15736
  - No endpoint named: stop at a local commit on a policy-compliant branch and
15737
15737
  state the next command. If the request implies delivery (fix, implement,
15738
- ship), go to the effective endpoint in \`workit grant show\`: \`pr\` opens
15739
- the PR; \`green\` babysits it without asking (workit-ship) to merge-ready,
15740
- never merging; \`merged\` also lands it with \`workit pr merge\`.
15741
- Merge and release need a workspace grant only the user raises from their
15742
- own terminal (a blocked verb names how); never edit workspaces.json or route
15743
- around grant_required. Release: \`workit release start <v>\`, commits,
15744
- \`finish\`; \`publish\` if asked.
15738
+ ship), go to the effective endpoint in \`workit grant show\`: \`pr\` stops
15739
+ at the PR even with merge granted; \`green\` babysits it (workit-ship) to
15740
+ merge-ready, never merging; \`merged\` lands it with \`workit pr merge\`.
15741
+ Only the user raises a grant or the endpoint, in a terminal outside the agent
15742
+ host (\`workit grant set <ws> defaultEndpoint=merged\`); never edit
15743
+ workspaces.json or route around grant_required. Release: \`workit release
15744
+ start <v>\`, commits, \`finish\`; \`publish\` if asked.
15745
15745
  - Ask only for a product or preference choice, or for authority you lack, with
15746
15746
  your recommended answer. Facts are yours: read, run or prototype.
15747
15747
  - Label claims measured (run and seen this session), inferred, or guess.
@@ -15755,9 +15755,8 @@ Autonomy contract:
15755
15755
  is not evidence of a requested remote push. Before reporting delivery,
15756
15756
  reconcile every requested item and observe it (\`workit verify-delivery\`).
15757
15757
 
15758
- CLI first: if a step has one right answer, use the \`workit\` verb instead of
15759
- hand-running git, gh or glab (\`workit git|pr|ci|check|help\`;
15760
- else \`npx -y @brainervirus/workit-cli\`).
15758
+ Read-only git and gh run raw; mutations go through workit verbs
15759
+ (\`workit git|pr|ci|check|help\`; else \`npx -y @brainervirus/workit-cli\`).
15761
15760
  Other checkout: \`workit <verb> --cwd <dir> …\` (verb first: host rules match it); one workit
15762
15761
  verb per shell call, never \`cd <dir> && workit\`. zsh-safe: no \`echo =====\`
15763
15762
  (\`printf '%s\\n' ---\`), quote globs and URLs, no variable named \`status\` or \`path\`.
@@ -17759,12 +17758,38 @@ ${offer}` : ""}${options.addendum ? `
17759
17758
  ${options.addendum}` : ""}
17760
17759
  </workit-contract>`;
17761
17760
  };
17761
+ var checkoutAt = (cwd) => {
17762
+ for (let dir = path20.resolve(cwd);; dir = path20.dirname(dir)) {
17763
+ const dotGit = path20.join(dir, ".git");
17764
+ if (fs15.existsSync(dotGit)) {
17765
+ const admin = fs15.statSync(dotGit).isFile() ? path20.resolve(dir, /^gitdir:\s*(.+)$/mu.exec(fs15.readFileSync(dotGit, "utf8"))?.[1]?.trim() ?? "") : dotGit;
17766
+ const head = fs15.readFileSync(path20.join(admin, "HEAD"), "utf8").trim();
17767
+ return { root: dir, branch: /^ref: refs\/heads\/(.+)$/u.exec(head)?.[1] ?? null };
17768
+ }
17769
+ if (path20.dirname(dir) === dir)
17770
+ return null;
17771
+ }
17772
+ };
17773
+ var whereLine = (cwd) => {
17774
+ try {
17775
+ const checkout = checkoutAt(cwd);
17776
+ if (!checkout)
17777
+ return null;
17778
+ const allowed = branchPolicySnapshotFor(cwd).namePolicy.allowed;
17779
+ const kinds = allowed.some((pattern) => pattern.source === "^.*$") ? "any" : allowedKinds(allowed).join(", ") || "see `workit help git`";
17780
+ const place = checkout.root === path20.resolve(cwd) ? "" : ` in ${checkout.root}`;
17781
+ return `cwd ${cwd}${place} on ${checkout.branch ?? "detached HEAD"}; branch kinds: ${kinds}`;
17782
+ } catch {
17783
+ return null;
17784
+ }
17785
+ };
17762
17786
  var turnContextText = (input, descriptor) => {
17763
17787
  try {
17764
17788
  const text = sessionCompactContext(new TaskStore(input.cwd), { host: input.host, handle: input.session.id }, hookOperationContext(input, descriptor), descriptor.context.task);
17765
17789
  if (text === MIGRATION_PENDING_NOTE)
17766
17790
  return text;
17767
- return text ? `<workit-task-context>${text}</workit-task-context>` : null;
17791
+ return text ? `<workit-task-context>${[whereLine(input.cwd), text].filter(Boolean).join(`
17792
+ `)}</workit-task-context>` : null;
17768
17793
  } catch {
17769
17794
  return null;
17770
17795
  }
@@ -19654,7 +19679,6 @@ var nudgeFor = (action, host, session) => {
19654
19679
  case "pr-create":
19655
19680
  return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
19656
19681
  case "pr-read":
19657
- return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
19658
19682
  case "merge":
19659
19683
  return null;
19660
19684
  }
@@ -22739,11 +22763,7 @@ function confineImplementerShell(input, command, dialect = "posix") {
22739
22763
  return confineImplementer(input, shellMutationTargets(input.cwd, command, dialect, true));
22740
22764
  }
22741
22765
 
22742
- // packages/workit-core/src/hooks/handle.ts
22743
- var usable2 = (value) => value === "native" || value === "partial";
22744
- var NONE6 = { kind: "none" };
22745
- var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
22746
- var offered = new Set;
22766
+ // packages/workit-core/src/hooks/steering.ts
22747
22767
  var ROLES = {
22748
22768
  implementer: "implementer",
22749
22769
  verifier: "judge",
@@ -22754,22 +22774,41 @@ var workitRole = (descriptor, agentType) => {
22754
22774
  const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
22755
22775
  return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
22756
22776
  };
22777
+ var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
22778
+ var roleSteering = (role, isolated) => ({
22779
+ role,
22780
+ isolated,
22781
+ git: role === "implementer" ? isolated ? "plain" : "workit" : null,
22782
+ nudges: role === null
22783
+ });
22784
+ var agentSteering = (descriptor, cwd, agent) => {
22785
+ const role = agent.type ? workitRole(descriptor, agent.type) : null;
22786
+ const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(cwd, agent.id) : CLAUDE_WORKTREE.test(cwd));
22787
+ return roleSteering(role, isolated);
22788
+ };
22789
+
22790
+ // packages/workit-core/src/hooks/handle.ts
22791
+ var usable2 = (value) => value === "native" || value === "partial";
22792
+ var NONE6 = { kind: "none" };
22793
+ var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
22794
+ var offered = new Set;
22757
22795
  var implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer";
22758
22796
  var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
22759
- var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
22760
22797
  var isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`;
22761
22798
  var subagentStartText = (input, descriptor, event) => {
22762
22799
  const session = input.session.id ?? null;
22763
- const role = workitRole(descriptor, event.agentType);
22800
+ const { role, isolated, git } = agentSteering(descriptor, input.cwd, {
22801
+ type: event.agentType,
22802
+ id: event.agentId
22803
+ });
22764
22804
  const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
22765
- const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
22766
22805
  const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
22767
- if (role === "implementer" && isolated)
22806
+ if (git === "plain")
22768
22807
  return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${isolatedGit(input.cwd)} Plain git is expected here, and the branch name is still policy-checked: a raw \`git switch -c\`, \`git checkout -b\`, \`git branch\` or \`git worktree add -b\` onto a protected or non-compliant name is denied, so use a policy-compliant branch.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
22769
22808
  if (isolated)
22770
22809
  return `${isolatedGit(input.cwd)}
22771
22810
  ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
22772
- if (role === "implementer")
22811
+ if (git === "workit")
22773
22812
  return `Workit observed ${who} as an implementer: it edits and commits only in its own git worktree, the one its brief names (the lead makes it with \`workit fanout worktree create <slice>\` before spawning), never in the lead's checkout, within its brief's scope. Workit binds it to the first Workit worktree it changes: from then on an edit or a mutating git command outside that worktree is denied, and before then so is one outside every Workit worktree. Run Workit against the worktree one verb per call, never \`cd … &&\` chains or \`$VAR\` paths: \`workit git --cwd <worktree> commit -m "<message>" -- <paths>\`, \`workit check --cwd <worktree> <name>\` (verb first, so host allow rules match). The worktree is on the brief's branch once the lead made it; otherwise switch with \`workit git --cwd <worktree> branch <branch> --base <base>\` (or \`--kind <kind> --slug <slug>\`, which picks the base); branch policy hooks still deny protected or non-compliant branches, raw git included.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
22774
22813
  const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
22775
22814
  if (role !== "judge" || !event.agentId)
@@ -22872,7 +22911,12 @@ function decide(input, deps) {
22872
22911
  } : NONE6;
22873
22912
  if (descriptor.transport !== "hook-process")
22874
22913
  return rewritten(null);
22875
- const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE6, aside), shipNudge(input, event.command));
22914
+ const { nudges } = agentSteering(descriptor, input.cwd, {
22915
+ type: input.session.agentType,
22916
+ id: input.session.agentId
22917
+ });
22918
+ const nudge = canDeny ? rawGitPre(input, event.command, { nudge: nudges }) : NONE6;
22919
+ const nudged = withContextLine(withContextLine(nudge, aside), shipNudge(input, event.command));
22876
22920
  if (!lease)
22877
22921
  return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
22878
22922
  return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.29.1",
3
+ "version": "8.29.2",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and sixteen method skills",
6
6
  "keywords": [
@@ -46,8 +46,8 @@
46
46
  "build": "bun scripts/build.ts"
47
47
  },
48
48
  "devDependencies": {
49
- "@brainervirus/workit-core": "^8.29.1",
50
- "@brainervirus/workit-mcp": "^8.29.1"
49
+ "@brainervirus/workit-core": "^8.29.2",
50
+ "@brainervirus/workit-mcp": "^8.29.2"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"