@brainervirus/workit-pi 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/dist/worker.js CHANGED
@@ -7988,6 +7988,7 @@ var LAUNCHERS = new Set([
7988
7988
  "command"
7989
7989
  ]);
7990
7990
  var PACKAGE_RUNNERS = new Set(["npx", "bunx", "pnpx"]);
7991
+ var OUTPUT_FILTERS = new Set(["tail", "head", "grep"]);
7991
7992
  var PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
7992
7993
  var VALUE_OPTIONS = {
7993
7994
  git: new Set([
package/dist/workit.js CHANGED
@@ -15987,13 +15987,13 @@ Autonomy contract:
15987
15987
  or an unresolved blocker; report open gaps and uncertain workers.
15988
15988
  - No endpoint named: stop at a local commit on a policy-compliant branch and
15989
15989
  state the next command. If the request implies delivery (fix, implement,
15990
- ship), go to the effective endpoint in \`workit grant show\`: \`pr\` opens
15991
- the PR; \`green\` babysits it without asking (workit-ship) to merge-ready,
15992
- never merging; \`merged\` also lands it with \`workit pr merge\`.
15993
- Merge and release need a workspace grant only the user raises from their
15994
- own terminal (a blocked verb names how); never edit workspaces.json or route
15995
- around grant_required. Release: \`workit release start <v>\`, commits,
15996
- \`finish\`; \`publish\` if asked.
15990
+ ship), go to the effective endpoint in \`workit grant show\`: \`pr\` stops
15991
+ at the PR even with merge granted; \`green\` babysits it (workit-ship) to
15992
+ merge-ready, never merging; \`merged\` lands it with \`workit pr merge\`.
15993
+ Only the user raises a grant or the endpoint, in a terminal outside the agent
15994
+ host (\`workit grant set <ws> defaultEndpoint=merged\`); never edit
15995
+ workspaces.json or route around grant_required. Release: \`workit release
15996
+ start <v>\`, commits, \`finish\`; \`publish\` if asked.
15997
15997
  - Ask only for a product or preference choice, or for authority you lack, with
15998
15998
  your recommended answer. Facts are yours: read, run or prototype.
15999
15999
  - Label claims measured (run and seen this session), inferred, or guess.
@@ -16007,9 +16007,8 @@ Autonomy contract:
16007
16007
  is not evidence of a requested remote push. Before reporting delivery,
16008
16008
  reconcile every requested item and observe it (\`workit verify-delivery\`).
16009
16009
 
16010
- CLI first: if a step has one right answer, use the \`workit\` verb instead of
16011
- hand-running git, gh or glab (\`workit git|pr|ci|check|help\`;
16012
- else \`npx -y @brainervirus/workit-cli\`).
16010
+ Read-only git and gh run raw; mutations go through workit verbs
16011
+ (\`workit git|pr|ci|check|help\`; else \`npx -y @brainervirus/workit-cli\`).
16013
16012
  Other checkout: \`workit <verb> --cwd <dir> …\` (verb first: host rules match it); one workit
16014
16013
  verb per shell call, never \`cd <dir> && workit\`. zsh-safe: no \`echo =====\`
16015
16014
  (\`printf '%s\\n' ---\`), quote globs and URLs, no variable named \`status\` or \`path\`.
@@ -17280,17 +17279,22 @@ function workitCheckTail(words) {
17280
17279
  return null;
17281
17280
  return args.slice(0, split).includes("--shell") ? { script: tail.join(" "), cwd } : { argv: tail, cwd };
17282
17281
  }
17283
- function simpleCommand(command, dialect = "posix", depth = 0) {
17282
+ var OUTPUT_FILTERS = new Set(["tail", "head", "grep"]);
17283
+ function simpleCommand(command, dialect = "posix", depth = 0, shaped = false) {
17284
17284
  let segments;
17285
17285
  try {
17286
17286
  segments = segmentsOf(command, dialect);
17287
17287
  } catch {
17288
17288
  return null;
17289
17289
  }
17290
- if (segments.length !== 1)
17290
+ const filter = shaped && segments.length === 2 ? segments[1] : null;
17291
+ if (filter) {
17292
+ if (!segments[0].pipe || !OUTPUT_FILTERS.has(commandName(filter.words[0])) || filter.group || filter.pipe || filter.unanalyzable || filter.subs?.length || filter.stdin?.length)
17293
+ return null;
17294
+ } else if (segments.length !== 1)
17291
17295
  return null;
17292
17296
  const [segment] = segments;
17293
- if (segment.group || segment.pipe || segment.unanalyzable || segment.redirects.length || segment.subs?.length || segment.stdin?.length)
17297
+ if (segment.group || segment.pipe && !filter || segment.unanalyzable || segment.redirects.length && !shaped || segment.subs?.length || segment.stdin?.length)
17294
17298
  return null;
17295
17299
  const { words } = stripPrefixes(segment.words);
17296
17300
  const name = commandName(words[0]);
@@ -17975,7 +17979,6 @@ var nudgeFor = (action, host, session) => {
17975
17979
  case "pr-create":
17976
17980
  return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
17977
17981
  case "pr-read":
17978
- return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
17979
17982
  case "merge":
17980
17983
  return null;
17981
17984
  }
@@ -21634,12 +21637,38 @@ ${offer}` : ""}${options.addendum ? `
21634
21637
  ${options.addendum}` : ""}
21635
21638
  </workit-contract>`;
21636
21639
  };
21640
+ var checkoutAt = (cwd) => {
21641
+ for (let dir = path27.resolve(cwd);; dir = path27.dirname(dir)) {
21642
+ const dotGit = path27.join(dir, ".git");
21643
+ if (fs19.existsSync(dotGit)) {
21644
+ const admin = fs19.statSync(dotGit).isFile() ? path27.resolve(dir, /^gitdir:\s*(.+)$/mu.exec(fs19.readFileSync(dotGit, "utf8"))?.[1]?.trim() ?? "") : dotGit;
21645
+ const head = fs19.readFileSync(path27.join(admin, "HEAD"), "utf8").trim();
21646
+ return { root: dir, branch: /^ref: refs\/heads\/(.+)$/u.exec(head)?.[1] ?? null };
21647
+ }
21648
+ if (path27.dirname(dir) === dir)
21649
+ return null;
21650
+ }
21651
+ };
21652
+ var whereLine = (cwd) => {
21653
+ try {
21654
+ const checkout = checkoutAt(cwd);
21655
+ if (!checkout)
21656
+ return null;
21657
+ const allowed = branchPolicySnapshotFor(cwd).namePolicy.allowed;
21658
+ const kinds = allowed.some((pattern) => pattern.source === "^.*$") ? "any" : allowedKinds(allowed).join(", ") || "see `workit help git`";
21659
+ const place = checkout.root === path27.resolve(cwd) ? "" : ` in ${checkout.root}`;
21660
+ return `cwd ${cwd}${place} on ${checkout.branch ?? "detached HEAD"}; branch kinds: ${kinds}`;
21661
+ } catch {
21662
+ return null;
21663
+ }
21664
+ };
21637
21665
  var turnContextText = (input, descriptor) => {
21638
21666
  try {
21639
21667
  const text = sessionCompactContext(new TaskStore(input.cwd), { host: input.host, handle: input.session.id }, hookOperationContext(input, descriptor), descriptor.context.task);
21640
21668
  if (text === MIGRATION_PENDING_NOTE)
21641
21669
  return text;
21642
- return text ? `<workit-task-context>${text}</workit-task-context>` : null;
21670
+ return text ? `<workit-task-context>${[whereLine(input.cwd), text].filter(Boolean).join(`
21671
+ `)}</workit-task-context>` : null;
21643
21672
  } catch {
21644
21673
  return null;
21645
21674
  }
@@ -22424,7 +22453,7 @@ function heavyPlan(command, options) {
22424
22453
  const heavy = heavyLines(lines, options);
22425
22454
  if (!heavy.length)
22426
22455
  return { kind: "none" };
22427
- const simple = simpleCommand(command, dialect);
22456
+ const simple = simpleCommand(command, dialect, 0, true);
22428
22457
  const single = simple && !WORKIT.test(baseName2(simple[0])) && heavyLines([simple], options)[0];
22429
22458
  const judged = single ? [{ words: lines.flat(), text: command }] : heavy.map((match) => ({
22430
22459
  words: match.line,
@@ -22436,7 +22465,7 @@ function heavyPlan(command, options) {
22436
22465
  if (!verdict.ok)
22437
22466
  return {
22438
22467
  kind: "passthrough",
22439
- note: `workit: \`${command.trim()}\` is heavy but runs outside the heavy-check lease because a host permission rule names it (or \`workit\` is allowlisted); the host decides.`
22468
+ note: ""
22440
22469
  };
22441
22470
  }
