@brainervirus/workit-cursor 8.4.1 → 8.5.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.
@@ -17240,6 +17240,8 @@ var support = (descriptor, axis) => {
17240
17240
  });
17241
17241
 
17242
17242
  // packages/workit-core/src/hooks/context.ts
17243
+ import { createHash as createHash10 } from "node:crypto";
17244
+ import fs13 from "node:fs";
17243
17245
  import path16 from "node:path";
17244
17246
  function sessionCompactContext(store, session, context, selection = "session-bound") {
17245
17247
  const listed = store.listTaskIndex();
@@ -17368,9 +17370,71 @@ ${options.addendum}` : ""}
17368
17370
  } catch {
17369
17371
  return null;
17370
17372
  }
17373
+ }, TURN_TTL_MS, digestOf = (text) => createHash10("sha256").update(text).digest("hex"), turnMarker = (input) => {
17374
+ if (!input.session.id)
17375
+ return null;
17376
+ try {
17377
+ const location = resolveStore(input.cwd);
17378
+ if (location instanceof Error)
17379
+ return null;
17380
+ const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
17381
+ return path16.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
17382
+ } catch {
17383
+ return null;
17384
+ }
17385
+ }, writeTurnDigest = (file, digest) => {
17386
+ try {
17387
+ fs13.mkdirSync(path16.dirname(file), { recursive: true });
17388
+ fs13.writeFileSync(file, `${JSON.stringify({ digest })}
17389
+ `);
17390
+ } catch {}
17391
+ }, clearTurnDigest = (file) => {
17392
+ try {
17393
+ fs13.rmSync(file, { force: true });
17394
+ } catch {}
17395
+ }, pruneTurnDigests = (dir, now) => {
17396
+ try {
17397
+ for (const name of fs13.readdirSync(dir)) {
17398
+ if (!name.startsWith("turn-"))
17399
+ continue;
17400
+ const file = path16.join(dir, name);
17401
+ try {
17402
+ if (now - fs13.statSync(file).mtimeMs > TURN_TTL_MS)
17403
+ fs13.rmSync(file, { force: true });
17404
+ } catch {}
17405
+ }
17406
+ } catch {}
17407
+ }, changedTurnContext = (input, text) => {
17408
+ const file = turnMarker(input);
17409
+ if (!text) {
17410
+ if (file)
17411
+ clearTurnDigest(file);
17412
+ return null;
17413
+ }
17414
+ if (!file)
17415
+ return text;
17416
+ const digest = digestOf(text);
17417
+ try {
17418
+ const previous = JSON.parse(fs13.readFileSync(file, "utf8"));
17419
+ if (previous.digest === digest)
17420
+ return null;
17421
+ } catch {}
17422
+ writeTurnDigest(file, digest);
17423
+ return text;
17424
+ }, seedTurnContext = (input, descriptor) => {
17425
+ const file = turnMarker(input);
17426
+ if (!file)
17427
+ return;
17428
+ pruneTurnDigests(path16.dirname(file), Date.now());
17429
+ const text = turnContextText(input, descriptor);
17430
+ if (text)
17431
+ writeTurnDigest(file, digestOf(text));
17432
+ else
17433
+ clearTurnDigest(file);
17371
17434
  };
17372
17435
  var init_context = __esm(() => {
17373
17436
  init_methods();
17437
+ init_paths();
17374
17438
  init_task_contract();
17375
17439
  init_task_evaluation();
17376
17440
  init_rev();
@@ -17378,6 +17442,7 @@ var init_context = __esm(() => {
17378
17442
  init_task_store();
17379
17443
  signals = new Map;
17380
17444
  cache = new Map;
17445
+ TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
17381
17446
  });
17382
17447
 
17383
17448
  // packages/workit-core/src/core/commit-flavors.ts
@@ -17387,7 +17452,7 @@ var init_commit_flavors = () => {};
17387
17452
  var init_git = () => {};
17388
17453
 
17389
17454
  // packages/workit-core/src/core/branch.ts
17390
- import { createHash as createHash10 } from "node:crypto";
17455
+ import { createHash as createHash11 } from "node:crypto";
17391
17456
  function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
17392
17457
  const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
17393
17458
  const config = readConfig();
@@ -17453,7 +17518,7 @@ var withReleaseTracks = (workspaceRoot, policy) => {
17453
17518
  const source = resolved.provenance.branchPolicy;
17454
17519
  const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
17455
17520
  const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
17456
- const fingerprint = createHash10("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17521
+ const fingerprint = createHash11("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
17457
17522
  return {
17458
17523
  branchPolicy,
17459
17524
  namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
@@ -17642,7 +17707,7 @@ function writeGate(cwd, paths) {
17642
17707
  const gate = gateFor(cwd);
17643
17708
  if (!gate || gate.blockers.length === 0)
17644
17709
  return NONE2;
17645
- if (paths && paths.every((file) => exempt(cwd, gate.root, file, gate.plans)))
17710
+ if (paths?.length && paths.every((file) => exempt(cwd, gate.root, file, gate.plans)))
17646
17711
  return NONE2;
17647
17712
  const reasons = gate.blockers.map((item) => `${item.ruleId}: ${item.reason}`).join("; ");
17648
17713
  return {
@@ -17812,8 +17877,8 @@ var init_write_gate = __esm(() => {
17812
17877
 
17813
17878
  // packages/workit-core/src/hooks/raw-git.ts
17814
17879
  import { spawnSync as spawnSync11 } from "node:child_process";
17815
- import { createHash as createHash11 } from "node:crypto";
17816
- import fs13 from "node:fs";
17880
+ import { createHash as createHash12 } from "node:crypto";
17881
+ import fs14 from "node:fs";
17817
17882
  import os4 from "node:os";
17818
17883
  import path18 from "node:path";
17819
17884
  function rawInvocations(command, dialect = "posix", depth = 0) {
@@ -17938,8 +18003,8 @@ function noteRawCommit(input, command, key) {
17938
18003
  if (action.kind !== "commit")
17939
18004
  continue;
17940
18005
  const file = markerFile(repo, input.session.id, key);
17941
- fs13.mkdirSync(path18.dirname(file), { recursive: true });
17942
- fs13.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
18006
+ fs14.mkdirSync(path18.dirname(file), { recursive: true });
18007
+ fs14.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
17943
18008
  `);
