@brainervirus/workit-cursor 8.4.0 → 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.
@@ -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,286 @@ 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
+ for (const word of words.slice(1)) {
18476
+ const skill = skillFileIn(word);
18477
+ if (skill)
18478
+ return skill;
18479
+ }
18480
+ }
18481
+ return null;
18482
+ }, nudgeOnce = (input, session, skill, line) => {
18483
+ const file = markerFile2(input, session);
18484
+ if (!file)
18485
+ return null;
18486
+ const marker = readMarker(file);
18487
+ if (marker.nudged.includes(skill) || marker.loaded.includes(skill))
18488
+ return null;
18489
+ if (loadedSkills(input.cwd, session).has(skill))
18490
+ return null;
18491
+ writeMarker(file, { ...marker, nudged: [...marker.nudged, skill] });
18492
+ return line;
18493
+ }, 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 }) => {
18494
+ const at = words.findIndex((word) => !/^\w+=/.test(word) && !LAUNCHERS.has(word));
18495
+ if (at >= 0 && /(?:^|[\\/])workit(?:\.exe)?$|^@brainervirus\/workit-cli$/.test(words[at])) {
18496
+ const args = words.slice(at + 1);
18497
+ if (args.some((arg) => arg === "--help" || arg === "-h" || arg === "--dry-run"))
18498
+ return false;
18499
+ return WORKIT_DELIVERY.test(args.join(" "));
18500
+ }
18501
+ const shell = SHELLS2.has(words[at]?.split(/[\\/]/).at(-1) ?? "");
18502
+ const script = shell && words[at + 1] === "-c" ? words[at + 2] : undefined;
18503
+ return depth < 3 && script !== undefined && runsWorkitDelivery(script, "posix", depth + 1);
18504
+ }), isDeliveryCommand = (cwd, command, dialect = "posix") => rawDelivery(cwd, command, dialect) || runsWorkitDelivery(command, dialect) && inWorkitWorkspace(cwd), withContextLine = (decision, line) => {
18505
+ if (!line)
18506
+ return decision;
18507
+ if (decision.kind === "none")
18508
+ return { kind: "context", text: line };
18509
+ if (decision.kind === "context")
18510
+ return { kind: "context", text: `${decision.text}
18511
+ ${line}` };
18512
+ return decision;
18513
+ };
18514
+ var init_skill_nudge = __esm(() => {
18515
+ init_skill_manifests();
18516
+ init_ledger();
18517
+ init_paths();
18518
+ init_raw_git();
18519
+ USER_INVOKED = new Set(["workit-retro", "workit-architecture"]);
18520
+ SKILL_HOST = {
18521
+ claude_code: "claude-code",
18522
+ opencode: "opencode",
18523
+ codex_cli: "codex",
18524
+ codex_desktop: "codex",
18525
+ cursor: "cursor",
18526
+ pi: "pi"
18527
+ };
18528
+ PROMPT_INTENTS = [
18529
+ [
18530
+ "workit-debug",
18531
+ /\b(flaky|regression|(?:is|are|got|looks) broken|debug (?:this|it|the|why)|fix (?:the|this|a) bug)\b/i
18532
+ ],
18533
+ [
18534
+ "workit-continue",
18535
+ /\b(pick up where|where (?:were|did) we|resume (?:the|this|my|our|work|where)|hand ?off)\b/i
18536
+ ],
18537
+ [
18538
+ "workit-review",
18539
+ /\b(blast radius|code review|review (?:the|this|my|PR|pr|#\d+|branch|diff|changes))\b/i
18540
+ ],
18541
+ [
18542
+ "workit-ship",
18543
+ /\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
18544
+ ],
18545
+ ["workit-bdd", /\b(BDD|TDD|acceptance criteria|Given\/When\/Then)(?![\w/])/],
18546
+ ["workit-test-audit", /\b(test audit|audit the tests|tautolog\w*|weak tests)\b/i],
18547
+ ["workit-deslop", /\b(deslop|slop|dead code)\b/i],
18548
+ ["workit-fanout", /\b(fan(?: |-)?out|parallelize|parallel agents|swarm)\b/i],
18549
+ ["workit-verify-app", /\b(verify the app|smoke test|prove it works)\b/i],
18550
+ ["workit-retro", /\b(retro|retrospective)\b(?!\.\w)/i],
18551
+ ["workit-architecture", /\b(deepen (?:the )?modules|architecture (?:review|pass|audit))\b/i],
18552
+ [
18553
+ "workit-shape",
18554
+ /\b(brainstorm\w*|grill me|should we|let'?s plan|plan (?:out|how|the|a|for)|(?:write|draft) (?:a|the) spec)\b/i
18555
+ ],
18556
+ [
18557
+ "workit-implement",
18558
+ /\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
18559
+ ]
18560
+ ];
18561
+ SKILL_FILE = /(?:^|[\\/])(workit-[a-z-]+)[\\/]SKILL\.md$/;
18562
+ READERS = new Set([
18563
+ "cat",
18564
+ "sed",
18565
+ "head",
18566
+ "tail",
18567
+ "less",
18568
+ "more",
18569
+ "bat",
18570
+ "nl",
18571
+ "get-content",
18572
+ "gc",
18573
+ "type"
18574
+ ]);
18575
+ WORKIT_DELIVERY = /^(?:pr (?:create|merge)|ci wait|git push)\b/;
18576
+ SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
18577
+ LAUNCHERS = new Set([
18578
+ "npx",
18579
+ "bunx",
18580
+ "pnpx",
18581
+ "-y",
18582
+ "--yes",
18583
+ "pnpm",
18584
+ "dlx",
18585
+ "exec",
18586
+ "env",
18587
+ "sudo",
18588
+ "command"
18589
+ ]);
18590
+ });
18591
+
18256
18592
  // packages/workit-core/src/hooks/hosts/fields.ts
18257
18593
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
18258
- import path19 from "node:path";
18594
+ import path20 from "node:path";
18259
18595
  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))
18596
+ if (!nonEmpty2(value) || !path20.isAbsolute(value) || !existsSync6(value))
18261
18597
  return null;
18262
18598
  try {
18263
18599
  return statSync2(value).isDirectory() ? realpathSync6(value) : null;
18264
18600
  } catch {
18265
18601
  return null;
18266
18602
  }
18267
- }, SHELLS2, SCRIPT_FLAG2, quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg), commandText = (value) => {
18603
+ }, SHELLS3, SCRIPT_FLAG2, quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg), commandText = (value) => {
18268
18604
  if (nonEmpty2(value))
18269
18605
  return value;
18270
18606
  if (!Array.isArray(value) || value.length === 0)
@@ -18273,7 +18609,7 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
18273
18609
  if (!argv.every((arg) => typeof arg === "string"))
18274
18610
  return null;
18275
18611
  const shell = argv[0].split(/[\\/]/).at(-1)?.replace(/\.exe$/i, "").toLowerCase() ?? "";
18276
- if (SHELLS2.has(shell))
18612
+ if (SHELLS3.has(shell))
18277
18613
  for (let index = 1;index < argv.length - 1; index++) {
18278
18614
  if (SCRIPT_FLAG2.test(argv[index]))
18279
18615
  return nonEmpty2(argv[index + 1]) ? argv[index + 1] : null;
@@ -18282,18 +18618,21 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
18282
18618
  }
18283
18619
  const joined = argv.map(quoteArg).join(" ");
18284
18620
  return nonEmpty2(joined) ? joined : null;
18285
- }, WRITE_TOOLS, isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, "")), PATH_KEYS, writePaths = (input) => {
18621
+ }, WRITE_TOOLS, isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, "")), PATH_KEYS, PATCH_HEADER, writePaths = (input) => {
18286
18622
  if (!isRecord4(input))
18287
18623
  return [];
18288
18624
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
18289
18625
  for (const value of Object.values(input))
18290
18626
  if (typeof value === "string")
18291
- for (const match of value.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm))
18627
+ for (const match of value.matchAll(PATCH_HEADER))
18292
18628
  paths.push(match[1].trim());
