@brainervirus/workit-core 8.18.0 → 8.19.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-core",
3
- "version": "8.18.0",
3
+ "version": "8.19.1",
4
4
  "private": false,
5
5
  "description": "Workit shared core — task, policy, evidence, review, decision, worker, and writer state for agentic coding workflows",
6
6
  "keywords": [
@@ -24,7 +24,10 @@ description: Build a requested change in small verified steps - follow local pat
24
24
  lease waits and names its holder (`workit lock status`).
25
25
  5. Prove the feature on its real surface with the project's `verify-<app>`
26
26
  skill; none yet? Write one (workit-verify-app). Tests show branch behavior,
27
- not that the feature works.
27
+ not that the feature works. The report carries what you observed: a UI
28
+ change a screenshot or console/network check (chrome devtools or
29
+ agent-browser), an API a quoted real response. App not runnable? Say so
30
+ plainly, never claim success.
28
31
  6. Commit: `workit git commit -m "<type>: <what>" -- <paths>` (or `--all`).
29
32
  No endpoint named? Stop here and state the next command. Hand delivery to
30
33
  ship, which pushes and opens the PR with its body shape (workit-ship), only
@@ -55,8 +58,7 @@ flag was never invoked)
55
58
 
56
59
  Good: "Added `--since`. measured: `workit check test` exit 0;
57
60
  `mytool log --since 2d` printed 3 entries against the fixture repo. inferred:
58
- the GitLab path behaves the same (shared parser, not run). Verification handed
59
- to the verifier agent."
61
+ the GitLab path behaves the same (not run). Handed to the verifier agent."
60
62
 
61
63
  ## Check
62
64
 
@@ -27,7 +27,10 @@ way a user would.
27
27
  - **Drive:** how to exercise it: CLI invocations, `curl` against routes, a
28
28
  browser tool for UI, with fixture data.
29
29
  - **Evidence:** what to capture (exit code, response body, screenshot path)
30
- and the command that records it.
30
+ and the command that records it. A UI is driven with chrome devtools or
31
+ agent-browser, with a screenshot or console/network observation; an API
32
+ with a real call, response quoted. The report carries the observation.
33
+ App not runnable? Say so plainly, never claim success.
31
34
  - **Cleanup:** stop processes, remove temp data.
32
35
  - **Feature map:** feature, how to drive it, expected observation.
33
36
  3. **Prove it end-to-end once:** launch, drive one feature, capture evidence,
@@ -54,7 +57,8 @@ report `clean`, `changed` (what) or `blocked` (why).
54
57
  Bad: "Verify by running the tests." (that is not the real surface)
55
58
 
56
59
  Good: "Launch `bun run dev` (ready: `listening on :5173`, 30 s). Drive:
57
- `curl -s localhost:5173/api/health` returns `{"ok":true}`. Evidence:
60
+ `curl -s localhost:5173/api/health` returned `{"ok":true}`; screenshot of
61
+ /settings at .workit-scratch/settings.png. Evidence:
58
62
  `workit check --name verify-web -- bun scripts/smoke.ts` exit 0."
59
63
 
60
64
  ## Check
@@ -30,6 +30,8 @@ description: Launch, drive and observe <app> on its real surface (<cli|web|api>)
30
30
  ## Evidence
31
31
  `workit check --name verify-<app> -- <driver command>` records exit code and log.
32
32
  Screenshots go to `<tmp dir>/verify-<app>/<feature>.png`; cite the path.
33
+ UI: also report a console or network observation. API: quote the real response.
34
+ If the app cannot be run, say so plainly instead of claiming success.
33
35
 
34
36
  ## Cleanup
35
37
  `<command>` (stop servers, remove `<tmp dir>`).
