@brainervirus/workit-codex 8.20.0 → 8.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workit",
3
- "version": "8.20.0",
3
+ "version": "8.21.0",
4
4
  "description": "Adaptive engineering workflow rails for Codex",
5
5
  "author": {
6
6
  "name": "BrainerVirus"
@@ -28826,8 +28826,11 @@ var WRITE_TOOLS = new Set([
28826
28826
  "editfile",
28827
28827
  "writefile"
28828
28828
  ]);
28829
+ // packages/workit-core/src/hooks/standing.ts
28830
+ var sinceStart = new Map;
28829
28831
  // packages/workit-core/src/hooks/handle.ts
28830
28832
  var offered = new Set;
28833
+ var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
28831
28834
  // packages/workit-core/src/hooks/deadline.ts
28832
28835
  var QUIET = new Set([
28833
28836
  "stop",
@@ -290,4 +290,64 @@ function maybeHeavy(command, cwd, env = process.env) {
290
290
  }
291
291
  }
292
292
 
293
- export { CHECKS_FILE, repoHeavyCommands, loadCheckConfig, matchesNamedCheck, gateCheckNames, checkCommand, stateDir, maybeHeavy };
293
+ // packages/workit-core/src/hooks/standing-signal.ts
294
+ import { createHash } from "node:crypto";
295
+ import fs3 from "node:fs";
296
+ import path3 from "node:path";
297
+ var gitStoreDir = (cwd) => {
298
+ try {
299
+ for (let dir = path3.resolve(cwd);; dir = path3.dirname(dir)) {
300
+ const dotGit = path3.join(dir, ".git");
301
+ if (fs3.existsSync(dotGit)) {
302
+ let gitDir = dotGit;
303
+ if (fs3.statSync(dotGit).isFile()) {
304
+ const target = /^gitdir:\s*(.+)$/mu.exec(fs3.readFileSync(dotGit, "utf8"))?.[1]?.trim();
305
+ if (!target)
306
+ return null;
307
+ gitDir = path3.resolve(dir, target);
308
+ const common = path3.join(gitDir, "commondir");
309
+ if (fs3.existsSync(common))
310
+ gitDir = path3.resolve(gitDir, fs3.readFileSync(common, "utf8").trim());
311
+ }
312
+ return path3.join(gitDir, "workit");
313
+ }
314
+ if (path3.dirname(dir) === dir)
315
+ return null;
316
+ }
317
+ } catch {
318
+ return null;
319
+ }
320
+ };
321
+ var standingRevFile = (store) => path3.join(store, "standing", "rev");
322
+ var standingSeenFile = (store, session, agentId) => path3.join(store, "standing", "seen", `${createHash("sha256").update(`${session}\x00${agentId ?? ""}`).digest("hex").slice(0, 32)}.json`);
323
+ var readStandingRev = (store) => {
324
+ try {
325
+ return fs3.readFileSync(standingRevFile(store), "utf8").trim() || null;
326
+ } catch {
327
+ return null;
328
+ }
329
+ };
330
+ var readStandingSeen = (file) => {
331
+ try {
332
+ const value = JSON.parse(fs3.readFileSync(file, "utf8"));
333
+ return {
334
+ rev: typeof value.rev === "string" ? value.rev : null,
335
+ ids: Array.isArray(value.ids) ? value.ids.filter((id) => typeof id === "string") : []
336
+ };
337
+ } catch {
338
+ return { rev: null, ids: [] };
339
+ }
340
+ };
341
+ var writeStandingSeen = (file, seen) => {
342
+ try {
343
+ fs3.mkdirSync(path3.dirname(file), { recursive: true });
344
+ fs3.writeFileSync(file, JSON.stringify(seen));
345
+ } catch {}
346
+ };
347
+ var standingPending = (cwd, session, agentId) => {
348
+ const store = gitStoreDir(cwd);
349
+ const rev = store ? readStandingRev(store) : null;
350
+ return rev !== null && readStandingSeen(standingSeenFile(store, session, agentId)).rev !== rev;
351
+ };
352
+
353
+ export { CHECKS_FILE, repoHeavyCommands, loadCheckConfig, matchesNamedCheck, gateCheckNames, checkCommand, stateDir, maybeHeavy, gitStoreDir, standingSeenFile, readStandingRev, readStandingSeen, writeStandingSeen, standingPending };
@@ -6,8 +6,13 @@ import {
6
6
  matchesNamedCheck,
7
7
  gateCheckNames,
8
8
  checkCommand,
9
- maybeHeavy
10
- } from "./workit-hook-kg4dxyfv.js";
9
+ maybeHeavy,
10
+ gitStoreDir,
11
+ standingSeenFile,
12
+ readStandingRev,
13
+ readStandingSeen,
14
+ writeStandingSeen
15
+ } from "./workit-hook-thet0x8m.js";
11
16
  // packages/workit-core/src/hooks/descriptor.ts
12
17
  var support = (descriptor, axis) => {
13
18
  if (axis.startsWith("event:"))
@@ -14536,6 +14541,28 @@ function checkVerdicts(cwd, branch, ledgerRows) {
14536
14541
  warnings
14537
14542
  };
14538
14543
  }
14544
+ var fromLead = (row, leads) => leads === null || row.actor.session !== null && leads.includes(row.actor.session);
14545
+ function activeStanding(rows, fanout, leads = null) {
14546
+ const active = [];
14547
+ for (const row of rows) {
14548
+ if (row.fanout !== fanout || !fromLead(row, leads))
14549
+ continue;
14550
+ if (row.type === "standing" && typeof row.what === "string" && row.what.trim()) {
14551
+ if (!row.superseded)
14552
+ active.push(row);
14553
+ } else if (row.type === "standing.cleared") {
14554
+ const target = str(row.target);
14555
+ if (target === null)
14556
+ active.length = 0;
14557
+ else {
14558
+ const index = active.findIndex((order) => order.id === target);
14559
+ if (index >= 0)
14560
+ active.splice(index, 1);
14561
+ }
14562
+ }
14563
+ }
14564
+ return active;
14565
+ }
14539
14566
  var OBSERVED_ONLY = new Set([
14540
14567
  "check",
14541
14568
  "merge.unverified",
@@ -22132,6 +22159,109 @@ var writeTargets = (input) => {
22132
22159
  const paths = writePaths(input);
22133
22160
  return paths.length > 0 ? paths : null;
22134
22161
  };
22162
+ // packages/workit-core/src/hooks/standing.ts
22163
+ import fs19 from "node:fs";
22164
+ import path26 from "node:path";
22165
+ var readPlans = (store) => {
22166
+ const dir = path26.join(store, "fanouts");
22167
+ let names;
22168
+ try {
22169
+ names = fs19.readdirSync(dir).filter((name) => name.endsWith(".json"));
22170
+ } catch {
22171
+ return [];
22172
+ }
22173
+ const plans = [];
22174
+ for (const name of names) {
22175
+ try {
22176
+ const raw = JSON.parse(fs19.readFileSync(path26.join(dir, name), "utf8"));
22177
+ if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
22178
+ continue;
22179
+ const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
22180
+ plans.push({
22181
+ name: raw.name,
22182
+ leads: texts([raw.leadSession, ...texts(raw.formerLeads)]),
22183
+ branches: texts(raw.slices.map((slice) => slice && typeof slice === "object" ? slice.branch : null))
22184
+ });
22185
+ } catch {}
22186
+ }
22187
+ return plans;
22188
+ };
22189
+ var leadOf2 = (input) => input.session.parentId ?? (input.session.agentId ? input.session.id : null) ?? (input.session.id.includes(":") ? input.session.id.split(":")[0] : null);
22190
+ var worksFor = (plan, input, branch) => {
22191
+ const session = input.session.id;
22192
+ if (plan.leads.includes(session) && !input.session.agentId)
22193
+ return false;
22194
+ const lead = leadOf2(input);
22195
+ if (lead && plan.leads.includes(lead))
22196
+ return true;
22197
+ if (plan.leads.some((each) => session.startsWith(`${each}-w-`)))
22198
+ return true;
22199
+ const current = branch();
22200
+ return current !== null && plan.branches.includes(current);
22201
+ };
22202
+ var standingFor = (input, store, rev) => {
22203
+ const orders = new Map;
22204
+ const ledger = readLedger(input.cwd);
22205
+ const rows = ledger.ok ? ledger.value.rows : [];
22206
+ let branch;
22207
+ const lazyBranch = () => branch === undefined ? branch = currentBranch(input.cwd) : branch;
22208
+ for (const plan of readPlans(store))
22209
+ if (worksFor(plan, input, lazyBranch))
22210
+ for (const row of activeStanding(rows, plan.name, plan.leads.length ? plan.leads : null))
22211
+ orders.set(row.id, row);
22212
+ return { rev, orders, rows };
22213
+ };
22214
+ var located = (input) => {
22215
+ const store = input.session.id ? gitStoreDir(input.cwd) : null;
22216
+ const rev = store ? readStandingRev(store) : null;
22217
+ if (!store || rev === null)
22218
+ return null;
22219
+ return { store, rev, file: standingSeenFile(store, input.session.id, input.session.agentId) };
22220
+ };
22221
+ var seedStanding = (input) => {
22222
+ try {
22223
+ const where = located(input);
22224
+ if (!where)
22225
+ return;
22226
+ const now = standingFor(input, where.store, where.rev);
22227
+ writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
22228
+ } catch {}
22229
+ };
22230
+ var fanoutOf = (row) => typeof row.fanout === "string" ? row.fanout : "?";
22231
+ var changedSince = (now, ids) => {
22232
+ const known = new Set(ids);
22233
+ const added = [...now.orders.values()].filter((row) => !known.has(row.id));
22234
+ const byId = new Map(now.rows.map((row) => [row.id, row]));
22235
+ const dropped = ids.filter((id) => !now.orders.has(id)).map((id) => byId.get(id)).filter((row) => row !== undefined);
22236
+ if (!added.length && !dropped.length)
22237
+ return null;
22238
+ const fanouts = [...new Set([...added, ...dropped].map(fanoutOf))].join(", ");
22239
+ const lines = [
22240
+ `Workit: the lead changed the standing orders for fanout ${fanouts} while you run. They apply to you now and override your brief's STANDING list.`,
22241
+ ...added.map((row) => ` - new: ${String(row.what)}`),
22242
+ ...dropped.map((row) => ` - no longer in force: ${String(row.what)}${row.stop ? " (the stop is lifted: continue your brief)" : ""}`)
22243
+ ];
22244
+ if (added.some((row) => row.stop === true))
22245
+ lines.push("Stop now: make no further changes, close what you opened, and report to the lead with your branch, head SHA, what is done and what is not.");
22246
+ return lines.join(`
22247
+ `);
22248
+ };
22249
+ var standingDelta = (input) => {
22250
+ try {
22251
+ const where = located(input);
22252
+ if (!where)
22253
+ return null;
22254
+ const seen = readStandingSeen(where.file);
22255
+ if (seen.rev === where.rev)
22256
+ return null;
22257
+ const now = standingFor(input, where.store, where.rev);
22258
+ writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
22259
+ return changedSince(now, seen.ids);
22260
+ } catch {
22261
+ return null;
22262
+ }
22263
+ };
22264
+ var sinceStart = new Map;
22135
22265
  // packages/workit-core/src/hooks/handle.ts
22136
22266
  var usable2 = (value) => value === "native" || value === "partial";
22137
22267
  var NONE5 = { kind: "none" };
@@ -22176,7 +22306,18 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
22176
22306
  const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
22177
22307
  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." : ""}`;
22178
22308
  };
22309
+ var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
22179
22310
  function handleHook(input, deps) {
22311
+ const decision = decide(input, deps);
22312
+ if (deps.descriptor.transport !== "hook-process" || !PRE_TOOL.has(input.event.kind) || decision.kind === "deny")
22313
+ return decision;
22314
+ const delta = standingDelta(input);
22315
+ if (!delta)
22316
+ return decision;
22317
+ return decision.kind === "rewrite" ? { ...decision, text: [decision.text, delta].filter(Boolean).join(`
22318
+ `) } : withContextLine(decision, delta);
22319
+ }
22320
+ function decide(input, deps) {
22180
22321
  const { descriptor } = deps;
22181
22322
  const event = input.event;
22182
22323
  switch (event.kind) {
@@ -22253,6 +22394,7 @@ function handleHook(input, deps) {
22253
22394
  case "write.pre":
22254
22395
  return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths, liveOwner(input, descriptor.transport)) : NONE5;
22255
22396
  case "subagent.start":
22397
+ seedStanding({ ...input, session: { ...input.session, agentId: event.agentId } });
22256
22398
  return {
22257
22399
  kind: "context",
22258
22400
  text: subagentStartText(input, descriptor, event)
@@ -22304,7 +22446,7 @@ var dispatchHook = (adapter, raw, env = process.env) => {
22304
22446
  };
22305
22447
  // packages/workit-core/src/hooks/deadline.ts
22306
22448
  import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
22307
- import path26 from "node:path";
22449
+ import path27 from "node:path";
22308
22450
  var HOOK_SKIP_TEXT = "workit context skipped: host under load";
22309
22451
  var HOOK_DEADLINE_MS = 8000;
22310
22452
  var HOST_DEADLINES = {
@@ -22322,7 +22464,7 @@ var hookDeadlineMs = (env, host = "", native) => {
22322
22464
  const row = HOST_DEADLINES[host];
22323
22465
  return override(env) ?? (row ? native === undefined ? Math.min(...Object.values(row)) : row[native] ?? row[""] : HOOK_DEADLINE_MS);
22324
22466
  };
22325
- var skipsFile = (stateDir) => path26.join(stateDir, HOOK_SKIPS_FILE);
22467
+ var skipsFile = (stateDir) => path27.join(stateDir, HOOK_SKIPS_FILE);
22326
22468
  var recordHookSkip = (skip, stateDir = resolveStateDir()) => {
22327
22469
  try {
22328
22470
  mkdirSync3(stateDir, { recursive: true });
@@ -22966,8 +23108,8 @@ var codexAdapter = {
22966
23108
  };
22967
23109
 
22968
23110
  // packages/workit-core/src/hooks/hosts/cursor.ts
22969
- import fs19 from "node:fs";
22970
- import path27 from "node:path";
23111
+ import fs20 from "node:fs";
23112
+ import path28 from "node:path";
22971
23113
  var undocumented = { support: "undocumented", native: null };
22972
23114
  var none = { support: "none", native: null };
22973
23115
  var CURSOR_DESCRIPTOR = {
@@ -23164,17 +23306,17 @@ var protocolEvent2 = (input) => {
23164
23306
  };
23165
23307
  var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
23166
23308
  var lastAssistantText = (file) => {
23167
- if (!file || !path27.isAbsolute(file))
23309
+ if (!file || !path28.isAbsolute(file))
23168
23310
  return null;
23169
23311
  try {
23170
- const size = fs19.statSync(file).size;
23312
+ const size = fs20.statSync(file).size;
23171
23313
  const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
23172
23314
  const buffer = Buffer.alloc(size - start);
23173
- const fd = fs19.openSync(file, "r");
23315
+ const fd = fs20.openSync(file, "r");
23174
23316
  try {
23175
- fs19.readSync(fd, buffer, 0, buffer.length, start);
23317
+ fs20.readSync(fd, buffer, 0, buffer.length, start);
23176
23318
  } finally {
23177
- fs19.closeSync(fd);
23319
+ fs20.closeSync(fd);
23178
23320
  }
23179
23321
  const lines = buffer.toString("utf8").split(`
23180
23322
  `);
@@ -23201,7 +23343,7 @@ var lastAssistantText = (file) => {
23201
23343
  return null;
23202
23344
  }
23203
23345
  };
23204
- var within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path27.sep) ? root : `${root}${path27.sep}`);
23346
+ var within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path28.sep) ? root : `${root}${path28.sep}`);
23205
23347
  var hookCwd = (input) => {
23206
23348
  const cwd = existingDirectory(input.cwd);
23207
23349
  if (cwd && input.hook_event_name === "beforeShellExecution")
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stateDir,
4
- maybeHeavy
5
- } from "./workit-hook-kg4dxyfv.js";
4
+ maybeHeavy,
5
+ standingPending
6
+ } from "./workit-hook-thet0x8m.js";
6
7
 
7
8
  // packages/workit-codex/hooks/launcher.ts
8
9
  var payload = "";
@@ -22,6 +23,8 @@ var quietEvent = () => {
22
23
  return null;
23
24
  if (typeof value.cwd !== "string" || typeof value.tool_name !== "string")
24
25
  return null;
26
+ if (event === "PreToolUse" && typeof value.session_id === "string" && standingPending(value.cwd, value.session_id, typeof value.agent_id === "string" && value.agent_id.trim() ? value.agent_id : null))
27
+ return null;
25
28
  const tool = value.tool_name.toLowerCase();
26
29
  if (event === "PreToolUse" && WRITE_TOOLS.has(tool.replace(/[_-]/g, "")))
27
30
  return null;
@@ -44,6 +47,6 @@ if (quiet)
44
47
  process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: quiet } })}
45
48
  `);
46
49
  else {
47
- const { runCodexHook } = await import("./workit-hook-00hstm40.js");
50
+ const { runCodexHook } = await import("./workit-hook-xhk0gksg.js");
48
51
  await runCodexHook([payload]);
49
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-codex",
3
- "version": "8.20.0",
3
+ "version": "8.21.0",
4
4
  "private": false,
5
5
  "description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
6
6
  "keywords": [
@@ -39,8 +39,8 @@
39
39
  "build": "bun scripts/build.ts"
40
40
  },
41
41
  "devDependencies": {
42
- "@brainervirus/workit-core": "^8.20.0",
43
- "@brainervirus/workit-mcp": "^8.20.0"
42
+ "@brainervirus/workit-core": "^8.21.0",
43
+ "@brainervirus/workit-mcp": "^8.21.0"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=24"