@brainervirus/workit-cursor 8.4.1 → 8.5.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.
@@ -17273,6 +17273,8 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
17273
17273
  };
17274
17274
  });
17275
17275
  // packages/workit-core/src/hooks/context.ts
17276
+ import { createHash as createHash10 } from "node:crypto";
17277
+ import fs13 from "node:fs";
17276
17278
  import path16 from "node:path";
17277
17279
  var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
17278
17280
  var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
@@ -17420,8 +17422,77 @@ var turnContextText = (input, descriptor) => {
17420
17422
  return null;
17421
17423
  }
17422
17424
  };
17425
+ var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
17426
+ var digestOf = (text) => createHash10("sha256").update(text).digest("hex");
17427
+ var turnMarker = (input) => {
17428
+ if (!input.session.id)
17429
+ return null;
17430
+ try {
17431
+ const location = resolveStore(input.cwd);
17432
+ if (location instanceof Error)
17433
+ return null;
17434
+ const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
17435
+ return path16.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17436
+ } catch {
17437
+ return null;
17438
+ }
17439
+ };
17440
+ var writeTurnDigest = (file, digest) => {
17441
+ try {
17442
+ fs13.mkdirSync(path16.dirname(file), { recursive: true });
17443
+ fs13.writeFileSync(file, `${JSON.stringify({ digest })}
17444
+ `);
17445
+ } catch {}
17446
+ };
17447
+ var clearTurnDigest = (file) => {
17448
+ try {
17449
+ fs13.rmSync(file, { force: true });
17450
+ } catch {}
17451
+ };
17452
+ var pruneTurnDigests = (dir, now) => {
17453
+ try {
17454
+ for (const name of fs13.readdirSync(dir)) {
17455
+ if (!name.startsWith("turn-"))
17456
+ continue;
17457
+ const file = path16.join(dir, name);
17458
+ try {
17459
+ if (now - fs13.statSync(file).mtimeMs > TURN_TTL_MS)
17460
+ fs13.rmSync(file, { force: true });
17461
+ } catch {}
17462
+ }
17463
+ } catch {}
17464
+ };
17465
+ var changedTurnContext = (input, text) => {
17466
+ const file = turnMarker(input);
17467
+ if (!text) {
17468
+ if (file)
17469
+ clearTurnDigest(file);
17470
+ return null;
17471
+ }
17472
+ if (!file)
17473
+ return text;
17474
+ const digest = digestOf(text);
17475
+ try {
17476
+ const previous = JSON.parse(fs13.readFileSync(file, "utf8"));
17477
+ if (previous.digest === digest)
17478
+ return null;
17479
+ } catch {}
17480
+ writeTurnDigest(file, digest);
17481
+ return text;
17482
+ };
17483
+ var seedTurnContext = (input, descriptor) => {
17484
+ const file = turnMarker(input);
17485
+ if (!file)
17486
+ return;
17487
+ pruneTurnDigests(path16.dirname(file), Date.now());
17488
+ const text = turnContextText(input, descriptor);
17489
+ if (text)
17490
+ writeTurnDigest(file, digestOf(text));
17491
+ else
17492
+ clearTurnDigest(file);
17493
+ };
17423
17494
  // packages/workit-core/src/core/branch.ts