18293
18629
  return [...new Set(paths)];
18630
+ }, writeTargets = (input) => {
18631
+ const paths = writePaths(input);
18632
+ return paths.length > 0 ? paths : null;
18294
18633
  };
18295
18634
  var init_fields = __esm(() => {
18296
- SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18635
+ SHELLS3 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18297
18636
  SCRIPT_FLAG2 = /^(?:-\w*c|-command|\/c)$/i;
18298
18637
  WRITE_TOOLS = new Set([
18299
18638
  "write",
@@ -18315,6 +18654,7 @@ var init_fields = __esm(() => {
18315
18654
  "writefile"
18316
18655
  ]);
18317
18656
  PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
18657
+ PATCH_HEADER = /^[ \t]*\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+)$/gm;
18318
18658
  });
18319
18659
 
18320
18660
  // packages/workit-core/src/hooks/handle.ts
@@ -18332,18 +18672,22 @@ function handleHook(input, deps) {
18332
18672
  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
18673
  const addendum = [deps.addendum, advisory].filter(Boolean).join(`
18334
18674
  `) || null;
18335
- return {
18336
- kind: "context",
18337
- text: sessionContextText(input, descriptor, { offer, addendum })
18338
- };
18675
+ const text = sessionContextText(input, descriptor, { offer, addendum });
18676
+ if (resendsOnChange(descriptor))
18677
+ seedTurnContext(input, descriptor);
18678
+ return { kind: "context", text };
18339
18679
  }
18340
18680
  case "context.turn": {
18341
18681
  if (!usable2(descriptor.context.perTurn))
18342
18682
  return NONE4;
18343
- const text = turnContextText(input, descriptor);
18344
- return text ? { kind: "context", text } : NONE4;
18683
+ const current = turnContextText(input, descriptor);
18684
+ const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
18685
+ return withContextLine(text ? { kind: "context", text } : NONE4, promptNudge(input, event.prompt));
18345
18686
  }
18346
18687
  case "shell.pre": {
18688
+ const skillRead = skillReadIn(event.command, event.dialect);
18689
+ if (skillRead)
18690
+ recordSkillLoad(input, skillRead, "read");
18347
18691
  const canDeny = usable2(descriptor.shellPolicy.deny);
18348
18692
  const policy = canDeny ? shellPolicy(input.cwd, event.command) : NONE4;
18349
18693
  if (policy.kind !== "none")
@@ -18359,7 +18703,7 @@ function handleHook(input, deps) {
18359
18703
  if (gate.kind === "deny")
18360
18704
  return gate;
18361
18705
  noteRawCommit(input, event.command, postTool ? callKey(event.toolUseId, event.command) : NEXT_COMMAND);
18362
- return raw;
18706
+ return withContextLine(raw, shipNudge(input, event.command));
18363
18707
  }
18364
18708
  case "shell.post":
18365
18709
  if (usable2(descriptor.events["shell.post"].support))
@@ -18370,7 +18714,7 @@ function handleHook(input, deps) {
18370
18714
  case "subagent.start":
18371
18715
  return {
18372
18716
  kind: "context",
18373
- text: subagentStartText(input.host, input.session.id ?? null, descriptor, event)
18717
+ text: subagentStartText(input.session.id ?? null, descriptor, event)
18374
18718
  };
18375
18719
  case "compact.pre":
18376
18720
  return {
@@ -18378,19 +18722,31 @@ function handleHook(input, deps) {
18378
18722
  userMessage: "Workit context may be stale after compaction; re-run inspection or resume before acting."
18379
18723
  };
18380
18724
  case "tool.pre":
18725
+ if (event.skill)
18726
+ recordSkillLoad(input, event.skill, "tool");
18727
+ return NONE4;
18381
18728
  case "subagent.stop":
18382
18729
  case "prompt.submit":
18383
18730
  case "stop":
18384
18731
  return NONE4;
18385
18732
  }
18386
18733
  }
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;
18734
+ var usable2 = (value) => value === "native" || value === "partial", NONE4, resendsOnChange = (descriptor) => descriptor.context.turnResend === "on-change" && usable2(descriptor.context.perTurn), offered, ROLES, workitRole = (descriptor, agentType) => {
18735
+ const prefix = descriptor.subagents.agentPrefix;
18736
+ const name = agentType.startsWith(prefix) ? agentType.slice(prefix.length) : "";
18737
+ return Object.hasOwn(ROLES, name) ? ROLES[name] : null;
18738
+ }, subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), subagentStartText = (session, descriptor, event) => {
18739
+ const role = workitRole(descriptor, event.agentType);
18740
+ const who = `${descriptor.label} subagent ${event.agentId} (${event.agentType})`;
18741
+ if (role === "implementer") {
18742
+ 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";
18743
+ 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.`;
18744
+ }
18745
+ const readOnly = `Workit observed ${who} as read-only/agent-guided.`;
18746
+ if (role !== "judge" || !event.agentId)
18747
+ return readOnly;
18748
+ const own = subagentSession(session, event.agentId);
18749
+ 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
18750
  }, failureDecision = (descriptor, event, error) => {
18395
18751
  if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
18396
18752
  return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE4;
@@ -18423,10 +18779,15 @@ var init_handle = __esm(() => {
18423
18779
  init_context();
18424
18780
  init_policy();
18425
18781
  init_raw_git();
18782
+ init_skill_nudge();
18426
18783
  init_write_gate();
18427
18784
  NONE4 = { kind: "none" };
18428
18785
  offered = new Set;
18429
- CLAUDE_JUDGES = new Set(["workit:verifier", "workit:reviewer"]);
18786
+ ROLES = {
18787
+ implementer: "implementer",
18788
+ verifier: "judge",
18789
+ reviewer: "judge"
18790
+ };
18430
18791
  });
18431
18792
 
18432
18793
  // packages/workit-core/src/hooks/hosts/claude-code.ts
@@ -18436,7 +18797,7 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, dialectOf2 = (value) =
18436
18797
  case "SessionStart":
18437
18798
  return SOURCES.has(value.source) ? { ok: true, event: { kind: "session.start", source: value.source } } : { ok: false, error: "SessionStart source is required" };
18438
18799
  case "UserPromptSubmit":
18439
- return { ok: true, event: { kind: "context.turn" } };
18800
+ return { ok: true, event: { kind: "context.turn", prompt: optionalText(value.prompt) } };
18440
18801
  case "PreToolUse": {
18441
18802
  if (!nonEmpty2(value.tool_name))
18442
18803
  return { ok: false, error: "tool_name is required" };
@@ -18446,10 +18807,20 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, dialectOf2 = (value) =
18446
18807
  event: {
18447
18808
  kind: "write.pre",
18448
18809
  tool: value.tool_name,
18449
- paths: writePaths(value.tool_input),
18810
+ paths: writeTargets(value.tool_input),
18450
18811
  toolUseId
18451
18812
  }
18452
18813
  };
18814
+ if (value.tool_name === "Skill")
18815
+ return {
18816
+ ok: true,
18817
+ event: {
18818
+ kind: "tool.pre",
18819
+ tool: value.tool_name,
18820
+ toolUseId,
18821
+ skill: isRecord4(value.tool_input) ? optionalText(value.tool_input.skill) : null
18822
+ }
18823
+ };
18453
18824
  if (!SHELL_TOOLS.has(value.tool_name))
18454
18825
  return { ok: true, event: { kind: "tool.pre", tool: value.tool_name, toolUseId } };
18455
18826
  const command = toolCommand(value);
@@ -18547,24 +18918,26 @@ var init_claude_code = __esm(() => {
18547
18918
  "write.pre": { support: "native", native: "PreToolUse" },
18548
18919
  "shell.post": { support: "native", native: "PostToolUse" },
18549
18920
  "subagent.start": { support: "native", native: "SubagentStart" },
18550
- "subagent.stop": { support: "native", native: "SubagentStop" },
18551
18921
  "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18552
- "compact.pre": { support: "partial", native: "PreCompact" },
18553
- stop: { support: "native", native: "Stop" }
18922
+ "subagent.stop": { support: "none", native: null },
18923
+ "compact.pre": { support: "none", native: null },
18924
+ stop: { support: "none", native: null }
18554
18925
  },
18555
18926
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18556
18927
  context: {
18557
18928
  sessionStart: "native",
18558
18929
  perTurn: "native",
18559
18930
  afterCompact: "native",
18560
- task: "session-bound"
18931
+ task: "session-bound",
18932
+ turnResend: "every-turn"
18561
18933
  },
18562
18934
  subagents: {
18563
18935
  identity: "native",
18564
18936
  parentBinding: "partial",
18565
18937
  blockStart: "none",
18566
18938
  worktreeIsolation: "native",
18567
- maxConcurrency: "undocumented"
18939
+ maxConcurrency: "undocumented",
18940
+ agentPrefix: "workit:"
18568
18941
  },
18569
18942
  provenance: { sessionId: "native", agentIdOnTool: "native", postToolObserve: "native" },
18570
18943
  interaction: { questions: "undocumented", writeBoundary: "partial" },
@@ -18582,13 +18955,13 @@ var init_claude_code = __esm(() => {
18582
18955
  },
18583
18956
  {
18584
18957
  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"],
18958
+ surface: "SubagentStart",
18959
+ refs: ["SubagentStart"],
18960
+ requires: ["event:subagent.start"],
18961
+ observed: ["subagent.start"],
18589
18962
  assurance: "agent_guided",
18590
18963
  reason: "Claude Code reports stable agent identities, but SubagentStart cannot block or bind",
18591
- unavailableReason: "Claude Code subagent lifecycle hooks are unavailable"
18964
+ unavailableReason: "Claude Code SubagentStart is unavailable"
18592
18965
  },
18593
18966
  {
18594
18967
  name: "fresh-context-review",
@@ -18684,7 +19057,7 @@ var init_claude_code = __esm(() => {
18684
19057
  function detectCodexSurface(env) {
18685
19058
  return env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || Boolean(env.CODEX_ELECTRON_RESOURCES_PATH) ? "codex_desktop" : "codex_cli";
18686
19059
  }
18687
- var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase()), SOURCES2, parseCodexHookInput = (value) => {
19060
+ var CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase()), SOURCES2, parseCodexHookInput = (value) => {
18688
19061
  if (!isRecord4(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
18689
19062
  return { ok: false, error: "hook_event_name is required" };
18690
19063
  const event = value.hook_event_name;
@@ -18710,6 +19083,7 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18710
19083
  cwd,
18711
19084
  ...event === "SessionStart" ? { source: SOURCES2.has(String(value.source)) ? value.source : "resume" } : {},
18712
19085
  ...nonEmpty2(value.turn_id) ? { turn_id: value.turn_id } : {},
19086
+ ...event === "UserPromptSubmit" ? { prompt: optionalText(value.prompt) } : {},
18713
19087
  ...nonEmpty2(value.tool_name) ? { tool_name: value.tool_name } : {},
18714
19088
  ...toolEvent ? { tool_input: value.tool_input } : {},
18715
19089
  ...event === "PostToolUse" && typeof value.tool_response === "string" ? { tool_response: value.tool_response } : {},
@@ -18728,13 +19102,20 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18728
19102
  switch (input.hook_event_name) {
18729
19103
  case "SessionStart":
18730
19104
  return { kind: "session.start", source: input.source };
19105
+ case "UserPromptSubmit":
19106
+ return { kind: "context.turn", prompt: input.prompt ?? null };
18731
19107
  case "PreToolUse": {
18732
19108
  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 };
19109
+ if (isShellTool(input.tool_name))
19110
+ return { kind: "shell.pre", command: input.command ?? "", toolUseId };
19111
+ if (isWriteTool(input.tool_name))
19112
+ return {
19113
+ kind: "write.pre",
19114
+ tool: input.tool_name,
19115
+ paths: writeTargets(input.tool_input),
19116
+ toolUseId
19117
+ };
19118
+ return { kind: "tool.pre", tool: input.tool_name, toolUseId };
18738
19119
  }
18739
19120
  case "PostToolUse": {
18740
19121
  const toolUseId = input.tool_use_id ?? null;
@@ -18781,39 +19162,40 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
18781
19162
  }, codexAdapter;
18782
19163
  var init_codex = __esm(() => {
18783
19164
  init_fields();
18784
- undocumented = { support: "undocumented", native: null };
18785
19165
  CODEX_DESCRIPTOR = {
18786
19166
  host: "codex_cli",
18787
19167
  label: "Codex",
18788
- verifiedAgainst: "codex-cli 0.153.4; Codex Desktop 26.901.20858",
19168
+ verifiedAgainst: "codex-cli 0.160.1 (hook JSON schemas in the binary); Codex Desktop 26.901.20858",
18789
19169
  docs: ["https://developers.openai.com/codex/hooks"],
18790
19170
  transport: "hook-process",
18791
19171
  events: {
18792
19172
  "session.start": { support: "native", native: "SessionStart" },
18793
- "context.turn": undocumented,
19173
+ "context.turn": { support: "native", native: "UserPromptSubmit" },
18794
19174
  "shell.pre": { support: "native", native: "PreToolUse" },
18795
19175
  "tool.pre": { support: "native", native: "PreToolUse" },
18796
- "write.pre": { support: "undocumented", native: null },
19176
+ "write.pre": { support: "native", native: "PreToolUse" },
18797
19177
  "shell.post": { support: "native", native: "PostToolUse" },
18798
19178
  "subagent.start": { support: "native", native: "SubagentStart" },
18799
19179
  "subagent.stop": { support: "native", native: "SubagentStop" },
18800
- "prompt.submit": undocumented,
19180
+ "prompt.submit": { support: "native", native: "UserPromptSubmit" },
18801
19181
  "compact.pre": { support: "none", native: null },
18802
- stop: undocumented
19182
+ stop: { support: "none", native: null }
18803
19183
  },
18804
19184
  shellPolicy: { deny: "native", channel: "permissionDecision", failClosed: false },
18805
19185
  context: {
18806
19186
  sessionStart: "native",
18807
- perTurn: "undocumented",
19187
+ perTurn: "native",
18808
19188
  afterCompact: "native",
18809
- task: "single-active"
19189
+ task: "single-active",
19190
+ turnResend: "on-change"
18810
19191
  },
18811
19192
  subagents: {
18812
19193
  identity: "native",
18813
19194
  parentBinding: "none",
18814
19195
  blockStart: "none",
18815
19196
  worktreeIsolation: "undocumented",
18816
- maxConcurrency: "undocumented"
19197
+ maxConcurrency: "undocumented",
19198
+ agentPrefix: "workit-"
18817
19199
  },
18818
19200
  provenance: { sessionId: "native", agentIdOnTool: "partial", postToolObserve: "native" },
18819
19201
  interaction: { questions: "none", writeBoundary: "partial" },
@@ -18880,13 +19262,14 @@ var init_codex = __esm(() => {
18880
19262
  };
18881
19263
  EVENTS2 = {
18882
19264
  SessionStart: "session.start",
19265
+ UserPromptSubmit: "context.turn",
18883
19266
  PreToolUse: "shell.pre",
18884
19267
  PostToolUse: "shell.post",
18885
19268
  SubagentStart: "subagent.start",
18886
19269
  SubagentStop: "subagent.stop"
18887
19270
  };
18888
19271
  SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
18889
- SOURCES2 = new Set(["startup", "resume", "clear", "compact"]);
19272
+ SOURCES2 = new Set(["startup", "resume", "clear", "compact", "fork"]);
18890
19273
  codexAdapter = {
18891
19274
  descriptor: CODEX_DESCRIPTOR,
18892
19275
  parse(raw, env) {
@@ -18916,13 +19299,13 @@ var init_codex = __esm(() => {
18916
19299
  };
18917
19300
  },
18918
19301
  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>`
19302
+ 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
19303
  };
18921
19304
  });