@@ -8,7 +8,7 @@ import {
8
8
  import type { HostDescriptor, Support } from "./descriptor";
9
9
  import { branchGuidance } from "../core/branch";
10
10
  import { workspaceTrailers } from "../core/workspaces";
11
- import { recordIssuedSession } from "../host-session";
11
+ import { judgeBranch, recordIssuedSession, verdictCommand } from "../host-session";
12
12
  import { heavyDenial, heavyGate, rewriteNote, splitDenial } from "./heavy-gate";
13
13
  import { shellPolicy } from "./policy";
14
14
  import {
@@ -114,9 +114,15 @@ const subagentStartText = (
114
114
  // and only with the token it hands to this subagent alone.
115
115
  // (An isolated judge's text is rebuilt with cwd "": the hook's own cwd then.)
116
116
  // Issued once: a replayed SubagentStart for the same id gets no token.
117
- const token = session ? recordIssuedSession(input.cwd || process.cwd(), session, own) : null;
118
- const flags = token ? `--session ${own} --token ${token}` : `--session ${own}`;
119
- return `${readOnly} Its own Workit session is ${own}: record verdicts with \`workit ledger verdict <result> ${flags} ...\` so the ledger tells it apart from the author.${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." : ""}`;
117
+ const cwd = input.cwd || process.cwd();
118
+ const token = session ? recordIssuedSession(cwd, session, own) : null;
119
+ // Already issued: without its token the id is refused (unbound_session).
120
+ if (session && !token)
121
+ 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.`;
122
+ const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
123
+ const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
124
+ const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
125
+ 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." : ""}`;
120
126
  };
121
127
 
122
128
  export function handleHook(input: HookInput, deps: HookDeps): HookDecision {
@@ -10,7 +10,9 @@
10
10
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
+ import { isProtectedTarget } from "./core/branch";
13
14
  import { resolveStateDir } from "./core/logger";
15
+ import { currentBranch } from "./git/rev";
14
16
  import { resolveStore } from "./store/paths";
15
17
 
16
18
  export type HostSession = { host: string | null; session: string | null };
@@ -217,6 +219,46 @@ export function recordIssuedSession(cwd: string, lead: string, issued: string):
217
219
  }
218
220
  }
219
221
 
222
+ /**
223
+ * The branch a judge spawned from `cwd` most likely verifies: the checkout's
224
+ * branch, or null on a detached HEAD or a protected branch (a lead on `main`
225
+ * fanning out names the candidate in its brief, never its own branch).
226
+ */
227
+ export function judgeBranch(cwd: string): string | null {
228
+ const branch = currentBranch(cwd);
229
+ return branch && !isProtectedTarget(cwd, branch) ? branch : null;
230
+ }
231
+
232
+ /**
233
+ * The exact verdict command a verifier or reviewer runs, filled in (#271
234
+ * S2a). `--token=` keeps a token from ever parsing as a flag. Hosts whose
235
+ * child shell carries its own session (OpenCode, Pi) pass no session.
236
+ * `--kind` is always named: left out, the CLI records `review`.
237
+ */
238
+ export function verdictCommand(options: {
239
+ branch: string | null;
240
+ judge: "verifier" | "reviewer" | null;
241
+ session?: string | null;
242
+ token?: string | null;
243
+ }): string {
244
+ const kind =
245
+ options.judge === "verifier"
246
+ ? "<live|unit>"
247
+ : options.judge === "reviewer"
248
+ ? "review"
249
+ : "<live|unit|review>";
250
+ return [
251
+ "workit ledger verdict <verified|failed|blocked>",
252
+ `--kind ${kind}`,
253
+ `--branch ${options.branch ?? "<branch>"}`,
254
+ options.session ? `--session ${options.session}` : null,
255
+ options.token ? `--token=${options.token}` : null,
256
+ '--how "<what you ran and saw>"',
257
+ ]
258
+ .filter(Boolean)
259
+ .join(" ");
260
+ }
261
+
220
262
  /** Keep the newest ISSUED_PER_LEAD ids of one lead (and their token hashes); `own` is never pruned. */
221
263
  function pruneIssued(dir: string, own: string, tokens: string): void {
222
264
  try {