17424
- import { createHash as createHash10 } from "node:crypto";
17495
+ import { createHash as createHash11 } from "node:crypto";
17425
17496
  var withReleaseTracks = (workspaceRoot, policy) => {
17426
17497
  const read = workspaceReleaseTracks(workspaceRoot);
17427
17498
  if (read.error)
@@ -17489,7 +17560,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
17489
17560
  const source = resolved.provenance.branchPolicy;
17490
17561
  const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
17491
17562
  const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
17492
- const fingerprint = createHash10("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17563
+ const fingerprint = createHash11("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17493
17564
  return {
17494
17565
  branchPolicy,
17495
17566
  namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
@@ -17824,7 +17895,7 @@ function writeGate(cwd, paths) {
17824
17895
  const gate = gateFor(cwd);
17825
17896
  if (!gate || gate.blockers.length === 0)
17826
17897
  return NONE2;
17827
- if (paths && paths.every((file) => exempt(cwd, gate.root, file, gate.plans)))
17898
+ if (paths?.length && paths.every((file) => exempt(cwd, gate.root, file, gate.plans)))
17828
17899
  return NONE2;
17829
17900
  const reasons = gate.blockers.map((item) => `${item.ruleId}: ${item.reason}`).join("; ");
17830
17901
  return {
@@ -17838,8 +17909,8 @@ function writeGate(cwd, paths) {
17838
17909
  }
17839
17910
  // packages/workit-core/src/hooks/raw-git.ts
17840
17911
  import { spawnSync as spawnSync11 } from "node:child_process";
17841
- import { createHash as createHash11 } from "node:crypto";
17842
- import fs13 from "node:fs";
17912
+ import { createHash as createHash12 } from "node:crypto";
17913
+ import fs14 from "node:fs";
17843
17914
  import os4 from "node:os";
17844
17915
  import path18 from "node:path";
17845
17916
  var NONE3 = { kind: "none" };
@@ -18085,7 +18156,7 @@ var repoAt = (dir) => {
18085
18156
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
18086
18157
  };
18087
18158
  var isWorkitWorkspace = (repo) => {
18088
- if (fs13.existsSync(repo.location.dir))
18159
+ if (fs14.existsSync(repo.location.dir))
18089
18160
  return true;
18090
18161
  try {
18091
18162
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -18116,7 +18187,7 @@ var headSha2 = (repo) => {
18116
18187
  if (!git || git.reftable)
18117
18188
  return null;
18118
18189
  try {
18119
- const head = fs13.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
18190
+ const head = fs14.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
18120
18191
  if (/^[0-9a-f]{40,64}$/.test(head))
18121
18192
  return head;
18122
18193
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
@@ -18124,9 +18195,9 @@ var headSha2 = (repo) => {
18124
18195
  return null;
18125
18196
  const common = path18.dirname(repo.location.dir);
18126
18197
  try {
18127
- return fs13.readFileSync(path18.join(common, ref), "utf8").trim() || null;
18198
+ return fs14.readFileSync(path18.join(common, ref), "utf8").trim() || null;
18128
18199
  } catch {}
18129
- const packed = fs13.readFileSync(path18.join(common, "packed-refs"), "utf8");
18200
+ const packed = fs14.readFileSync(path18.join(common, "packed-refs"), "utf8");
18130
18201
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
18131
18202
  } catch {
18132
18203
  return null;
@@ -18174,6 +18245,11 @@ var actionsIn = (cwd, command, dialect) => {
18174
18245
  }
18175
18246
  return out;
18176
18247
  };
18248
+ var inWorkitWorkspace = (dir) => {
18249
+ const repo = repoAt(dir);
18250
+ return repo !== null && isWorkitWorkspace(repo);
18251
+ };
18252
+ var rawDelivery = (cwd, command, dialect) => mentionsRawTool(command) && actionsIn(cwd, command, dialect).some(({ action }) => action.kind !== "commit" && action.kind !== "pr-read");
18177
18253
  var mentionsRawTool = (command) => /\b(?:git|gh|glab)\b/i.test(command);
18178
18254
  var dialectOf = (input) => (input.event.kind === "shell.pre" || input.event.kind === "shell.post" ? input.event.dialect : undefined) ?? "posix";
18179
18255
  function rawGitPre(input, command) {
@@ -18203,8 +18279,8 @@ function rawGitPre(input, command) {
18203
18279
  var deny = (reason) => ({ kind: "deny", reason, unblock: null });
18204
18280
  var NEXT_COMMAND = "next";
18205
18281
  var MARKER_TTL_SECONDS = 3600;
18206
- var markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash11("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18207
- var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash11("sha256").update(command).digest("hex")}`;
18282
+ var markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash12("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
18283
+ var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash12("sha256").update(command).digest("hex")}`;
18208
18284
  function noteRawCommit(input, command, key) {
18209
18285
  try {
18210
18286
  if (!input.session.id || !/\bcommit\b/.test(command))
@@ -18214,8 +18290,8 @@ function noteRawCommit(input, command, key) {
18214
18290
  if (action.kind !== "commit")
18215
18291
  continue;
18216
18292
  const file = markerFile(repo, input.session.id, key);
18217
- fs13.mkdirSync(path18.dirname(file), { recursive: true });
18218
- fs13.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18293
+ fs14.mkdirSync(path18.dirname(file), { recursive: true });
18294
+ fs14.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18219
18295
  `);
18220
18296
  }
18221
18297
  } catch {}
@@ -18238,11 +18314,11 @@ var headCommit = (dir) => {
18238
18314
  var settle2 = (input, repo, file) => {
18239
18315
  let marker;
18240
18316
  try {
18241
- marker = JSON.parse(fs13.readFileSync(file, "utf8"));
18317
+ marker = JSON.parse(fs14.readFileSync(file, "utf8"));
18242
18318
  } catch {
18243
18319
  return;
18244
18320
  }
18245
- fs13.rmSync(file, { force: true });
18321
+ fs14.rmSync(file, { force: true });
18246
18322
  const session = input.session.id;
18247
18323
  const now = Date.now() / 1000;
18248
18324
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -18291,18 +18367,292 @@ function settlePendingCommit(input) {
18291
18367
  if (!repo)
18292
18368
  return;
18293
18369
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
18294
- if (fs13.existsSync(file))
18370
+ if (fs14.existsSync(file))
18295
18371
  settle2(input, repo, file);
18296
18372
  } catch {}
18297
18373
  }
18374
+ // packages/workit-core/src/hooks/skill-nudge.ts
18375
+ import { createHash as createHash13 } from "node:crypto";
18376
+ import fs15 from "node:fs";
18377
+ import path19 from "node:path";
18378
+
18379
+ // packages/workit-core/src/core/skill-manifests.ts
18380
+ var WORKIT_METHOD_SKILLS = [
18381
+ "workit-shape",
18382
+ "workit-implement",
18383
+ "workit-review",
18384
+ "workit-debug",
18385
+ "workit-ship",
18386
+ "workit-continue",
18387
+ "workit-bdd",
18388
+ "workit-test-audit",
18389
+ "workit-deslop",
18390
+ "workit-fanout",
18391
+ "workit-verify-app",
18392
+ "workit-retro",
18393
+ "workit-architecture"
18394
+ ];
18395
+ var WORKIT_SKILL_ALIASES = {
18396
+ "wk-shape": "workit-shape",
18397
+ "wk-implement": "workit-implement",
18398
+ "wk-review": "workit-review",
18399
+ "wk-debug": "workit-debug",
18400
+ "wk-ship": "workit-ship",
18401
+ "wk-continue": "workit-continue",
18402
+ "wk-bdd": "workit-bdd",
18403
+ "wk-test-audit": "workit-test-audit",
18404
+ "wk-deslop": "workit-deslop",
18405
+ "wk-fanout": "workit-fanout",
18406
+ "wk-verify-app": "workit-verify-app",
18407
+ "wk-retro": "workit-retro",
18408
+ "wk-architecture": "workit-architecture"
18409
+ };
18410
+ var skillLoadWording = (host, skill) => {
18411
+ switch (host) {
18412
+ case "claude-code":
18413
+ return `call the Skill tool with \`workit:${skill.replace(/^workit-/, "")}\``;
18414
+ case "opencode":
18415
+ return `call the skill tool with \`${skill}\``;
18416
+ default:
18417
+ return `read the \`${skill}\` skill's SKILL.md and follow it`;
18418
+ }
18419
+ };
18420
+ if (false) {}
18421
+
18422
+ // packages/workit-core/src/hooks/skill-nudge.ts
18423
+ var USER_INVOKED = new Set(["workit-retro", "workit-architecture"]);
18424
+ var SKILL_HOST = {
18425
+ claude_code: "claude-code",
18426
+ opencode: "opencode",
18427
+ codex_cli: "codex",
18428
+ codex_desktop: "codex",
18429
+ cursor: "cursor",
18430
+ pi: "pi"
18431
+ };
18432
+ var PROMPT_INTENTS = [
18433
+ [
18434
+ "workit-debug",
18435
+ /\b(flaky|regression|(?:is|are|got|looks) broken|debug (?:this|it|the|why)|fix (?:the|this|a) bug)\b/i
18436
+ ],
18437
+ [
18438
+ "workit-continue",
18439
+ /\b(pick up where|where (?:were|did) we|resume (?:the|this|my|our|work|where)|hand ?off)\b/i
18440
+ ],
18441
+ [
18442
+ "workit-review",
18443
+ /\b(blast radius|code review|review (?:the|this|my|PR|pr|#\d+|branch|diff|changes))\b/i
18444
+ ],
18445
+ [
18446
+ "workit-ship",
18447
+ /\b(ship (?:it|this|the)|babysit|open (?:a|the) (?:PR|pr|MR|mr)|merge (?:the|this|my) (?:PR|pr|MR|mr|branch)|(?:get|until|make) CI (?:is )?green)\b/i
18448
+ ],
18449
+ ["workit-bdd", /\b(BDD|TDD|acceptance criteria|Given\/When\/Then)(?![\w/])/],
18450
+ ["workit-test-audit", /\b(test audit|audit the tests|tautolog\w*|weak tests)\b/i],
18451
+ ["workit-deslop", /\b(deslop|slop|dead code)\b/i],
18452
+ ["workit-fanout", /\b(fan(?: |-)?out|parallelize|parallel agents|swarm)\b/i],
18453
+ ["workit-verify-app", /\b(verify the app|smoke test|prove it works)\b/i],
18454
+ ["workit-retro", /\b(retro|retrospective)\b(?!\.\w)/i],
18455
+ ["workit-architecture", /\b(deepen (?:the )?modules|architecture (?:review|pass|audit))\b/i],
18456
+ [
18457
+ "workit-shape",
18458
+ /\b(brainstorm\w*|grill me|should we|let'?s plan|plan (?:out|how|the|a|for)|(?:write|draft) (?:a|the) spec)\b/i
18459
+ ],
18460
+ [
18461
+ "workit-implement",
18462
+ /\b(implement (?:the|this|a|it)|add (?:a|the) feature|build (?:a|an|the) (?:new )?(?:feature|command|verb|page|endpoint|component|cli|tool))\b/i
18463
+ ]
18464
+ ];
18465
+ var workitSkillOf = (name) => {
18466
+ const bare = name.trim().replace(/^\//, "").toLowerCase();
18467
+ const alias = WORKIT_SKILL_ALIASES[bare];
18468
+ if (alias)
18469
+ return alias;
18470
+ const skill = bare.replace(/^workit:/, "workit-");
18471
+ return WORKIT_METHOD_SKILLS.includes(skill) ? skill : null;
18472
+ };
18473
+ var promptTrigger = (prompt) => {
18474
+ const text = prompt.replace(/```[\s\S]*?```/g, " ").slice(0, 4000);
18475
+ for (const [skill, pattern] of PROMPT_INTENTS) {
18476
+ const match = pattern.exec(text);
18477
+ if (match)
18478
+ return { skill, trigger: match[1] ?? match[0] };
18479
+ }
18480
+ return null;
18481
+ };
18482
+ var markerFile2 = (input, session) => {
18483
+ const location = resolveStore(input.cwd);
18484
+ if (location instanceof Error || !location.shared)
18485
+ return null;
18486
+ const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18487
+ return path19.join(location.dir, "hooks", `skills-${name}.json`);
18488
+ };
18489
+ var readMarker = (file) => {
18490
+ try {
18491
+ const value = JSON.parse(fs15.readFileSync(file, "utf8"));
18492
+ return { nudged: value.nudged ?? [], loaded: value.loaded ?? [] };
18493
+ } catch {
18494
+ return { nudged: [], loaded: [] };
18495
+ }
18496
+ };
18497
+ var writeMarker = (file, marker) => {
18498
+ try {
18499
+ fs15.mkdirSync(path19.dirname(file), { recursive: true });
18500
+ fs15.writeFileSync(file, JSON.stringify(marker));
18501
+ } catch {}
18502
+ };
18503
+ var loadedSkills = (cwd, session) => {
18504
+ const ledger = readLedger(cwd);
18505
+ const loaded = new Set;
18506
+ if (!ledger.ok)
18507
+ return loaded;
18508
+ for (const row of ledger.value.rows)
18509
+ if (row.type === "skill.loaded" && row.actor.session === session && typeof row.skill === "string")
18510
+ loaded.add(row.skill);
18511
+ return loaded;
18512
+ };
18513
+ var SKILL_FILE = /(?:^|[\\/])(workit-[a-z-]+)[\\/]SKILL\.md$/;
18514
+ var skillFileIn = (file) => SKILL_FILE.exec(file)?.[1] ?? null;
18515
+ var READERS = new Set([
18516
+ "cat",
18517
+ "sed",
18518
+ "head",
18519
+ "tail",
18520
+ "less",
18521
+ "more",
18522
+ "bat",
18523
+ "nl",
18524
+ "get-content",
18525
+ "gc",
18526
+ "type"
18527
+ ]);
18528
+ var skillReadIn = (command, dialect = "posix") => {
18529
+ for (const { words } of segmentsOf(command, dialect)) {
18530
+ if (!READERS.has((words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()))
18531
+ continue;
18532
+ for (const word of words.slice(1)) {
18533
+ const skill = skillFileIn(word);
18534
+ if (skill)
18535
+ return skill;
18536
+ }
18537
+ }
18538
+ return null;
18539
+ };
18540
+ function recordSkillLoad(input, name, via) {
18541
+ try {
18542
+ const skill = workitSkillOf(name);
18543
+ const session = input.session.id;
18544
+ if (!skill || !session)
18545
+ return;
18546
+ if (!inWorkitWorkspace(input.cwd))
18547
+ return;
18548
+ const file = markerFile2(input, session);
18549
+ if (!file)
18550
+ return;
18551
+ const marker = readMarker(file);
18552
+ if (marker.loaded.includes(skill))
18553
+ return;
18554
+ writeMarker(file, { ...marker, loaded: [...marker.loaded, skill] });
18555
+ if (loadedSkills(input.cwd, session).has(skill))
18556
+ return;
18557
+ appendHookObserved(input.cwd, {
18558
+ type: "skill.loaded",
18559
+ actor: { host: input.host, session, agentId: input.session.agentId },
18560
+ skill,
18561
+ via
18562
+ });
18563
+ } catch {}
18564
+ }
18565
+ var nudgeOnce = (input, session, skill, line) => {
18566
+ const file = markerFile2(input, session);
18567
+ if (!file)
18568
+ return null;
18569
+ const marker = readMarker(file);
18570
+ if (marker.nudged.includes(skill) || marker.loaded.includes(skill))
18571
+ return null;
18572
+ if (loadedSkills(input.cwd, session).has(skill))
18573
+ return null;
18574
+ writeMarker(file, { ...marker, nudged: [...marker.nudged, skill] });
18575
+ return line;
18576
+ };
18577
+ var nudgeText = (input, skill, why) => USER_INVOKED.has(skill) ? `Workit: ${why} looks like ${skill} work, which the user starts; offer it (/${skill.replace(/^workit-/, "wk-")}) rather than loading it.` : `Workit: ${why} looks like ${skill} work; if it is, ${skillLoadWording(SKILL_HOST[input.host], skill)} first.`;
18578
+ var promptLoads = (prompt) => /^\s*\/(?:skill:)?([\w:-]+)/.exec(prompt)?.[1] ?? /^\s*<skill name="([\w:-]+)"/.exec(prompt)?.[1] ?? /^\s*Load the (workit-[a-z-]+) skill with the skill tool\b/.exec(prompt)?.[1] ?? null;
18579
+ function promptNudge(input, prompt) {
18580
+ try {
18581
+ const session = input.session.id;
18582
+ if (!prompt || !session || input.session.agentId)
18583
+ return null;
18584
+ const loads = promptLoads(prompt);
18585
+ if (loads) {
18586
+ recordSkillLoad(input, loads, "slash");
18587
+ return null;
18588
+ }
18589
+ const hit = promptTrigger(prompt);
18590
+ if (!hit || !inWorkitWorkspace(input.cwd))
18591
+ return null;
18592
+ return nudgeOnce(input, session, hit.skill, nudgeText(input, hit.skill, `this request ("${hit.trigger}")`));
18593
+ } catch {
18594
+ return null;
18595
+ }
18596
+ }
18597
+ var WORKIT_DELIVERY = /^(?:pr (?:create|merge)|ci wait|git push)\b/;
18598
+ var SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
18599
+ var LAUNCHERS = new Set([
18600
+ "npx",
18601
+ "bunx",
18602
+ "pnpx",
18603
+ "-y",
18604
+ "--yes",
18605
+ "pnpm",
18606
+ "dlx",
18607
+ "exec",
18608
+ "env",
18609
+ "sudo",
18610
+ "command"
18611
+ ]);
18612
+ var runsWorkitDelivery = (command, dialect, depth = 0) => segmentsOf(command, dialect).some(({ words }) => {
18613
+ const at = words.findIndex((word) => !/^\w+=/.test(word) && !LAUNCHERS.has(word));
18614
+ if (at >= 0 && /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/.test(words[at])) {
18615
+ const args = words.slice(at + 1);
18616
+ if (args.some((arg) => arg === "--help" || arg === "-h" || arg === "--dry-run"))
18617
+ return false;
18618
+ return WORKIT_DELIVERY.test(args.join(" "));
18619
+ }
18620
+ const shell = SHELLS2.has(words[at]?.split(/[\\/]/).at(-1) ?? "");
18621
+ const script = shell && words[at + 1] === "-c" ? words[at + 2] : undefined;
18622
+ return depth < 3 && script !== undefined && runsWorkitDelivery(script, "posix", depth + 1);
18623
+ });
18624
+ var isDeliveryCommand = (cwd, command, dialect = "posix") => rawDelivery(cwd, command, dialect) || runsWorkitDelivery(command, dialect) && inWorkitWorkspace(cwd);
18625
+ function shipNudge(input, command) {
18626
+ try {
18627
+ const session = input.session.id;
18628
+ if (!session || input.session.agentId)
18629
+ return null;
18630
+ const dialect = input.event.kind === "shell.pre" ? input.event.dialect ?? "posix" : "posix";
18631
+ if (!isDeliveryCommand(input.cwd, command, dialect))
18632
+ return null;
18633
+ return nudgeOnce(input, session, "workit-ship", nudgeText(input, "workit-ship", "this delivery step"));
18634
+ } catch {
18635
+ return null;
18636
+ }
18637
+ }
18638
+ var withContextLine = (decision, line) => {
18639
+ if (!line)
18640
+ return decision;
18641
+ if (decision.kind === "none")
18642
+ return { kind: "context", text: line };
18643
+ if (decision.kind === "context")
18644
+ return { kind: "context", text: `${decision.text}
18645
+ ${line}` };
18646
+ return decision;
18647
+ };
18298
18648
  // packages/workit-core/src/hooks/hosts/fields.ts
18299
18649
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
18300
- import path19 from "node:path";
18650
+ import path20 from "node:path";
18301
18651
  var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
18302
18652
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
18303
18653
  var optionalText = (value) => typeof value === "string" ? value : null;
18304
18654
  var existingDirectory = (value) => {
18305
- if (!nonEmpty2(value) || !path19.isAbsolute(value) || !existsSync6(value))
18655
+ if (!nonEmpty2(value) || !path20.isAbsolute(value) || !existsSync6(value))
18306
18656
  return null;
18307
18657
  try {
18308
18658
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
@@ -18310,7 +18660,7 @@ var existingDirectory = (value) => {
18310
18660
  return null;
18311
18661
  }
18312
18662
  };
18313
- var SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18663
+ var SHELLS3 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18314
18664
  var SCRIPT_FLAG2 = /^(?:-\w*c|-command|\/c)$/i;
18315
18665
  var quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg);
18316
18666
  var commandText = (value) => {
@@ -18322,7 +18672,7 @@ var commandText = (value) => {
18322
18672
  if (!argv.every((arg) => typeof arg === "string"))
18323
18673
  return null;
18324
18674
  const shell = argv[0].split(/[\\/]/).at(-1)?.replace(/\.exe$/i, "").toLowerCase() ?? "";
18325
- if (SHELLS2.has(shell))
18675
+ if (SHELLS3.has(shell))
18326
18676
  for (let index = 1;index < argv.length - 1; index++) {
18327
18677
  if (SCRIPT_FLAG2.test(argv[index]))
18328
18678
  return nonEmpty2(argv[index + 1]) ? argv[index + 1] : null;
@@ -18353,30 +18703,49 @@ var WRITE_TOOLS = new Set([
18353
18703
  ]);
18354
18704
  var isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, ""));
18355
18705
  var PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
18706
+ var PATCH_HEADER = /^[ \t]*\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+)$/gm;
18356
18707
  var writePaths = (input) => {
18357
18708
  if (!isRecord4(input))
18358
18709
  return [];
18359
18710
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
18360
18711
  for (const value of Object.values(input))
18361
18712
  if (typeof value === "string")
18362
- for (const match of value.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm))
18713
+ for (const match of value.matchAll(PATCH_HEADER))
18363
18714
  paths.push(match[1].trim());
18364
18715
  return [...new Set(paths)];
18365
18716
  };
18717
+ var writeTargets = (input) => {
18718
+ const paths = writePaths(input);
18719
+ return paths.length > 0 ? paths : null;
18720
+ };
18366
18721
  // packages/workit-core/src/hooks/handle.ts
18367
18722
  var usable2 = (value) => value === "native" || value === "partial";
18368
18723
  var NONE4 = { kind: "none" };
18724
+ var resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn);
18369
18725
  var offered = new Set;
18370
- var CLAUDE_WORKTREE_IMPLEMENTER = "workit:implementer";
18371
- var CLAUDE_JUDGES = new Set(["workit:verifier", "workit:reviewer"]);
18726
+ var ROLES = {
18727
+ implementer: "implementer",
18728
+ verifier: "judge",
18729
+ reviewer: "judge"
18730
+ };
18731
+ var workitRole = (descriptor, agentType) => {
18732
+ const prefix = descriptor.subagents.agentPrefix;
18733
+ const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
18734
+ return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
18735
+ };
18372
18736
  var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
18373
- var subagentStartText = (host, session, descriptor, event) => {
18374
- if (host === "claude_code" && event.agentType === CLAUDE_WORKTREE_IMPLEMENTER)
18375
- return `Workit observed ${descriptor.label} subagent ${event.agentId} (${event.agentType}) working in its own git worktree: it may edit and commit there, within its brief's scope. Before the first commit, switch to a policy-compliant branch with \`workit git branch <branch> --base <base>\` (e.g. feature/<slug>); branch policy hooks still deny protected or non-compliant branches. Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
18376
- const readOnly = `Workit observed ${descriptor.label} subagent ${event.agentId} (${event.agentType}) as read-only/agent-guided.`;
18377
- if (host === "claude_code" && event.agentType && CLAUDE_JUDGES.has(event.agentType) && event.agentId)
18378
- return `${readOnly} Its own Workit session is ${subagentSession(session, event.agentId)}: record verdicts with \`workit ledger verdict <result> --session ${subagentSession(session, event.agentId)} ...\` so the ledger tells it apart from the author.`;
18379
- return readOnly;
18737
+ var subagentStartText = (session, descriptor, event) => {
18738
+ const role = workitRole(descriptor, event.agentType);
18739
+ const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
18740
+ if (role === "implementer") {
18741
+ const where = descriptor.subagents.worktreeIsolation === "native" ? "working in its own git worktree: it may edit and commit there" : "as an implementer: it edits and commits only in its own git worktree (the lead makes one with `workit fanout worktree create <slice>`), never in the lead's checkout";
18742
+ return `Workit observed ${who} ${where}, within its brief's scope. Before the first commit, switch to a policy-compliant branch with \`workit git branch <branch> --base <base>\` (e.g. feature/<slug>); branch policy hooks still deny protected or non-compliant branches. Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
18743
+ }
18744
+ const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
18745
+ if (role !== "judge" || !event.agentId)
18746
+ return readOnly;
18747
+ const own = subagentSession(session, event.agentId);
18748
+ return `${readOnly} Its own Workit session is ${own}: record verdicts with \`workit ledger verdict <result> --session ${own} ...\` so the ledger tells it apart from the author.`;
18380
18749
  };
18381
18750
  function handleHook(input, deps) {
18382
18751
  const { descriptor } = deps;
@@ -18392,18 +18761,22 @@ function handleHook(input, deps) {
18392
18761
  const advisory = usable2(descriptor.events["write.pre"].support) ? null : `Workit cannot gate file writes on ${descriptor.label} (no pre-write hook): before-write requirements (an open product choice, a missing plan) are advisory here, so settle them before editing.`;
18393
18762
  const addendum = [deps.addendum, advisory].filter(Boolean).join(`
18394
18763
  `) || null;
18395
- return {
18396
- kind: "context",
18397
- text: sessionContextText(input, descriptor, { offer, addendum })
18398
- };
18764
+ const text = sessionContextText(input, descriptor, { offer, addendum });
18765
+ if (resendsOnChange(descriptor))
18766
+ seedTurnContext(input, descriptor);
18767
+ return { kind: "context", text };
18399
18768
  }
18400
18769
  case "context.turn": {
18401
18770
  if (!usable2(descriptor.context.perTurn))
18402
18771
  return NONE4;
18403
- const text = turnContextText(input, descriptor);
18404
- return text ? { kind: "context", text } : NONE4;
18772
+ const current = turnContextText(input, descriptor);
18773
+ const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
18774
+ return withContextLine(text ? { kind: "context", text } : NONE4, promptNudge(input, event.prompt));
18405
18775
  }
18406
18776
  case "shell.pre": {
18777
+ const skillRead = skillReadIn(event.command, event.dialect);
18778
+ if (skillRead)
18779
+ recordSkillLoad(input, skillRead, "read");
18407
18780
  const canDeny = usable2(descriptor.shellPolicy.deny);
18408
18781
  const policy = canDeny ? shellPolicy(input.cwd, event.command) : NONE4;
18409
18782
  if (policy.kind !== "none")
@@ -18419,7 +18792,7 @@ function handleHook(input, deps) {
18419
18792
  if (gate.kind === "deny")
18420
18793
  return gate;
18421
18794
  noteRawCommit(input, event.command, postTool ? callKey(event.toolUseId, event.command) : NEXT_COMMAND);
18422
- return raw;
18795
+ return withContextLine(raw, shipNudge(input, event.command));
18423
18796
  }
18424
18797
  case "shell.post":
18425
18798
  if (usable2(descriptor.events["shell.post"].support))
@@ -18430,7 +18803,7 @@ function handleHook(input, deps) {
18430
18803
  case "subagent.start":
18431
18804
  return {
18432
18805
  kind: "context",
18433
- text: subagentStartText(input.host, input.session.id ?? null, descriptor, event)
18806
+ text: subagentStartText(input.session.id ?? null, descriptor, event)
18434
18807
  };
18435
18808
  case "compact.pre":
18436
18809
  return {
@@ -18438,6 +18811,9 @@ function handleHook(input, deps) {
18438
18811
  userMessage: "Workit context may be stale after compaction; re-run inspection or resume before acting."
18439
18812
  };
18440
18813
  case "tool.pre":
18814
+ if (event.skill)
18815
+ recordSkillLoad(input, event.skill, "tool");
18816
+ return NONE4;
18441
18817
  case "subagent.stop":
18442
18818
  case "prompt.submit":
18443
18819
  case "stop":
@@ -18488,24 +18864,26 @@ var CLAUDE_CODE_DESCRIPTOR = {
18488
18864
  "write.pre": { support: "native", native: "PreToolUse" },
18489
18865
  "shell.post": { support: "native", native: "PostToolUse" },
18490
18866
  "subagent.start": { support: "native", native: "SubagentStart" },
18491
- "subagent.stop": { support: "native", native: "SubagentStop" },
18492
18867
  "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18493
- "compact.pre": { support: "partial", native: "PreCompact" },
18494
- stop: { support: "native", native: "Stop" }
18868
+ "subagent.stop": { support: "none", native: null },
18869
+ "compact.pre": { support: "none", native: null },
18870
+ stop: { support: "none", native: null }
18495
18871
  },
18496
18872
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18497
18873
  context: {
18498
18874
  sessionStart: "native",
18499
18875
  perTurn: "native",
18500
18876
  afterCompact: "native",
18501
- task: "session-bound"
18877
+ task: "session-bound",
18878
+ turnResend: "every-turn"
18502
18879
  },
18503
18880
  subagents: {
18504
18881
  identity: "native",
18505
18882
  parentBinding: "partial",
18506
18883
  blockStart: "none",
18507
18884
  worktreeIsolation: "native",
18508
- maxConcurrency: "undocumented"
18885
+ maxConcurrency: "undocumented",
18886
+ agentPrefix: "workit:"
18509
18887
  },
18510
18888
  provenance: { sessionId: "native", agentIdOnTool: "native", postToolObserve: "native" },
18511
18889
  interaction: { questions: "undocumented", writeBoundary: "partial" },
@@ -18523,13 +18901,13 @@ var CLAUDE_CODE_DESCRIPTOR = {
18523
18901
  },
18524
18902
  {
18525
18903
  name: "native_subagents",
18526
- surface: "SubagentStart/SubagentStop",
18527
- refs: ["SubagentStart", "SubagentStop"],
18528
- requires: ["event:subagent.start", "event:subagent.stop"],
18529
- observed: ["subagent.start", "subagent.stop"],
18904
+ surface: "SubagentStart",
18905
+ refs: ["SubagentStart"],
18906
+ requires: ["event:subagent.start"],
18907
+ observed: ["subagent.start"],
18530
18908
  assurance: "agent_guided",
18531
18909
  reason: "Claude Code reports stable agent identities, but SubagentStart cannot block or bind",
18532
- unavailableReason: "Claude Code subagent lifecycle hooks are unavailable"
18910
+ unavailableReason: "Claude Code SubagentStart is unavailable"
18533
18911
  },
18534
18912
  {
18535
18913
  name: "fresh-context-review",
@@ -18580,7 +18958,7 @@ var eventOf = (name, value) => {
18580
18958
  case "SessionStart":
18581
18959
  return SOURCES.has(value.source) ? { ok: true, event: { kind: "session.start", source: value.source } } : { ok: false, error: "SessionStart source is required" };
18582
18960
  case "UserPromptSubmit":
18583
- return { ok: true, event: { kind: "context.turn" } };
18961
+ return { ok: true, event: { kind: "context.turn", prompt: optionalText(value.prompt) } };
18584
18962
  case "PreToolUse": {
18585
18963
  if (!nonEmpty2(value.tool_name))
18586
18964
  return { ok: false, error: "tool_name is required" };
@@ -18590,10 +18968,20 @@ var eventOf = (name, value) => {
18590
18968
  event: {
18591
18969
  kind: "write.pre",
18592
18970
  tool: value.tool_name,
18593
- paths: writePaths(value.tool_input),
18971
+ paths: writeTargets(value.tool_input),
18594
18972
  toolUseId
18595
18973
  }
18596
18974
  };
18975
+ if (value.tool_name === "Skill")
18976
+ return {
18977
+ ok: true,
18978
+ event: {
18979
+ kind: "tool.pre",
18980
+ tool: value.tool_name,
18981
+ toolUseId,
18982
+ skill: isRecord4(value.tool_input) ? optionalText(value.tool_input.skill) : null
18983
+ }
18984
+ };
18597
18985
  if (!SHELL_TOOLS.has(value.tool_name))
18598
18986
  return { ok: true, event: { kind: "tool.pre", tool: value.tool_name, toolUseId } };
18599
18987
  const command = toolCommand(value);
@@ -18728,39 +19116,40 @@ var claudeCodeAdapter = {
18728
19116
  function detectCodexSurface(env) {
18729
19117
  return env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || Boolean(env.CODEX_ELECTRON_RESOURCES_PATH) ? "codex_desktop" : "codex_cli";
18730
19118
  }
18731
- var undocumented = { support: "undocumented", native: null };
18732
19119
  var CODEX_DESCRIPTOR = {
18733
19120
  host: "codex_cli",
18734
19121
  label: "Codex",
18735
- verifiedAgainst: "codex-cli 0.153.4; Codex Desktop 26.901.20858",
19122
+ verifiedAgainst: "codex-cli 0.160.1 (hook JSON schemas in the binary); Codex Desktop 26.901.20858",
18736
19123
  docs: ["https://developers.openai.com/codex/hooks"],
18737
19124
  transport: "hook-process",
18738
19125
  events: {
18739
19126
  "session.start": { support: "native", native: "SessionStart" },
18740
- "context.turn": undocumented,
19127
+ "context.turn": { support: "native", native: "UserPromptSubmit" },
18741
19128
  "shell.pre": { support: "native", native: "PreToolUse" },
18742
19129
  "tool.pre": { support: "native", native: "PreToolUse" },
18743
- "write.pre": { support: "undocumented", native: null },
19130
+ "write.pre": { support: "native", native: "PreToolUse" },
18744
19131
  "shell.post": { support: "native", native: "PostToolUse" },
18745
19132
  "subagent.start": { support: "native", native: "SubagentStart" },
18746
19133
  "subagent.stop": { support: "native", native: "SubagentStop" },
18747
- "prompt.submit": undocumented,
19134
+ "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18748
19135
  "compact.pre": { support: "none", native: null },
18749
- stop: undocumented
19136
+ stop: { support: "none", native: null }
18750
19137
  },
18751
19138
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18752
19139
  context: {
18753
19140
  sessionStart: "native",
18754
- perTurn: "undocumented",
19141
+ perTurn: "native",
18755
19142
  afterCompact: "native",
18756
- task: "single-active"
19143
+ task: "single-active",
19144
+ turnResend: "on-change"
18757
19145
  },
18758
19146
  subagents: {
18759
19147
  identity: "native",
18760
19148
  parentBinding: "none",
18761
19149
  blockStart: "none",
18762
19150
  worktreeIsolation: "undocumented",
18763
- maxConcurrency: "undocumented"
19151
+ maxConcurrency: "undocumented",
19152
+ agentPrefix: "workit-"
18764
19153
  },
18765
19154
  provenance: { sessionId: "native", agentIdOnTool: "partial", postToolObserve: "native" },
18766
19155
  interaction: { questions: "none", writeBoundary: "partial" },
@@ -18827,6 +19216,7 @@ var CODEX_DESCRIPTOR = {
18827
19216
  };
18828
19217
  var EVENTS2 = {
18829
19218
  SessionStart: "session.start",
19219
+ UserPromptSubmit: "context.turn",
18830
19220
  PreToolUse: "shell.pre",
18831
19221
  PostToolUse: "shell.post",
18832
19222
  SubagentStart: "subagent.start",
@@ -18834,7 +19224,7 @@ var EVENTS2 = {
18834
19224
  };
18835
19225
  var SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
18836
19226
  var isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase());
18837
- var SOURCES2 = new Set(["startup", "resume", "clear", "compact"]);
19227
+ var SOURCES2 = new Set(["startup", "resume", "clear", "compact", "fork"]);
18838
19228
  var parseCodexHookInput = (value) => {
18839
19229
  if (!isRecord4(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
18840
19230
  return { ok: false, error: "hook_event_name is required" };
@@ -18861,6 +19251,7 @@ var parseCodexHookInput = (value) => {
18861
19251
  cwd,
18862
19252
  ...event === "SessionStart" ? { source: SOURCES2.has(String(value.source)) ? value.source : "resume" } : {},
18863
19253
  ...nonEmpty2(value.turn_id) ? { turn_id: value.turn_id } : {},
19254
+ ...event === "UserPromptSubmit" ? { prompt: optionalText(value.prompt) } : {},
18864
19255
  ...nonEmpty2(value.tool_name) ? { tool_name: value.tool_name } : {},
18865
19256
  ...toolEvent ? { tool_input: value.tool_input } : {},
18866
19257
  ...event === "PostToolUse" && typeof value.tool_response === "string" ? { tool_response: value.tool_response } : {},
@@ -18880,13 +19271,20 @@ var protocolEvent = (input) => {
18880
19271
  switch (input.hook_event_name) {
18881
19272
  case "SessionStart":
18882
19273
  return { kind: "session.start", source: input.source };
19274
+ case "UserPromptSubmit":
19275
+ return { kind: "context.turn", prompt: input.prompt ?? null };
18883
19276
  case "PreToolUse": {
18884
19277
  const toolUseId = input.tool_use_id ?? null;
18885
- return isShellTool(input.tool_name) ? {
18886
- kind: "shell.pre",
18887
- command: input.command ?? "",
18888
- toolUseId
18889
- } : { kind: "tool.pre", tool: input.tool_name, toolUseId };
19278
+ if (isShellTool(input.tool_name))
19279
+ return { kind: "shell.pre", command: input.command ?? "", toolUseId };
19280
+ if (isWriteTool(input.tool_name))
19281
+ return {
19282
+ kind: "write.pre",
19283
+ tool: input.tool_name,
19284
+ paths: writeTargets(input.tool_input),
19285
+ toolUseId
19286
+ };
19287
+ return { kind: "tool.pre", tool: input.tool_name, toolUseId };
18890
19288
  }
18891
19289
  case "PostToolUse": {
18892
19290
  const toolUseId = input.tool_use_id ?? null;
@@ -18962,12 +19360,12 @@ var codexAdapter = {
18962
19360
  };
18963
19361
  },
18964
19362
  render: render2,
18965
- addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under a session the lead assigns (WORKIT_HOST=codex_cli WORKIT_SESSION_ID=<lead>-v<n>), never the author's. Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
19363
+ addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under its own session, never the author's: a workit-verifier or workit-reviewer agent uses the --session its SubagentStart context names; any other uses one the lead assigns (WORKIT_HOST=codex_cli WORKIT_SESSION_ID=<lead>-v<n>). Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
18966
19364
  };
18967
19365
 
18968
19366
  // packages/workit-core/src/hooks/hosts/cursor.ts
18969
- import path20 from "node:path";
18970
- var undocumented2 = { support: "undocumented", native: null };
19367
+ import path21 from "node:path";
19368
+ var undocumented = { support: "undocumented", native: null };
18971
19369
  var none = { support: "none", native: null };
18972
19370
  var CURSOR_DESCRIPTOR = {
18973
19371
  host: "cursor",
@@ -18981,26 +19379,28 @@ var CURSOR_DESCRIPTOR = {
18981
19379
  "shell.pre": { support: "native", native: "beforeShellExecution" },
18982
19380
  "tool.pre": { support: "native", native: "preToolUse" },
18983
19381
  "write.pre": { support: "partial", native: "preToolUse" },
18984
- "shell.post": undocumented2,
19382
+ "shell.post": undocumented,
18985
19383
  "subagent.start": { support: "native", native: "subagentStart" },
18986
19384
  "subagent.stop": { support: "partial", native: "subagentStop" },
18987
- "prompt.submit": undocumented2,
19385
+ "prompt.submit": undocumented,
18988
19386
  "compact.pre": { support: "partial", native: "preCompact" },
18989
- stop: undocumented2
19387
+ stop: none
18990
19388
  },
18991
19389
  shellPolicy: { deny: "native", channel: "exit2+json", failClosed: true },
18992
19390
  context: {
18993
19391
  sessionStart: "native",
18994
19392
  perTurn: "none",
18995
19393
  afterCompact: "partial",
18996
- task: "single-active"
19394
+ task: "single-active",
19395
+ turnResend: "every-turn"
18997
19396
  },
18998
19397
  subagents: {
18999
19398
  identity: "native",
19000
19399
  parentBinding: "native",
19001
19400
  blockStart: "native",
19002
19401
  worktreeIsolation: "undocumented",
19003
- maxConcurrency: "undocumented"
19402
+ maxConcurrency: "undocumented",
19403
+ agentPrefix: "workit-"
19004
19404
  },
19005
19405
  provenance: {
19006
19406
  sessionId: "native",
@@ -19125,7 +19525,7 @@ var protocolEvent2 = (input) => {
19125
19525
  return isWriteTool(input.tool_name) ? {
19126
19526
  kind: "write.pre",
19127
19527
  tool: input.tool_name ?? "",
19128
- paths: writePaths(input.tool_input),
19528
+ paths: writeTargets(input.tool_input),
19129
19529
  toolUseId: null
19130
19530
  } : { kind: "tool.pre", tool: input.tool_name ?? "", toolUseId: null };
19131
19531
  case "subagentStart":
@@ -19147,7 +19547,7 @@ var protocolEvent2 = (input) => {
19147
19547
  return { kind: "compact.pre", trigger: "auto" };
19148
19548
  }
19149
19549
  };
19150
- var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path20.sep) ? root : `${root}${path20.sep}`);
19550
+ var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path21.sep) ? root : `${root}${path21.sep}`);
19151
19551
  var hookCwd = (input) => {
19152
19552
  const cwd = existingDirectory(input.cwd);
19153
19553
  if (cwd && input.hook_event_name === "beforeShellExecution")