18922
19305
 
18923
19306
  // packages/workit-core/src/hooks/hosts/cursor.ts
18924
- import path20 from "node:path";
18925
- var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
19307
+ import path21 from "node:path";
19308
+ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
18926
19309
  if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
18927
19310
  return { ok: false, error: "hook_event_name is required" };
18928
19311
  const roots = value.workspace_roots;
@@ -18969,7 +19352,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
18969
19352
  return isWriteTool(input.tool_name) ? {
18970
19353
  kind: "write.pre",
18971
19354
  tool: input.tool_name ?? "",
18972
- paths: writePaths(input.tool_input),
19355
+ paths: writeTargets(input.tool_input),
18973
19356
  toolUseId: null
18974
19357
  } : { kind: "tool.pre", tool: input.tool_name ?? "", toolUseId: null };
18975
19358
  case "subagentStart":
@@ -18990,7 +19373,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
18990
19373
  case "preCompact":
18991
19374
  return { kind: "compact.pre", trigger: "auto" };
18992
19375
  }
18993
- }, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path20.sep) ? root : `${root}${path20.sep}`), hookCwd = (input) => {
19376
+ }, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path21.sep) ? root : `${root}${path21.sep}`), hookCwd = (input) => {
18994
19377
  const cwd = existingDirectory(input.cwd);
18995
19378
  if (cwd && input.hook_event_name === "beforeShellExecution")
18996
19379
  return cwd;
@@ -19021,7 +19404,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
19021
19404
  }, cursorAdapter;