22442
22471
  if (single) {
@@ -22446,7 +22475,7 @@ function heavyPlan(command, options) {
22446
22475
  const parts = heavy.map((match) => leaseCommand(match.line));
22447
22476
  return {
22448
22477
  kind: "split",
22449
- 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 each heavy part alone as \`workit check --heavy -- <segment>\` (here: ${parts.map((part) => `\`${part}\``).join("; ")}); run the other parts as their own commands.`,
22478
+ 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" : ""}.`,
22450
22479
  unblock: parts[0] ?? null
22451
22480
  };
22452
22481
  }
@@ -24387,11 +24416,7 @@ function confineImplementerShell(input, command, dialect = "posix") {
24387
24416
  return confineImplementer(input, shellMutationTargets(input.cwd, command, dialect, true));
24388
24417
  }
24389
24418
 
24390
- // packages/workit-core/src/hooks/handle.ts
24391
- var usable2 = (value) => value === "native" || value === "partial";
24392
- var NONE6 = { kind: "none" };
24393
- var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
24394
- var offered = new Set;
24419
+ // packages/workit-core/src/hooks/steering.ts
24395
24420
  var ROLES = {
24396
24421
  implementer: "implementer",
24397
24422
  verifier: "judge",
@@ -24402,34 +24427,56 @@ var workitRole = (descriptor, agentType) => {
24402
24427
  const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
24403
24428
  return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
24404
24429
  };
24430
+ var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
24431
+ var roleSteering = (role, isolated) => ({
24432
+ role,
24433
+ isolated,
24434
+ git: role === "implementer" ? isolated ? "plain" : "workit" : null,
24435
+ nudges: role === null
24436
+ });
24437
+ var agentSteering = (descriptor, cwd, agent) => {
24438
+ const role = agent.type ? workitRole(descriptor, agent.type) : null;
24439
+ const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(cwd, agent.id) : CLAUDE_WORKTREE.test(cwd));
24440
+ return roleSteering(role, isolated);
24441
+ };
24442
+
24443
+ // packages/workit-core/src/hooks/handle.ts
24444
+ var usable2 = (value) => value === "native" || value === "partial";
24445
+ var NONE6 = { kind: "none" };
24446
+ var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
24447
+ var offered = new Set;
24405
24448
  var implementerAgent = (input, descriptor) => Boolean(input.session.agentId) && input.session.agentType !== null && workitRole(descriptor, input.session.agentType) === "implementer";
