@brainervirus/workit-cursor 8.29.0 → 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.
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +92 -38
- package/dist/mcp-server.js +1 -0
- package/dist/workit-hook.js +84 -32
- package/package.json +3 -3
|
@@ -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\`
|
|
15693
|
-
the PR; \`green\` babysits it
|
|
15694
|
-
never merging; \`merged\`
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
around grant_required. Release: \`workit release
|
|
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
|
-
|
|
15713
|
-
|
|
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
|
|
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();
|
|
@@ -18477,17 +18501,21 @@ function workitCheckTail(words) {
|
|
|
18477
18501
|
return null;
|
|
18478
18502
|
return args.slice(0, split).includes("--shell") ? { script: tail.join(" "), cwd } : { argv: tail, cwd };
|
|
18479
18503
|
}
|
|
18480
|
-
function simpleCommand(command, dialect = "posix", depth = 0) {
|
|
18504
|
+
function simpleCommand(command, dialect = "posix", depth = 0, shaped = false) {
|
|
18481
18505
|
let segments;
|
|
18482
18506
|
try {
|
|
18483
18507
|
segments = segmentsOf(command, dialect);
|
|
18484
18508
|
} catch {
|
|
18485
18509
|
return null;
|
|
18486
18510
|
}
|
|
18487
|
-
|
|
18511
|
+
const filter = shaped && segments.length === 2 ? segments[1] : null;
|
|
18512
|
+
if (filter) {
|
|
18513
|
+
if (!segments[0].pipe || !OUTPUT_FILTERS.has(commandName(filter.words[0])) || filter.group || filter.pipe || filter.unanalyzable || filter.subs?.length || filter.stdin?.length)
|
|
18514
|
+
return null;
|
|
18515
|
+
} else if (segments.length !== 1)
|
|
18488
18516
|
return null;
|
|
18489
18517
|
const [segment] = segments;
|
|
18490
|
-
if (segment.group || segment.pipe || segment.unanalyzable || segment.redirects.length || segment.subs?.length || segment.stdin?.length)
|
|
18518
|
+
if (segment.group || segment.pipe && !filter || segment.unanalyzable || segment.redirects.length && !shaped || segment.subs?.length || segment.stdin?.length)
|
|
18491
18519
|
return null;
|
|
18492
18520
|
const { words } = stripPrefixes(segment.words);
|
|
18493
18521
|
const name = commandName(words[0]);
|
|
@@ -18950,7 +18978,7 @@ var NONE2, SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLA
|
|
|
18950
18978
|
...Object.keys(env).length ? { env } : {},
|
|
18951
18979
|
...stdin === undefined ? {} : { stdin }
|
|
18952
18980
|
};
|
|
18953
|
-
}, RECENT, LAUNCHERS, WORKIT_BIN, WORKIT_PACKAGE, PACKAGE_RUNNERS, WORKIT_GLOBAL, PUSH_VALUE_OPTIONS, CURRENT_BRANCH, pushDestination = (destination) => {
|
|
18981
|
+
}, RECENT, LAUNCHERS, WORKIT_BIN, WORKIT_PACKAGE, PACKAGE_RUNNERS, OUTPUT_FILTERS, WORKIT_GLOBAL, PUSH_VALUE_OPTIONS, CURRENT_BRANCH, pushDestination = (destination) => {
|
|
18954
18982
|
if (destination === "HEAD" || destination === "@" || CURRENT_BRANCH.test(destination))
|
|
18955
18983
|
return { name: null };
|
|
18956
18984
|
if (destination.startsWith("refs/heads/"))
|
|
@@ -19436,7 +19464,6 @@ var NONE2, SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLA
|
|
|
19436
19464
|
case "pr-create":
|
|
19437
19465
|
return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
|
|
19438
19466
|
case "pr-read":
|
|
19439
|
-
return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
|
|
19440
19467
|
case "merge":
|
|
19441
19468
|
return null;
|
|
19442
19469
|
}
|
|
@@ -19644,6 +19671,7 @@ var init_raw_git = __esm(() => {
|
|
|
19644
19671
|
WORKIT_BIN = /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/;
|
|
19645
19672
|
WORKIT_PACKAGE = /^@brainervirus\/workit-cli(?:@\S*)?$/;
|
|
19646
19673
|
PACKAGE_RUNNERS = new Set(["npx", "bunx", "pnpx"]);
|
|
19674
|
+
OUTPUT_FILTERS = new Set(["tail", "head", "grep"]);
|
|
19647
19675
|
WORKIT_GLOBAL = /^--(?:cwd|session|token|as)(=|$)/;
|
|
19648
19676
|
PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
|
|
19649
19677
|
CURRENT_BRANCH = /^\$\(\s*git\s+(?:branch\s+--show-current|rev-parse\s+--abbrev-ref\s+HEAD|symbolic-ref\s+--short\s+HEAD)\s*\)$/;
|
|
@@ -20427,7 +20455,7 @@ function heavyPlan(command, options) {
|
|
|
20427
20455
|
const heavy = heavyLines(lines, options);
|
|
20428
20456
|
if (!heavy.length)
|
|
20429
20457
|
return { kind: "none" };
|
|
20430
|
-
const simple = simpleCommand(command, dialect);
|
|
20458
|
+
const simple = simpleCommand(command, dialect, 0, true);
|
|
20431
20459
|
const single = simple && !WORKIT.test(baseName2(simple[0])) && heavyLines([simple], options)[0];
|
|
20432
20460
|
const judged = single ? [{ words: lines.flat(), text: command }] : heavy.map((match) => ({
|
|
20433
20461
|
words: match.line,
|
|
@@ -20439,7 +20467,7 @@ function heavyPlan(command, options) {
|
|
|
20439
20467
|
if (!verdict.ok)
|
|
20440
20468
|
return {
|
|
20441
20469
|
kind: "passthrough",
|
|
20442
|
-
note:
|
|
20470
|
+
note: ""
|
|
20443
20471
|
};
|
|
20444
20472
|
}
|
|
20445
20473
|
if (single) {
|
|
@@ -20449,7 +20477,7 @@ function heavyPlan(command, options) {
|
|
|
20449
20477
|
const parts = heavy.map((match) => leaseCommand(match.line));
|
|
20450
20478
|
return {
|
|
20451
20479
|
kind: "split",
|
|
20452
|
-
reason: `heavy_command: \`${command.trim()}\` chains heavy work (${heavy.map((match) => match.reason).join("; ")}) with other commands, and a chain cannot run under the machine-wide heavy-check lease. Run
|
|
20480
|
+
reason: `heavy_command: \`${command.trim()}\` chains heavy work (${heavy.map((match) => match.reason).join("; ")}) with other commands, and a chain cannot run under the machine-wide heavy-check lease. Run the heavy part alone, now: \`${parts[0]}\`; then run the other parts as their own commands${parts.length > 1 ? ", each heavy one the same way" : ""}.`,
|
|
20453
20481
|
unblock: parts[0] ?? null
|
|
20454
20482
|
};
|
|
20455
20483
|
}
|
|
@@ -22506,6 +22534,31 @@ var init_worktree_confine = __esm(() => {
|
|
|
22506
22534
|
CONFIG_VALUE = /^(?:--file|-f|--blob|--type|--default|--comment)$/;
|
|
22507
22535
|
});
|
|
22508
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
|
+
|
|
22509
22562
|
// packages/workit-core/src/hooks/handle.ts
|
|
22510
22563
|
function handleHook(input, deps) {
|
|
22511
22564
|
const decision = decide(input, deps);
|
|
@@ -22591,7 +22644,12 @@ function decide(input, deps) {
|
|
|
22591
22644
|
} : NONE6;
|
|
22592
22645
|
if (descriptor.transport !== "hook-process")
|
|
22593
22646
|
return rewritten(null);
|
|
22594
|
-
const
|
|
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));
|
|
22595
22653
|
if (!lease)
|
|
22596
22654
|
return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
|
|
22597
22655
|
return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
|
|
@@ -22639,34 +22697,35 @@ function decide(input, deps) {
|
|
|
22639
22697
|
return NONE6;
|
|
22640
22698
|
}
|
|
22641
22699
|
}
|
|
22642
|
-
var usable2 = (value) => value === "native" || value === "partial", NONE6, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered,
|
|
22643
|
-
const prefix = descriptor.subagents.agentPrefix;
|
|
22644
|
-
const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
|
|
22645
|
-
return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
|
|
22646
|
-
}, 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) => {
|
|
22647
22701
|
const session = input.session.id ?? null;
|
|
22648
|
-
const role =
|
|
22702
|
+
const { role, isolated, git } = agentSteering(descriptor, input.cwd, {
|
|
22703
|
+
type: event.agentType,
|
|
22704
|
+
id: event.agentId
|
|
22705
|
+
});
|
|
22649
22706
|
const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
|
|
22650
|
-
const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
|
|
22651
22707
|
const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
|
|
22652
|
-
if (
|
|
22708
|
+
if (git === "plain")
|
|
22653
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.`;
|
|
22654
22710
|
if (isolated)
|
|
22655
22711
|
return `${isolatedGit(input.cwd)}
|
|
22656
22712
|
${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
22657
|
-
if (
|
|
22713
|
+
if (git === "workit")
|
|
22658
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.`;
|
|
22659
22715
|
const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
|
|
22660
22716
|
if (role !== "judge" || !event.agentId)
|
|
22661
22717
|
return readOnly;
|
|
22662
22718
|
const own = subagentSession(session, event.agentId);
|
|
22663
22719
|
const cwd = input.cwd || process.cwd();
|
|
22720
|
+
const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
|
|
22721
|
+
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22722
|
+
const branch = judgeBranch(cwd);
|
|
22723
|
+
if (descriptor.host === "codex_cli" || descriptor.host === "codex_desktop")
|
|
22724
|
+
return `${readOnly} Its shell already acts as its own Workit session, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${verdictCommand({ branch, judge })}\`. Add no session or token option to it, and never set WORKIT_SESSION_ID by hand.`;
|
|
22664
22725
|
const token = session ? recordIssuedSession(cwd, session, own) : null;
|
|
22665
22726
|
if (session && !token)
|
|
22666
22727
|
return `${readOnly} ${own} was already issued to an earlier subagent, so no token is handed out again and a verdict under it would be refused (unbound_session). Record no verdict as ${own}: spawn a fresh verifier or reviewer, which gets its own session and token.`;
|
|
22667
|
-
const
|
|
22668
|
-
const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
|
|
22669
|
-
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22728
|
+
const line = verdictCommand({ branch, judge, session: own, token });
|
|
22670
22729
|
return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
|
|
22671
22730
|
}, PRE_TOOL, failureDecision = (descriptor, event, error) => {
|
|
22672
22731
|
if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
|
|
@@ -22714,14 +22773,9 @@ var init_handle = __esm(() => {
|
|
|
22714
22773
|
init_live_session();
|
|
22715
22774
|
init_write_gate();
|
|
22716
22775
|
init_worktree_confine();
|
|
22776
|
+
init_steering();
|
|
22717
22777
|
NONE6 = { kind: "none" };
|
|
22718
22778
|
offered = new Set;
|
|
22719
|
-
ROLES = {
|
|
22720
|
-
implementer: "implementer",
|
|
22721
|
-
verifier: "judge",
|
|
22722
|
-
reviewer: "judge"
|
|
22723
|
-
};
|
|
22724
|
-
CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
|
|
22725
22779
|
PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
|
|
22726
22780
|
});
|
|
22727
22781
|
|
package/dist/mcp-server.js
CHANGED
|
@@ -24574,6 +24574,7 @@ var LAUNCHERS = new Set([
|
|
|
24574
24574
|
"command"
|
|
24575
24575
|
]);
|
|
24576
24576
|
var PACKAGE_RUNNERS = new Set(["npx", "bunx", "pnpx"]);
|
|
24577
|
+
var OUTPUT_FILTERS = new Set(["tail", "head", "grep"]);
|
|
24577
24578
|
var PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
|
|
24578
24579
|
var VALUE_OPTIONS = {
|
|
24579
24580
|
git: new Set([
|
package/dist/workit-hook.js
CHANGED
|
@@ -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\`
|
|
15739
|
-
the PR; \`green\` babysits it
|
|
15740
|
-
never merging; \`merged\`
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
around grant_required. Release: \`workit release
|
|
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
|
-
|
|
15759
|
-
|
|
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
|
|
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
|
}
|
|
@@ -18954,17 +18979,22 @@ function workitCheckTail(words) {
|
|
|
18954
18979
|
return null;
|
|
18955
18980
|
return args.slice(0, split).includes("--shell") ? { script: tail.join(" "), cwd } : { argv: tail, cwd };
|
|
18956
18981
|
}
|
|
18957
|
-
|
|
18982
|
+
var OUTPUT_FILTERS = new Set(["tail", "head", "grep"]);
|
|
18983
|
+
function simpleCommand(command, dialect = "posix", depth = 0, shaped = false) {
|
|
18958
18984
|
let segments;
|
|
18959
18985
|
try {
|
|
18960
18986
|
segments = segmentsOf(command, dialect);
|
|
18961
18987
|
} catch {
|
|
18962
18988
|
return null;
|
|
18963
18989
|
}
|
|
18964
|
-
|
|
18990
|
+
const filter = shaped && segments.length === 2 ? segments[1] : null;
|
|
18991
|
+
if (filter) {
|
|
18992
|
+
if (!segments[0].pipe || !OUTPUT_FILTERS.has(commandName(filter.words[0])) || filter.group || filter.pipe || filter.unanalyzable || filter.subs?.length || filter.stdin?.length)
|
|
18993
|
+
return null;
|
|
18994
|
+
} else if (segments.length !== 1)
|
|
18965
18995
|
return null;
|
|
18966
18996
|
const [segment] = segments;
|
|
18967
|
-
if (segment.group || segment.pipe || segment.unanalyzable || segment.redirects.length || segment.subs?.length || segment.stdin?.length)
|
|
18997
|
+
if (segment.group || segment.pipe && !filter || segment.unanalyzable || segment.redirects.length && !shaped || segment.subs?.length || segment.stdin?.length)
|
|
18968
18998
|
return null;
|
|
18969
18999
|
const { words } = stripPrefixes(segment.words);
|
|
18970
19000
|
const name = commandName(words[0]);
|
|
@@ -19649,7 +19679,6 @@ var nudgeFor = (action, host, session) => {
|
|
|
19649
19679
|
case "pr-create":
|
|
19650
19680
|
return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
|
|
19651
19681
|
case "pr-read":
|
|
19652
|
-
return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
|
|
19653
19682
|
case "merge":
|
|
19654
19683
|
return null;
|
|
19655
19684
|
}
|
|
@@ -20739,7 +20768,7 @@ function heavyPlan(command, options) {
|
|
|
20739
20768
|
const heavy = heavyLines(lines, options);
|
|
20740
20769
|
if (!heavy.length)
|
|
20741
20770
|
return { kind: "none" };
|
|
20742
|
-
const simple = simpleCommand(command, dialect);
|
|
20771
|
+
const simple = simpleCommand(command, dialect, 0, true);
|
|
20743
20772
|
const single = simple && !WORKIT.test(baseName2(simple[0])) && heavyLines([simple], options)[0];
|
|
20744
20773
|
const judged = single ? [{ words: lines.flat(), text: command }] : heavy.map((match) => ({
|
|
20745
20774
|
words: match.line,
|
|
@@ -20751,7 +20780,7 @@ function heavyPlan(command, options) {
|
|
|
20751
20780
|
if (!verdict.ok)
|
|
20752
20781
|
return {
|
|
20753
20782
|
kind: "passthrough",
|
|
20754
|
-
note:
|
|
20783
|
+
note: ""
|
|
20755
20784
|
};
|
|
20756
20785
|
}
|
|
20757
20786
|
if (single) {
|
|
@@ -20761,7 +20790,7 @@ function heavyPlan(command, options) {
|
|
|
20761
20790
|
const parts = heavy.map((match) => leaseCommand(match.line));
|
|
20762
20791
|
return {
|
|
20763
20792
|
kind: "split",
|
|
20764
|
-
reason: `heavy_command: \`${command.trim()}\` chains heavy work (${heavy.map((match) => match.reason).join("; ")}) with other commands, and a chain cannot run under the machine-wide heavy-check lease. Run
|
|
20793
|
+
reason: `heavy_command: \`${command.trim()}\` chains heavy work (${heavy.map((match) => match.reason).join("; ")}) with other commands, and a chain cannot run under the machine-wide heavy-check lease. Run the heavy part alone, now: \`${parts[0]}\`; then run the other parts as their own commands${parts.length > 1 ? ", each heavy one the same way" : ""}.`,
|
|
20765
20794
|
unblock: parts[0] ?? null
|
|
20766
20795
|
};
|
|
20767
20796
|
}
|
|
@@ -22734,11 +22763,7 @@ function confineImplementerShell(input, command, dialect = "posix") {
|
|
|
22734
22763
|
return confineImplementer(input, shellMutationTargets(input.cwd, command, dialect, true));
|
|
22735
22764
|
}
|
|
22736
22765
|
|
|
22737
|
-
// packages/workit-core/src/hooks/
|
|
22738
|
-
var usable2 = (value) => value === "native" || value === "partial";
|
|
22739
|
-
var NONE6 = { kind: "none" };
|
|
22740
|
-
var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
|
|
22741
|
-
var offered = new Set;
|
|
22766
|
+
// packages/workit-core/src/hooks/steering.ts
|
|
22742
22767
|
var ROLES = {
|
|
22743
22768
|
implementer: "implementer",
|
|
22744
22769
|
verifier: "judge",
|
|
@@ -22749,34 +22774,56 @@ var workitRole = (descriptor, agentType) => {
|
|
|
22749
22774
|
const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
|
|
22750
22775
|
return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
|
|
22751
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;
|
|
22752
22795
|
var implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer";
|
|
22753
22796
|
var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
|
|
22754
|
-
var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
|
|
22755
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\`).`;
|
|
22756
22798
|
var subagentStartText = (input, descriptor, event) => {
|
|
22757
22799
|
const session = input.session.id ?? null;
|
|
22758
|
-
const role =
|
|
22800
|
+
const { role, isolated, git } = agentSteering(descriptor, input.cwd, {
|
|
22801
|
+
type: event.agentType,
|
|
22802
|
+
id: event.agentId
|
|
22803
|
+
});
|
|
22759
22804
|
const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
|
|
22760
|
-
const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
|
|
22761
22805
|
const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
|
|
22762
|
-
if (
|
|
22806
|
+
if (git === "plain")
|
|
22763
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.`;
|
|
22764
22808
|
if (isolated)
|
|
22765
22809
|
return `${isolatedGit(input.cwd)}
|
|
22766
22810
|
${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
22767
|
-
if (
|
|
22811
|
+
if (git === "workit")
|
|
22768
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.`;
|
|
22769
22813
|
const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
|
|
22770
22814
|
if (role !== "judge" || !event.agentId)
|
|
22771
22815
|
return readOnly;
|
|
22772
22816
|
const own = subagentSession(session, event.agentId);
|
|
22773
22817
|
const cwd = input.cwd || process.cwd();
|
|
22818
|
+
const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
|
|
22819
|
+
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22820
|
+
const branch = judgeBranch(cwd);
|
|
22821
|
+
if (descriptor.host === "codex_cli" || descriptor.host === "codex_desktop")
|
|
22822
|
+
return `${readOnly} Its shell already acts as its own Workit session, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${verdictCommand({ branch, judge })}\`. Add no session or token option to it, and never set WORKIT_SESSION_ID by hand.`;
|
|
22774
22823
|
const token = session ? recordIssuedSession(cwd, session, own) : null;
|
|
22775
22824
|
if (session && !token)
|
|
22776
22825
|
return `${readOnly} ${own} was already issued to an earlier subagent, so no token is handed out again and a verdict under it would be refused (unbound_session). Record no verdict as ${own}: spawn a fresh verifier or reviewer, which gets its own session and token.`;
|
|
22777
|
-
const
|
|
22778
|
-
const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
|
|
22779
|
-
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22826
|
+
const line = verdictCommand({ branch, judge, session: own, token });
|
|
22780
22827
|
return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
|
|
22781
22828
|
};
|
|
22782
22829
|
var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
|
|
@@ -22864,7 +22911,12 @@ function decide(input, deps) {
|
|
|
22864
22911
|
} : NONE6;
|
|
22865
22912
|
if (descriptor.transport !== "hook-process")
|
|
22866
22913
|
return rewritten(null);
|
|
22867
|
-
const
|
|
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));
|
|
22868
22920
|
if (!lease)
|
|
22869
22921
|
return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
|
|
22870
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.
|
|
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.
|
|
50
|
-
"@brainervirus/workit-mcp": "^8.29.
|
|
49
|
+
"@brainervirus/workit-core": "^8.29.2",
|
|
50
|
+
"@brainervirus/workit-mcp": "^8.29.2"
|
|
51
51
|
},
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=24"
|