19022
19405
  var init_cursor = __esm(() => {
19023
19406
  init_fields();
19024
- undocumented2 = { support: "undocumented", native: null };
19407
+ undocumented = { support: "undocumented", native: null };
19025
19408
  none = { support: "none", native: null };
19026
19409
  CURSOR_DESCRIPTOR = {
19027
19410
  host: "cursor",
@@ -19035,26 +19418,28 @@ var init_cursor = __esm(() => {
19035
19418
  "shell.pre": { support: "native", native: "beforeShellExecution" },
19036
19419
  "tool.pre": { support: "native", native: "preToolUse" },
19037
19420
  "write.pre": { support: "partial", native: "preToolUse" },
19038
- "shell.post": undocumented2,
19421
+ "shell.post": undocumented,
19039
19422
  "subagent.start": { support: "native", native: "subagentStart" },
19040
19423
  "subagent.stop": { support: "partial", native: "subagentStop" },
19041
- "prompt.submit": undocumented2,
19424
+ "prompt.submit": undocumented,
19042
19425
  "compact.pre": { support: "partial", native: "preCompact" },
19043
- stop: undocumented2
19426
+ stop: none
19044
19427
  },
19045
19428
  shellPolicy: { deny: "native", channel: "exit2+json", failClosed: true },
19046
19429
  context: {
19047
19430
  sessionStart: "native",
19048
19431
  perTurn: "none",
19049
19432
  afterCompact: "partial",
19050
- task: "single-active"
19433
+ task: "single-active",
19434
+ turnResend: "every-turn"
19051
19435
  },
19052
19436
  subagents: {
19053
19437
  identity: "native",
19054
19438
  parentBinding: "native",
19055
19439
  blockStart: "native",
19056
19440
  worktreeIsolation: "undocumented",
19057
- maxConcurrency: "undocumented"
19441
+ maxConcurrency: "undocumented",
19442
+ agentPrefix: "workit-"
19058
19443
  },
19059
19444
  provenance: {
19060
19445
  sessionId: "native",
@@ -19211,6 +19596,7 @@ var init_hooks = __esm(async () => {
19211
19596
  init_policy();
19212
19597
  init_write_gate();
19213
19598
  init_raw_git();
19599
+ init_skill_nudge();
19214
19600
  init_fields();
19215
19601
  init_handle();
19216
19602
  init_claude_code();