24406
24449
  var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
24407
- var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
24408
24450
  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\`).`;
24409
24451
  var subagentStartText = (input, descriptor, event) => {
24410
24452
  const session = input.session.id ?? null;
24411
- const role = workitRole(descriptor, event.agentType);
24453
+ const { role, isolated, git } = agentSteering(descriptor, input.cwd, {
24454
+ type: event.agentType,
24455
+ id: event.agentId
24456
+ });
24412
24457
  const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
24413
- const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" ? hostIsolated(input.cwd, event.agentId) : CLAUDE_WORKTREE.test(input.cwd));
24414
24458
  const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
24415
- if (role === "implementer" && isolated)
24459
+ if (git === "plain")
24416
24460
  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.`;
24417
24461
  if (isolated)
24418
24462
  return `${isolatedGit(input.cwd)}
24419
24463
  ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
24420
- if (role === "implementer")
24464
+ if (git === "workit")
24421
24465
  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.`;
24422
24466
  const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
24423
24467
  if (role !== "judge" || !event.agentId)
24424
24468
  return readOnly;
24425
24469
  const own = subagentSession(session, event.agentId);
24426
24470
  const cwd = input.cwd || process.cwd();
24471
+ const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
24472
+ const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
24473
+ const branch = judgeBranch(cwd);
24474
+ if (descriptor.host === "codex_cli" || descriptor.host === "codex_desktop")
24475
+ 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.`;
24427
24476
  const token = session ? recordIssuedSession(cwd, session, own) : null;
24428
24477
  if (session && !token)
24429
24478
  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.`;
24430
- const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
24431
- const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
24432
- const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
24479
+ const line = verdictCommand({ branch, judge, session: own, token });
24433
24480
  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." : ""}`;
24434
24481
  };
24435
24482
  var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
@@ -24517,7 +24564,12 @@ function decide(input, deps) {
24517
24564
  } : NONE6;
24518
24565
  if (descriptor.transport !== "hook-process")
24519
24566
  return rewritten(null);
24520
- const nudged = withContextLine(withContextLine(canDeny ? rawGitPre(input, event.command) : NONE6, aside), shipNudge(input, event.command));
24567
+ const { nudges } = agentSteering(descriptor, input.cwd, {
24568
+ type: input.session.agentType,
24569
+ id: input.session.agentId
24570
+ });
24571
+ const nudge = canDeny ? rawGitPre(input, event.command, { nudge: nudges }) : NONE6;
24572
+ const nudged = withContextLine(withContextLine(nudge, aside), shipNudge(input, event.command));
24521
24573
  if (!lease)
24522
24574
  return cwdCommand && nudged.kind !== "deny" ? rewritten(nudged.kind === "context" ? nudged.text : null) : nudged;
24523
24575
  return rewritten([rewriteNote(lease), nudged.kind === "context" ? nudged.text : null].filter(Boolean).join(`
@@ -24860,7 +24912,9 @@ var observeToolResult = (event, ctx) => {
24860
24912
  toolUseId: event.toolCallId
24861
24913
  });
24862
24914
  handleHook(post, { descriptor: PI_DESCRIPTOR, addendum: null });
24863
- const nudge = process.env.WORKIT_PI_WORKER_SESSION ? rawGitPre(post, command) : shellNudge(post, command);
24915
+ const named = process.env.WORKIT_PI_WORKER_ROLE;
24916
+ const role = named === "implementer" ? "implementer" : named ? "judge" : null;
24917
+ const nudge = process.env.WORKIT_PI_WORKER_SESSION ? rawGitPre(post, command, { nudge: roleSteering(role, false).nudges }) : shellNudge(post, command);
24864
24918
  return nudge.kind === "context" ? { content: [...event.content, { type: "text", text: nudge.text }] } : undefined;
24865
24919
  } catch {
24866
24920
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-pi",
3
- "version": "8.29.0",
3
+ "version": "8.29.2",
4
4
  "description": "Workit native extension for Pi — tools, method skills, and session continuity",
5
5
  "keywords": [
6
6
  "agentic-coding",