17944
18009
  }
17945
18010
  } catch {}
@@ -17961,7 +18026,7 @@ function settlePendingCommit(input) {
17961
18026
  if (!repo)
17962
18027
  return;
17963
18028
  const file = markerFile(repo, input.session.id, NEXT_COMMAND);
17964
- if (fs13.existsSync(file))
18029
+ if (fs14.existsSync(file))
17965
18030
  settle2(input, repo, file);
17966
18031
  } catch {}
17967
18032
  }
@@ -18067,7 +18132,7 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
18067
18132
  return null;
18068
18133
  return { location, dir, branch: resolveTaskKey(dir, location).branch };
18069
18134
  }, isWorkitWorkspace = (repo) => {
18070
- if (fs13.existsSync(repo.location.dir))
18135
+ if (fs14.existsSync(repo.location.dir))
18071
18136
  return true;
18072
18137
  try {
18073
18138
  return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
@@ -18095,7 +18160,7 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
18095
18160
  if (!git || git.reftable)
18096
18161
  return null;
18097
18162
  try {
18098
- const head = fs13.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
18163
+ const head = fs14.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
18099
18164
  if (/^[0-9a-f]{40,64}$/.test(head))
18100
18165
  return head;
18101
18166
  const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
@@ -18103,9 +18168,9 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
18103
18168
  return null;
18104
18169
  const common = path18.dirname(repo.location.dir);
18105
18170
  try {
18106
- return fs13.readFileSync(path18.join(common, ref), "utf8").trim() || null;
18171
+ return fs14.readFileSync(path18.join(common, ref), "utf8").trim() || null;
18107
18172
  } catch {}
18108
- const packed = fs13.readFileSync(path18.join(common, "packed-refs"), "utf8");
18173
+ const packed = fs14.readFileSync(path18.join(common, "packed-refs"), "utf8");
18109
18174
  return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
18110
18175
  } catch {
18111
18176
  return null;
@@ -18148,7 +18213,10 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
18148
18213
  out.push({ action, repo });
18149
18214
  }
18150
18215
  return out;
18151
- }, mentionsRawTool = (command) => /\b(?:git|gh|glab)\b/i.test(command), dialectOf = (input) => (input.event.kind === "shell.pre" || input.event.kind === "shell.post" ? input.event.dialect : undefined) ?? "posix", deny = (reason) => ({ kind: "deny", reason, unblock: null }), NEXT_COMMAND = "next", MARKER_TTL_SECONDS = 3600, markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash11("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`), callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash11("sha256").update(command).digest("hex")}`, headCommit = (dir) => {
18216
+ }, inWorkitWorkspace = (dir) => {
18217
+ const repo = repoAt(dir);
18218
+ return repo !== null && isWorkitWorkspace(repo);
18219
+ }, rawDelivery = (cwd, command, dialect) => mentionsRawTool(command) && actionsIn(cwd, command, dialect).some(({ action }) => action.kind !== "commit" && action.kind !== "pr-read"), mentionsRawTool = (command) => /\b(?:git|gh|glab)\b/i.test(command), dialectOf = (input) => (input.event.kind === "shell.pre" || input.event.kind === "shell.post" ? input.event.dialect : undefined) ?? "posix", deny = (reason) => ({ kind: "deny", reason, unblock: null }), NEXT_COMMAND = "next", MARKER_TTL_SECONDS = 3600, markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash12("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`), callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash12("sha256").update(command).digest("hex")}`, headCommit = (dir) => {
18152
18220
  const run = spawnSync11("git", [
18153
18221
  "log",
18154
18222
  "-1",
@@ -18165,11 +18233,11 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
18165
18233
  }, settle2 = (input, repo, file) => {
18166
18234
  let marker;
18167
18235
  try {
18168
- marker = JSON.parse(fs13.readFileSync(file, "utf8"));
18236
+ marker = JSON.parse(fs14.readFileSync(file, "utf8"));
18169
18237
  } catch {
18170
18238
  return;
18171
18239
  }
18172
- fs13.rmSync(file, { force: true });
18240
+ fs14.rmSync(file, { force: true });
18173
18241
  const session = input.session.id;
18174
18242
  const now = Date.now() / 1000;
18175
18243
  if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
@@ -18253,18 +18321,291 @@ var init_raw_git = __esm(() => {
18253
18321
  };
18254
18322
  });
18255
18323
 
18324
+ // packages/workit-core/src/core/skill-manifests.ts
18325
+ var WORKIT_METHOD_SKILLS, WORKIT_SKILL_ALIASES, skillLoadWording = (host, skill) => {
18326
+ switch (host) {
18327
+ case "claude-code":
18328
+ return `call the Skill tool with \`workit:${skill.replace(/^workit-/, "")}\``;
18329
+ case "opencode":
18330
+ return `call the skill tool with \`${skill}\``;
18331
+ default:
18332
+ return `read the \`${skill}\` skill's SKILL.md and follow it`;
18333
+ }
18334
+ };
18335
+ var init_skill_manifests = __esm(() => {
18336
+ WORKIT_METHOD_SKILLS = [
18337
+ "workit-shape",
18338
+ "workit-implement",
18339
+ "workit-review",
18340
+ "workit-debug",
18341
+ "workit-ship",
18342
+ "workit-continue",
18343
+ "workit-bdd",
18344
+ "workit-test-audit",
18345
+ "workit-deslop",
18346
+ "workit-fanout",
18347
+ "workit-verify-app",
18348
+ "workit-retro",
18349
+ "workit-architecture"
18350
+ ];
18351
+ WORKIT_SKILL_ALIASES = {
18352
+ "wk-shape": "workit-shape",
18353
+ "wk-implement": "workit-implement",
18354
+ "wk-review": "workit-review",
18355
+ "wk-debug": "workit-debug",
18356
+ "wk-ship": "workit-ship",
18357
+ "wk-continue": "workit-continue",
18358
+ "wk-bdd": "workit-bdd",
18359
+ "wk-test-audit": "workit-test-audit",
18360
+ "wk-deslop": "workit-deslop",
18361
+ "wk-fanout": "workit-fanout",
18362
+ "wk-verify-app": "workit-verify-app",
18363
+ "wk-retro": "workit-retro",
18364
+ "wk-architecture": "workit-architecture"
18365
+ };
18366
+ if (false) {}
18367
+ });
18368
+
18369
+ // packages/workit-core/src/hooks/skill-nudge.ts
18370
+ import { createHash as createHash13 } from "node:crypto";
18371
+ import fs15 from "node:fs";
18372
+ import path19 from "node:path";
18373
+ function recordSkillLoad(input, name, via) {
18374
+ try {
18375
+ const skill = workitSkillOf(name);
18376
+ const session = input.session.id;
18377
+ if (!skill || !session)
18378
+ return;
18379
+ if (!inWorkitWorkspace(input.cwd))
18380
+ return;
18381
+ const file = markerFile2(input, session);
18382
+ if (!file)
18383
+ return;
18384
+ const marker = readMarker(file);
18385
+ if (marker.loaded.includes(skill))
18386
+ return;
18387
+ writeMarker(file, { ...marker, loaded: [...marker.loaded, skill] });
18388
+ if (loadedSkills(input.cwd, session).has(skill))
18389
+ return;
18390
+ appendHookObserved(input.cwd, {
18391
+ type: "skill.loaded",
18392
+ actor: { host: input.host, session, agentId: input.session.agentId },
18393
+ skill,
18394
+ via
18395
+ });
18396
+ } catch {}
18397
+ }
18398
+ function promptNudge(input, prompt) {
18399
+ try {
18400
+ const session = input.session.id;
18401
+ if (!prompt || !session || input.session.agentId)
18402
+ return null;
18403
+ const loads = promptLoads(prompt);
18404
+ if (loads) {
18405
+ recordSkillLoad(input, loads, "slash");
18406
+ return null;
18407
+ }
18408
+ const hit = promptTrigger(prompt);
18409
+ if (!hit || !inWorkitWorkspace(input.cwd))
18410
+ return null;
18411
+ return nudgeOnce(input, session, hit.skill, nudgeText(input, hit.skill, `this request ("${hit.trigger}")`));
18412
+ } catch {
18413
+ return null;
18414
+ }
18415
+ }
18416
+ function shipNudge(input, command) {
18417
+ try {
18418
+ const session = input.session.id;
18419
+ if (!session || input.session.agentId)
18420
+ return null;
18421
+ const dialect = input.event.kind === "shell.pre" ? input.event.dialect ?? "posix" : "posix";
18422
+ if (!isDeliveryCommand(input.cwd, command, dialect))
18423
+ return null;
18424
+ return nudgeOnce(input, session, "workit-ship", nudgeText(input, "workit-ship", "this delivery step"));
18425
+ } catch {
18426
+ return null;
18427
+ }
18428
+ }
18429
+ var USER_INVOKED, SKILL_HOST, PROMPT_INTENTS, workitSkillOf = (name) => {
18430
+ const bare = name.trim().replace(/^\//, "").toLowerCase();
18431
+ const alias = WORKIT_SKILL_ALIASES[bare];
18432
+ if (alias)
18433
+ return alias;
18434
+ const skill = bare.replace(/^workit:/, "workit-");
18435
+ return WORKIT_METHOD_SKILLS.includes(skill) ? skill : null;
18436
+ }, promptTrigger = (prompt) => {
18437
+ const text = prompt.replace(/```[\s\S]*?```/g, " ").slice(0, 4000);
18438
+ for (const [skill, pattern] of PROMPT_INTENTS) {
18439
+ const match = pattern.exec(text);
18440
+ if (match)
18441
+ return { skill, trigger: match[1] ?? match[0] };
18442
+ }
18443
+ return null;
18444
+ }, markerFile2 = (input, session) => {
18445
+ const location = resolveStore(input.cwd);
18446
+ if (location instanceof Error || !location.shared)
18447
+ return null;
18448
+ const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18449
+ return path19.join(location.dir, "hooks", `skills-${name}.json`);
18450
+ }, readMarker = (file) => {
18451
+ try {
18452
+ const value = JSON.parse(fs15.readFileSync(file, "utf8"));
18453
+ return { nudged: value.nudged ?? [], loaded: value.loaded ?? [] };
18454
+ } catch {
18455
+ return { nudged: [], loaded: [] };
18456
+ }
18457
+ }, writeMarker = (file, marker) => {
18458
+ try {
18459
+ fs15.mkdirSync(path19.dirname(file), { recursive: true });
18460
+ fs15.writeFileSync(file, JSON.stringify(marker));
18461
+ } catch {}
18462
+ }, loadedSkills = (cwd, session) => {
18463
+ const ledger = readLedger(cwd);
18464
+ const loaded = new Set;
18465
+ if (!ledger.ok)
18466
+ return loaded;
18467
+ for (const row of ledger.value.rows)
18468
+ if (row.type === "skill.loaded" && row.actor.session === session && typeof row.skill === "string")
18469
+ loaded.add(row.skill);
18470
+ return loaded;
18471
+ }, SKILL_FILE, skillFileIn = (file) => SKILL_FILE.exec(file)?.[1] ?? null, READERS, skillReadIn = (command, dialect = "posix") => {
18472
+ for (const { words } of segmentsOf(command, dialect)) {
18473
+ if (!READERS.has((words[0]?.split(/[\\/]/).at(-1) ?? "").toLowerCase()))
18474
+ continue;
18475
+ if (words.some((word) => /^(?:-i(?:\.\w+)?|--in-place(?:=.*)?)$/.test(word)))
18476
+ continue;
18477
+ for (const word of words.slice(1)) {
18478
+ const skill = skillFileIn(word);
18479
+ if (skill)
18480
+ return skill;
18481
+ }
18482
+ }
18483
+ return null;
18484
+ }, nudgeOnce = (input, session, skill, line) => {
18485
+ const file = markerFile2(input, session);
18486
+ if (!file)
18487
+ return null;
18488
+ const marker = readMarker(file);
18489
+ if (marker.nudged.includes(skill) || marker.loaded.includes(skill))
18490
+ return null;
18491
+ if (loadedSkills(input.cwd, session).has(skill))
18492
+ return null;
18493
+ writeMarker(file, { ...marker, nudged: [...marker.nudged, skill] });
18494
+ return line;
18495
+ }, 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.`, 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, WORKIT_DELIVERY, SHELLS2, LAUNCHERS, runsWorkitDelivery = (command, dialect, depth = 0) => segmentsOf(command, dialect).some(({ words }) => {
18496
+ const at = words.findIndex((word) => !/^\w+=/.test(word) && !LAUNCHERS.has(word));
18497
+ if (at >= 0 && /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/.test(words[at])) {
18498
+ const args = words.slice(at + 1);
18499
+ if (args.some((arg) => arg === "--help" || arg === "-h" || arg === "--dry-run"))
18500
+ return false;
18501
+ return WORKIT_DELIVERY.test(args.join(" "));
18502
+ }
18503
+ const shell = SHELLS2.has(words[at]?.split(/[\\/]/).at(-1) ?? "");
18504
+ const script = shell && words[at + 1] === "-c" ? words[at + 2] : undefined;
18505
+ return depth < 3 && script !== undefined && runsWorkitDelivery(script, "posix", depth + 1);
18506
+ }), isDeliveryCommand = (cwd, command, dialect = "posix") => rawDelivery(cwd, command, dialect) || runsWorkitDelivery(command, dialect) && inWorkitWorkspace(cwd), withContextLine = (decision, line) => {
18507
+ if (!line)
18508
+ return decision;
18509
+ if (decision.kind === "none")
18510
+ return { kind: "context", text: line };
18511
+ if (decision.kind === "context")
18512
+ return { kind: "context", text: `${decision.text}
18513
+ ${line}` };
18514
+ return decision;
18515
+ };
18516
+ var init_skill_nudge = __esm(() => {
18517
+ init_skill_manifests();
18518
+ init_ledger();
18519
+ init_paths();
18520
+ init_raw_git();
18521
+ USER_INVOKED = new Set(["workit-retro", "workit-architecture"]);
18522
+ SKILL_HOST = {
18523
+ claude_code: "claude-code",
18524
+ opencode: "opencode",
18525
+ codex_cli: "codex",
18526
+ codex_desktop: "codex",
18527
+ cursor: "cursor",
18528
+ pi: "pi"
18529
+ };
18530
+ PROMPT_INTENTS = [
18531
+ [
18532
+ "workit-debug",
18533
+ /\b(flaky|regressed|(?:is|introduced) a regression|regression (?:in|after|since|from)|(?:is|are|got|looks) broken|debug (?:this|it|the|why)|fix (?:the|this|a) bug)\b/i
18534
+ ],
18535
+ [
18536
+ "workit-continue",
18537
+ /\b(pick up where|where (?:were|did) we|resume (?:the|this|my|our|work|where)|hand ?off)\b/i
18538
+ ],
18539
+ [
18540
+ "workit-review",
18541
+ /\b(blast radius|code review|review (?:the|this|my|PR|pr|#\d+|branch|diff|changes))\b/i
18542
+ ],
18543
+ [
18544
+ "workit-ship",
18545
+ /\b(ship (?:it|this|the)|babysit|open (?:a|the) (?:PR|pr|MR|mr)(?=\s*$|\s+(?:for|to|on|with|and|against|into|from|after|once)\b|[.!,;])|merge (?:the|this|my) (?:PR|pr|MR|mr|branch)|(?:get|until|make) CI (?:is )?green)\b/i
18546
+ ],
18547
+ ["workit-bdd", /\b(BDD|TDD|acceptance criteria|Given\/When\/Then)(?![\w/])/],
18548
+ ["workit-test-audit", /\b(test audit|audit the tests|tautolog\w*|weak tests)\b/i],
18549
+ ["workit-deslop", /\b(deslop|slop|dead code)\b/i],
18550
+ [
18551
+ "workit-fanout",
18552
+ /\b(fan(?: |-)?out|parallelize|parallel agents|agent swarm|swarm of agents)\b/i
18553
+ ],
18554
+ ["workit-verify-app", /\b(verify the app|smoke test|prove it works)\b/i],
18555
+ ["workit-retro", /\b((?:a|the) retro(?![-\w]|\.\w)|retrospective)/i],
18556
+ ["workit-architecture", /\b(deepen (?:the )?modules|architecture (?:review|pass|audit))\b/i],
18557
+ [
18558
+ "workit-shape",
18559
+ /\b(brainstorm\w*|grill me|should we|let'?s plan|plan (?:out|how|the|a|for)|(?:write|draft) (?:a|the) spec)\b/i
18560
+ ],
18561
+ [
18562
+ "workit-implement",
18563
+ /\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
18564
+ ]
18565
+ ];
18566
+ SKILL_FILE = /(?:^|[\\/])(workit-[a-z-]+)[\\/]SKILL\.md$/;
18567
+ READERS = new Set([
18568
+ "cat",
18569
+ "sed",
18570
+ "head",
18571
+ "tail",
18572
+ "less",
18573
+ "more",
18574
+ "bat",
18575
+ "nl",
18576
+ "get-content",
18577
+ "gc",
18578
+ "type"
18579
+ ]);
18580
+ WORKIT_DELIVERY = /^(?:pr (?:create|merge)|ci wait|git push)\b/;
18581
+ SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
18582
+ LAUNCHERS = new Set([
18583
+ "npx",
18584
+ "bunx",
18585
+ "pnpx",
18586
+ "-y",
18587
+ "--yes",
18588
+ "pnpm",
18589
+ "dlx",
18590
+ "exec",
18591
+ "env",
18592
+ "sudo",
18593
+ "command"
18594
+ ]);
18595
+ });
18596
+
18256
18597
  // packages/workit-core/src/hooks/hosts/fields.ts
18257
18598
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
18258
- import path19 from "node:path";
18599
+ import path20 from "node:path";
18259
18600
  var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "", optionalText = (value) => typeof value === "string" ? value : null, existingDirectory = (value) => {
18260
- if (!nonEmpty2(value) || !path19.isAbsolute(value) || !existsSync6(value))
18601
+ if (!nonEmpty2(value) || !path20.isAbsolute(value) || !existsSync6(value))
18261
18602
  return null;
18262
18603
  try {
18263
18604
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
18264
18605
  } catch {
18265
18606
  return null;
18266
18607
  }
18267
- }, SHELLS2, SCRIPT_FLAG2, quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg), commandText = (value) => {
18608
+ }, SHELLS3, SCRIPT_FLAG2, quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg), commandText = (value) => {
18268
18609
  if (nonEmpty2(value))
18269
18610
  return value;
18270
18611
  if (!Array.isArray(value) || value.length === 0)
@@ -18273,7 +18614,7 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
18273
18614
  if (!argv.every((arg) => typeof arg === "string"))
18274
18615
  return null;
18275
18616
  const shell = argv[0].split(/[\\/]/).at(-1)?.replace(/\.exe$/i, "").toLowerCase() ?? "";
18276
- if (SHELLS2.has(shell))
18617
+ if (SHELLS3.has(shell))
18277
18618
  for (let index = 1;index < argv.length - 1; index++) {
18278
18619
  if (SCRIPT_FLAG2.test(argv[index]))
18279
18620
  return nonEmpty2(argv[index + 1]) ? argv[index + 1] : null;
@@ -18282,18 +18623,21 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
18282
18623
  }
18283
18624
  const joined = argv.map(quoteArg).join(" ");
18284
18625
  return nonEmpty2(joined) ? joined : null;
18285
- }, WRITE_TOOLS, isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, "")), PATH_KEYS, writePaths = (input) => {
18626
+ }, WRITE_TOOLS, isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, "")), PATH_KEYS, PATCH_HEADER, writePaths = (input) => {
18286
18627
  if (!isRecord4(input))
18287
18628
  return [];
18288
18629
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
18289
18630
  for (const value of Object.values(input))
18290
18631
  if (typeof value === "string")
18291
- for (const match of value.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm))
18632
+ for (const match of value.matchAll(PATCH_HEADER))
18292
18633
  paths.push(match[1].trim());
18293
18634
  return [...new Set(paths)];
18635
+ }, writeTargets = (input) => {
18636
+ const paths = writePaths(input);
18637
+ return paths.length > 0 ? paths : null;
18294
18638
  };
18295
18639
  var init_fields = __esm(() => {
18296
- SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18640
+ SHELLS3 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18297
18641
  SCRIPT_FLAG2 = /^(?:-\w*c|-command|\/c)$/i;
18298
18642
  WRITE_TOOLS = new Set([
18299
18643
  "write",
@@ -18315,6 +18659,7 @@ var init_fields = __esm(() => {
18315
18659
  "writefile"
18316
18660
  ]);
18317
18661
  PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
18662
+ PATCH_HEADER = /^[ \t]*\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+)$/gm;
18318
18663
  });
18319
18664
 
18320
18665
  // packages/workit-core/src/hooks/handle.ts
@@ -18332,18 +18677,22 @@ function handleHook(input, deps) {
18332
18677
  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.`;
18333
18678
  const addendum = [deps.addendum, advisory].filter(Boolean).join(`
18334
18679
  `) || null;
18335
- return {
18336
- kind: "context",
18337
- text: sessionContextText(input, descriptor, { offer, addendum })
18338
- };
18680
+ const text = sessionContextText(input, descriptor, { offer, addendum });
18681
+ if (resendsOnChange(descriptor))
18682
+ seedTurnContext(input, descriptor);
18683
+ return { kind: "context", text };
18339
18684
  }
18340
18685
  case "context.turn": {
18341
18686
  if (!usable2(descriptor.context.perTurn))
18342
18687
  return NONE4;
18343
- const text = turnContextText(input, descriptor);
18344
- return text ? { kind: "context", text } : NONE4;
18688
+ const current = turnContextText(input, descriptor);
18689
+ const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
18690
+ return withContextLine(text ? { kind: "context", text } : NONE4, promptNudge(input, event.prompt));
18345
18691
  }
18346
18692
  case "shell.pre": {
18693
+ const skillRead = skillReadIn(event.command, event.dialect);
18694
+ if (skillRead)
18695
+ recordSkillLoad(input, skillRead, "read");
18347
18696
  const canDeny = usable2(descriptor.shellPolicy.deny);
18348
18697
  const policy = canDeny ? shellPolicy(input.cwd, event.command) : NONE4;
18349
18698
  if (policy.kind !== "none")
@@ -18359,7 +18708,7 @@ function handleHook(input, deps) {
18359
18708
  if (gate.kind === "deny")
18360
18709
  return gate;
18361
18710
  noteRawCommit(input, event.command, postTool ? callKey(event.toolUseId, event.command) : NEXT_COMMAND);
18362
- return raw;
18711
+ return withContextLine(raw, shipNudge(input, event.command));
18363
18712
  }
18364
18713
  case "shell.post":
18365
18714
  if (usable2(descriptor.events["shell.post"].support))
@@ -18370,7 +18719,7 @@ function handleHook(input, deps) {
18370
18719
  case "subagent.start":
18371
18720
  return {
18372
18721
  kind: "context",
18373
- text: subagentStartText(input.host, input.session.id ?? null, descriptor, event)
18722
+ text: subagentStartText(input.session.id ?? null, descriptor, event)
18374
18723
  };
18375
18724
  case "compact.pre":
18376
18725
  return {
@@ -18378,19 +18727,31 @@ function handleHook(input, deps) {
18378
18727
  userMessage: "Workit context may be stale after compaction; re-run inspection or resume before acting."
18379
18728
  };
18380
18729
  case "tool.pre":
18730
+ if (event.skill)
18731
+ recordSkillLoad(input, event.skill, "tool");
18732
+ return NONE4;
18381
18733
  case "subagent.stop":
18382
18734
  case "prompt.submit":
18383
18735
  case "stop":
18384
18736
  return NONE4;
18385
18737
  }
18386
18738
  }
18387
- var usable2 = (value) => value === "native" || value === "partial", NONE4, offered, CLAUDE_WORKTREE_IMPLEMENTER = "workit:implementer", CLAUDE_JUDGES, subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), subagentStartText = (host, session, descriptor, event) => {
18388
- if (host === "claude_code" && event.agentType === CLAUDE_WORKTREE_IMPLEMENTER)
18389
- 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.`;
18390
- const readOnly = `Workit observed ${descriptor.label} subagent ${event.agentId} (${event.agentType}) as read-only/agent-guided.`;
18391
- if (host === "claude_code" && event.agentType && CLAUDE_JUDGES.has(event.agentType) && event.agentId)
18392
- 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.`;
18393
- return readOnly;
18739
+ var usable2 = (value) => value === "native" || value === "partial", NONE4, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, ROLES, workitRole = (descriptor, agentType) => {
18740
+ const prefix = descriptor.subagents.agentPrefix;
18741
+ const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
18742
+ return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
18743
+ }, subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), subagentStartText = (session, descriptor, event) => {
18744
+ const role = workitRole(descriptor, event.agentType);
18745
+ const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
18746
+ if (role === "implementer") {
18747
+ 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";
18748
+ 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.`;
18749
+ }
18750
+ const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
18751
+ if (role !== "judge" || !event.agentId)
18752
+ return readOnly;
18753
+ const own = subagentSession(session, event.agentId);
18754
+ 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.`;
18394
18755
  }, failureDecision = (descriptor, event, error) => {
18395
18756
  if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
18396
18757
  return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE4;
@@ -18423,10 +18784,15 @@ var init_handle = __esm(() => {
18423
18784
  init_context();
18424
18785
  init_policy();
18425
18786
  init_raw_git();
18787
+ init_skill_nudge();
18426
18788
  init_write_gate();
18427
18789
  NONE4 = { kind: "none" };
18428
18790
  offered = new Set;
18429
- CLAUDE_JUDGES = new Set(["workit:verifier", "workit:reviewer"]);
18791
+ ROLES = {
18792
+ implementer: "implementer",
18793
+ verifier: "judge",
18794
+ reviewer: "judge"
18795
+ };
18430
18796
  });
18431
18797
 
18432
18798
  // packages/workit-core/src/hooks/hosts/claude-code.ts
@@ -18436,7 +18802,7 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, dialectOf2 = (value) =
18436
18802
  case "SessionStart":
18437
18803
  return SOURCES.has(value.source) ? { ok: true, event: { kind: "session.start", source: value.source } } : { ok: false, error: "SessionStart source is required" };
18438
18804
  case "UserPromptSubmit":
18439
- return { ok: true, event: { kind: "context.turn" } };
18805
+ return { ok: true, event: { kind: "context.turn", prompt: optionalText(value.prompt) } };
18440
18806
  case "PreToolUse": {
18441
18807
  if (!nonEmpty2(value.tool_name))
18442
18808
  return { ok: false, error: "tool_name is required" };
@@ -18446,10 +18812,20 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, dialectOf2 = (value) =
18446
18812
  event: {
18447
18813
  kind: "write.pre",
18448
18814
  tool: value.tool_name,
18449
- paths: writePaths(value.tool_input),
18815
+ paths: writeTargets(value.tool_input),
18450
18816
  toolUseId
18451
18817
  }
18452
18818
  };
18819
+ if (value.tool_name === "Skill")
18820
+ return {
18821
+ ok: true,
18822
+ event: {
18823
+ kind: "tool.pre",
18824
+ tool: value.tool_name,
18825
+ toolUseId,
18826
+ skill: isRecord4(value.tool_input) ? optionalText(value.tool_input.skill) : null
18827
+ }
18828
+ };
18453
18829
  if (!SHELL_TOOLS.has(value.tool_name))
18454
18830
  return { ok: true, event: { kind: "tool.pre", tool: value.tool_name, toolUseId } };
18455
18831
  const command = toolCommand(value);
@@ -18547,24 +18923,26 @@ var init_claude_code = __esm(() => {
18547
18923
  "write.pre": { support: "native", native: "PreToolUse" },
18548
18924
  "shell.post": { support: "native", native: "PostToolUse" },
18549
18925
  "subagent.start": { support: "native", native: "SubagentStart" },
18550
- "subagent.stop": { support: "native", native: "SubagentStop" },
18551
18926
  "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18552
- "compact.pre": { support: "partial", native: "PreCompact" },
18553
- stop: { support: "native", native: "Stop" }
18927
+ "subagent.stop": { support: "none", native: null },
18928
+ "compact.pre": { support: "none", native: null },
18929
+ stop: { support: "none", native: null }
18554
18930
  },
18555
18931
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18556
18932
  context: {
18557
18933
  sessionStart: "native",
18558
18934
  perTurn: "native",
18559
18935
  afterCompact: "native",
18560
- task: "session-bound"
18936
+ task: "session-bound",
18937
+ turnResend: "every-turn"
18561
18938
  },
18562
18939
  subagents: {
18563
18940
  identity: "native",
18564
18941
  parentBinding: "partial",
18565
18942
  blockStart: "none",
18566
18943
  worktreeIsolation: "native",
18567
- maxConcurrency: "undocumented"
18944
+ maxConcurrency: "undocumented",
18945
+ agentPrefix: "workit:"
18568
18946
  },
18569
18947
  provenance: { sessionId: "native", agentIdOnTool: "native", postToolObserve: "native" },
18570
18948
  interaction: { questions: "undocumented", writeBoundary: "partial" },
@@ -18582,13 +18960,13 @@ var init_claude_code = __esm(() => {
18582
18960
  },
18583
18961
  {
18584
18962
  name: "native_subagents",
18585
- surface: "SubagentStart/SubagentStop",
18586
- refs: ["SubagentStart", "SubagentStop"],
18587
- requires: ["event:subagent.start", "event:subagent.stop"],
18588
- observed: ["subagent.start", "subagent.stop"],
18963
+ surface: "SubagentStart",
18964
+ refs: ["SubagentStart"],
18965
+ requires: ["event:subagent.start"],
18966
+ observed: ["subagent.start"],
18589
18967
  assurance: "agent_guided",
18590
18968
  reason: "Claude Code reports stable agent identities, but SubagentStart cannot block or bind",
18591
- unavailableReason: "Claude Code subagent lifecycle hooks are unavailable"
18969
+ unavailableReason: "Claude Code SubagentStart is unavailable"
18592
18970
  },
18593
18971
  {
18594
18972
  name: "fresh-context-review",
@@ -18684,7 +19062,7 @@ var init_claude_code = __esm(() => {
18684
19062
  function detectCodexSurface(env) {
18685
19063
  return env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || Boolean(env.CODEX_ELECTRON_RESOURCES_PATH) ? "codex_desktop" : "codex_cli";
18686
19064
  }
18687
- var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase()), SOURCES2, parseCodexHookInput = (value) => {
19065
+ var CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase()), SOURCES2, parseCodexHookInput = (value) => {
18688
19066
  if (!isRecord4(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
18689
19067
  return { ok: false, error: "hook_event_name is required" };
18690
19068
  const event = value.hook_event_name;
@@ -18710,6 +19088,7 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18710
19088
  cwd,
18711
19089
  ...event === "SessionStart" ? { source: SOURCES2.has(String(value.source)) ? value.source : "resume" } : {},
18712
19090
  ...nonEmpty2(value.turn_id) ? { turn_id: value.turn_id } : {},
19091
+ ...event === "UserPromptSubmit" ? { prompt: optionalText(value.prompt) } : {},
18713
19092
  ...nonEmpty2(value.tool_name) ? { tool_name: value.tool_name } : {},
18714
19093
  ...toolEvent ? { tool_input: value.tool_input } : {},
18715
19094
  ...event === "PostToolUse" && typeof value.tool_response === "string" ? { tool_response: value.tool_response } : {},
@@ -18728,13 +19107,20 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18728
19107
  switch (input.hook_event_name) {
18729
19108
  case "SessionStart":
18730
19109
  return { kind: "session.start", source: input.source };
19110
+ case "UserPromptSubmit":
19111
+ return { kind: "context.turn", prompt: input.prompt ?? null };
18731
19112
  case "PreToolUse": {
18732
19113
  const toolUseId = input.tool_use_id ?? null;
18733
- return isShellTool(input.tool_name) ? {
18734
- kind: "shell.pre",
18735
- command: input.command ?? "",
18736
- toolUseId
18737
- } : { kind: "tool.pre", tool: input.tool_name, toolUseId };
19114
+ if (isShellTool(input.tool_name))
19115
+ return { kind: "shell.pre", command: input.command ?? "", toolUseId };
19116
+ if (isWriteTool(input.tool_name))
19117
+ return {
19118
+ kind: "write.pre",
19119
+ tool: input.tool_name,
19120
+ paths: writeTargets(input.tool_input),
19121
+ toolUseId
19122
+ };
19123
+ return { kind: "tool.pre", tool: input.tool_name, toolUseId };
18738
19124
  }
18739
19125
  case "PostToolUse": {
18740
19126
  const toolUseId = input.tool_use_id ?? null;
@@ -18781,39 +19167,40 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18781
19167
  }, codexAdapter;
18782
19168
  var init_codex = __esm(() => {
18783
19169
  init_fields();
18784
- undocumented = { support: "undocumented", native: null };
18785
19170
  CODEX_DESCRIPTOR = {
18786
19171
  host: "codex_cli",
18787
19172
  label: "Codex",
18788
- verifiedAgainst: "codex-cli 0.153.4; Codex Desktop 26.901.20858",
19173
+ verifiedAgainst: "codex-cli 0.160.1 (hook JSON schemas in the binary); Codex Desktop 26.901.20858",
18789
19174
  docs: ["https://developers.openai.com/codex/hooks"],
18790
19175
  transport: "hook-process",
18791
19176
  events: {
18792
19177
  "session.start": { support: "native", native: "SessionStart" },
18793
- "context.turn": undocumented,
19178
+ "context.turn": { support: "native", native: "UserPromptSubmit" },
18794
19179
  "shell.pre": { support: "native", native: "PreToolUse" },
18795
19180
  "tool.pre": { support: "native", native: "PreToolUse" },
18796
- "write.pre": { support: "undocumented", native: null },
19181
+ "write.pre": { support: "native", native: "PreToolUse" },
18797
19182
  "shell.post": { support: "native", native: "PostToolUse" },
18798
19183
  "subagent.start": { support: "native", native: "SubagentStart" },
18799
19184
  "subagent.stop": { support: "native", native: "SubagentStop" },
18800
- "prompt.submit": undocumented,
19185
+ "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18801
19186
  "compact.pre": { support: "none", native: null },
18802
- stop: undocumented
19187
+ stop: { support: "none", native: null }
18803
19188
  },
18804
19189
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18805
19190
  context: {
18806
19191
  sessionStart: "native",
18807
- perTurn: "undocumented",
19192
+ perTurn: "native",
18808
19193
  afterCompact: "native",
18809
- task: "single-active"
19194
+ task: "single-active",
19195
+ turnResend: "on-change"
18810
19196
  },
18811
19197
  subagents: {
18812
19198
  identity: "native",
18813
19199
  parentBinding: "none",
18814
19200
  blockStart: "none",
18815
19201
  worktreeIsolation: "undocumented",
18816
- maxConcurrency: "undocumented"
19202
+ maxConcurrency: "undocumented",
19203
+ agentPrefix: "workit-"
18817
19204
  },
18818
19205
  provenance: { sessionId: "native", agentIdOnTool: "partial", postToolObserve: "native" },
18819
19206
  interaction: { questions: "none", writeBoundary: "partial" },
@@ -18880,13 +19267,14 @@ var init_codex = __esm(() => {
18880
19267
  };
18881
19268
  EVENTS2 = {
18882
19269
  SessionStart: "session.start",
19270
+ UserPromptSubmit: "context.turn",
18883
19271
  PreToolUse: "shell.pre",
18884
19272
  PostToolUse: "shell.post",
18885
19273
  SubagentStart: "subagent.start",
18886
19274
  SubagentStop: "subagent.stop"
18887
19275
  };
18888
19276
  SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
18889
- SOURCES2 = new Set(["startup", "resume", "clear", "compact"]);
19277
+ SOURCES2 = new Set(["startup", "resume", "clear", "compact", "fork"]);
18890
19278
  codexAdapter = {
18891
19279
  descriptor: CODEX_DESCRIPTOR,
18892
19280
  parse(raw, env) {
@@ -18916,13 +19304,13 @@ var init_codex = __esm(() => {
18916
19304
  };
18917
19305
  },
18918
19306
  render: render2,
18919
- 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>`
19307
+ 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>`
18920
19308
  };
18921
19309
  });
18922
19310
 
18923
19311
  // packages/workit-core/src/hooks/hosts/cursor.ts
18924
- import path20 from "node:path";
18925
- var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
19312
+ import path21 from "node:path";
19313
+ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
18926
19314
  if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
18927
19315
  return { ok: false, error: "hook_event_name is required" };
18928
19316
  const roots = value.workspace_roots;
@@ -18969,7 +19357,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
18969
19357
  return isWriteTool(input.tool_name) ? {
18970
19358
  kind: "write.pre",
18971
19359
  tool: input.tool_name ?? "",
18972
- paths: writePaths(input.tool_input),
19360
+ paths: writeTargets(input.tool_input),
18973
19361
  toolUseId: null
18974
19362
  } : { kind: "tool.pre", tool: input.tool_name ?? "", toolUseId: null };
18975
19363
  case "subagentStart":
@@ -18990,7 +19378,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
18990
19378
  case "preCompact":
18991
19379
  return { kind: "compact.pre", trigger: "auto" };
18992
19380
  }
18993
- }, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path20.sep) ? root : `${root}${path20.sep}`), hookCwd = (input) => {
19381
+ }, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path21.sep) ? root : `${root}${path21.sep}`), hookCwd = (input) => {
18994
19382
  const cwd = existingDirectory(input.cwd);
18995
19383
  if (cwd && input.hook_event_name === "beforeShellExecution")
18996
19384
  return cwd;
@@ -19021,7 +19409,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
19021
19409
  }, cursorAdapter;
19022
19410
  var init_cursor = __esm(() => {
19023
19411
  init_fields();
19024
- undocumented2 = { support: "undocumented", native: null };
19412
+ undocumented = { support: "undocumented", native: null };
19025
19413
  none = { support: "none", native: null };
19026
19414
  CURSOR_DESCRIPTOR = {
19027
19415
  host: "cursor",
@@ -19035,26 +19423,28 @@ var init_cursor = __esm(() => {
19035
19423
  "shell.pre": { support: "native", native: "beforeShellExecution" },
19036
19424
  "tool.pre": { support: "native", native: "preToolUse" },
19037
19425
  "write.pre": { support: "partial", native: "preToolUse" },
19038
- "shell.post": undocumented2,
19426
+ "shell.post": undocumented,
19039
19427
  "subagent.start": { support: "native", native: "subagentStart" },
19040
19428
  "subagent.stop": { support: "partial", native: "subagentStop" },
19041
- "prompt.submit": undocumented2,
19429
+ "prompt.submit": undocumented,
19042
19430
  "compact.pre": { support: "partial", native: "preCompact" },
19043
- stop: undocumented2
19431
+ stop: none
19044
19432
  },
19045
19433
  shellPolicy: { deny: "native", channel: "exit2+json", failClosed: true },
19046
19434
  context: {
19047
19435
  sessionStart: "native",
19048
19436
  perTurn: "none",
19049
19437
  afterCompact: "partial",
19050
- task: "single-active"
19438
+ task: "single-active",
19439
+ turnResend: "every-turn"
19051
19440
  },
19052
19441
  subagents: {
19053
19442
  identity: "native",
19054
19443
  parentBinding: "native",
19055
19444
  blockStart: "native",
19056
19445
  worktreeIsolation: "undocumented",
19057
- maxConcurrency: "undocumented"
19446
+ maxConcurrency: "undocumented",
19447
+ agentPrefix: "workit-"
19058
19448
  },
19059
19449
  provenance: {
19060
19450
  sessionId: "native",
@@ -19211,6 +19601,7 @@ var init_hooks = __esm(async () => {
19211
19601
  init_policy();
19212
19602
  init_write_gate();
19213
19603
  init_raw_git();
19604
+ init_skill_nudge();
19214
19605
  init_fields();
19215
19606
  init_handle();
19216
19607
  init_claude_code();