@brainervirus/workit-cursor 8.22.1 → 8.22.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.
@@ -2,7 +2,7 @@
2
2
  "name": "workit",
3
3
  "displayName": "Workit",
4
4
  "description": "Adaptive Workit workflow with shared MCP tools and native Cursor hooks",
5
- "version": "8.22.1",
5
+ "version": "8.22.2",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -18403,9 +18403,15 @@ var sessionMarkerFile = (input, session, store) => {
18403
18403
  }
18404
18404
  const name = createHash14("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
18405
18405
  return path20.join(dir, "hooks", `skills-${name}.json`);
18406
- }, list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [], readSessionMarker = (file) => {
18406
+ }, list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [], EMPTY, readRaw = (file) => {
18407
18407
  try {
18408
- const value = JSON.parse(fs16.readFileSync(file, "utf8"));
18408
+ return fs16.readFileSync(file, "utf8");
18409
+ } catch {
18410
+ return "";
18411
+ }
18412
+ }, parseMarker = (text) => {
18413
+ try {
18414
+ const value = JSON.parse(text);
18409
18415
  return {
18410
18416
  nudged: list2(value.nudged),
18411
18417
  loaded: list2(value.loaded),
@@ -18414,24 +18420,46 @@ var sessionMarkerFile = (input, session, store) => {
18414
18420
  judges: list2(value.judges)
18415
18421
  };
18416
18422
  } catch {
18417
- return { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
18423
+ return { ...EMPTY };
18424
+ }
18425
+ }, readSessionMarker = (file) => parseMarker(readRaw(file)), writeAtomic = (file, marker) => {
18426
+ fs16.mkdirSync(path20.dirname(file), { recursive: true });
18427
+ const temp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
18428
+ try {
18429
+ fs16.writeFileSync(temp, JSON.stringify(marker));
18430
+ fs16.renameSync(temp, file);
18431
+ } catch (error) {
18432
+ fs16.rmSync(temp, { force: true });
18433
+ throw error;
18418
18434
  }
18419
18435
  }, writeSessionMarker = (file, marker) => {
18420
18436
  try {
18421
- fs16.mkdirSync(path20.dirname(file), { recursive: true });
18422
- fs16.writeFileSync(file, JSON.stringify(marker));
18437
+ writeAtomic(file, marker);
18438
+ } catch {}
18439
+ }, updateSessionMarker = (file, change) => {
18440
+ try {
18441
+ for (let attempt = 0;attempt < 2; attempt++) {
18442
+ const before = readRaw(file);
18443
+ const next = change(parseMarker(before));
18444
+ if (attempt === 0 && readRaw(file) !== before)
18445
+ continue;
18446
+ writeAtomic(file, next);
18447
+ return;
18448
+ }
18423
18449
  } catch {}
18424
18450
  }, trackJudge = (input, agentId, running) => {
18425
18451
  const session = input.session.id;
18426
18452
  const file = session && agentId ? sessionMarkerFile(input, session) : null;
18427
18453
  if (!file || !agentId)
18428
18454
  return;
18429
- const marker = readSessionMarker(file);
18430
- const rest = marker.judges.filter((id) => id !== agentId);
18431
- writeSessionMarker(file, { ...marker, judges: running ? [...rest, agentId] : rest });
18455
+ updateSessionMarker(file, (marker) => {
18456
+ const rest = marker.judges.filter((id) => id !== agentId);
18457
+ return { ...marker, judges: running ? [...rest, agentId] : rest };
18458
+ });
18432
18459
  };
18433
18460
  var init_session_marker = __esm(() => {
18434
18461
  init_paths();
18462
+ EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
18435
18463
  });
18436
18464
 
18437
18465
  // packages/workit-core/src/hooks/shell-words.ts
@@ -19941,8 +19969,8 @@ var NONE2, SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLA
19941
19969
  }, nudgeFor = (action, host, session) => {
19942
19970
  switch (action.kind) {
19943
19971
  case "commit": {
19944
- const prefix = host === "cursor" && session ? `WORKIT_SESSION_ID=${session} ` : "";
19945
- return action.amend ? `workit: raw ${quote("git commit --amend")} is recorded for this session; for new commits prefer ${quote(`${prefix}workit git commit -m '<msg>'`)} (adds the Workit-Session trailer and checks branch and commit policy).` : `workit: prefer ${quote(`${prefix}workit git commit -m '<msg>' [--all | -- <paths>]`)}: it adds the Workit-Session trailer and checks branch and commit policy.`;
19972
+ const workit = host === "cursor" && session ? `workit --session ${session}` : "workit";
19973
+ return action.amend ? `workit: raw ${quote("git commit --amend")} is recorded for this session; for new commits prefer ${quote(`${workit} git commit -m '<msg>'`)} (adds the Workit-Session trailer and checks branch and commit policy).` : `workit: prefer ${quote(`${workit} git commit -m '<msg>' [--all | -- <paths>]`)}: it adds the Workit-Session trailer and checks branch and commit policy.`;
19946
19974
  }
19947
19975
  case "push":
19948
19976
  return action.blindForce ? `workit: ${quote("git push --force")} overwrites without a lease; use ${quote("workit git push --force-with-lease")}.` : `workit: prefer ${quote("workit git push")}: it refuses protected branches and verifies the remote tip.`;
@@ -20447,7 +20475,7 @@ function claudeSettingsFiles(cwd, env, platform = process.platform) {
20447
20475
  ];
20448
20476
  }
20449
20477
  function claudeRules(cwd, env = process.env) {
20450
- const rules = EMPTY();
20478
+ const rules = EMPTY2();
20451
20479
  try {
20452
20480
  for (const file of claudeSettingsFiles(cwd, env)) {
20453
20481
  const text = readText2(file);
@@ -20486,7 +20514,7 @@ function claudeRules(cwd, env = process.env) {
20486
20514
  return rules;
20487
20515
  }
20488
20516
  function opencodeRules(cwd, env = process.env) {
20489
- const rules = EMPTY();
20517
+ const rules = EMPTY2();
20490
20518
  try {
20491
20519
  const config = env.XDG_CONFIG_HOME || path23.join(homeOf(env), ".config");
20492
20520
  const files = [
@@ -20507,7 +20535,7 @@ function opencodeRules(cwd, env = process.env) {
20507
20535
  return rules;
20508
20536
  }
20509
20537
  function codexRules(cwd, env = process.env) {
20510
- const rules = EMPTY();
20538
+ const rules = EMPTY2();
20511
20539
  try {
20512
20540
  const home = env.CODEX_HOME || path23.join(homeOf(env), ".codex");
20513
20541
  const top = gitTop(cwd) ?? cwd;
@@ -20536,7 +20564,7 @@ function codexRules(cwd, env = process.env) {
20536
20564
  return rules;
20537
20565
  }
20538
20566
  function cursorRules(cwd, env = process.env) {
20539
- const rules = EMPTY();
20567
+ const rules = EMPTY2();
20540
20568
  try {
20541
20569
  const top = gitTop(cwd) ?? cwd;
20542
20570
  for (const file of [
@@ -20592,7 +20620,7 @@ function wrapAllowed(read, words, command, options = {}) {
20592
20620
  return { ok: false, why: "allowlisted" };
20593
20621
  return { ok: true };
20594
20622
  }
20595
- var EMPTY = () => ({ deny: [], allow: [] }), readText2 = (file) => {
20623
+ var EMPTY2 = () => ({ deny: [], allow: [] }), readText2 = (file) => {
20596
20624
  try {
20597
20625
  return fs18.readFileSync(file, "utf8");
20598
20626
  } catch (error) {
@@ -21886,7 +21914,7 @@ function stopDecision(input, descriptor) {
21886
21914
  if (file && marker) {
21887
21915
  if (marker.stops.includes(key))
21888
21916
  return NONE4;
21889
- writeSessionMarker(file, { ...marker, stops: [...marker.stops, key] });
21917
+ updateSessionMarker(file, (fresh) => ({ ...fresh, stops: [...fresh.stops, key] }));
21890
21918
  }
21891
21919
  return {
21892
21920
  kind: "continue",
@@ -21965,24 +21993,28 @@ var NONE4, QUESTION, OFFER, YES_NO, LIST_ITEM, asksUser = (message) => {
21965
21993
  kind: "checks",
21966
21994
  reason: `PR #${pr}'s checks were last seen ${state} at ${short(head)}, and this workspace's endpoint is \`${endpoint}\`: run \`workit ci wait --pr ${pr}\`${state === "failing" ? " after fixing the failures `workit pr status` lists (then push)" : ""}.`
21967
21995
  };
21968
- }, highRisk = (cwd) => {
21996
+ }, taskJudgment = (cwd) => {
21969
21997
  try {
21970
21998
  const store = new TaskStore(cwd);
21971
21999
  const listed = store.listTaskIndex();
21972
22000
  const key = store.currentKey();
21973
22001
  if (!listed.ok || !key.ok)
21974
- return false;
22002
+ return null;
21975
22003
  const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
21976
22004
  const task = entry ? store.readTask(entry.id) : null;
21977
- return task?.ok === true && latestJudgment(task.data)?.riskTier === "high";
22005
+ return task?.ok === true ? latestJudgment(task.data) : null;
21978
22006
  } catch {
21979
- return false;
22007
+ return null;
21980
22008
  }
21981
22009
  }, unverified = (cwd, branch, all, descriptor, verification) => {
21982
22010
  const check = checkVerdicts(cwd, branch, all);
21983
22011
  if (check.accepted.accepted || check.accepted.reasons.includes("failing_verdict"))
21984
22012
  return null;
21985
- const independent = verification === "independent" || highRisk(cwd);
22013
+ const judgment = taskJudgment(cwd);
22014
+ const high = judgment?.riskTier === "high";
22015
+ if (judgment && !judgment.behaviorChange && !high)
22016
+ return null;
22017
+ const independent = verification === "independent" || high;
21986
22018
  if (!independent && check.review === "self-reviewed")
21987
22019
  return null;
21988
22020
  const has = check.review === "self-reviewed" ? "only a self verdict" : "no current verdict";
@@ -23586,7 +23618,7 @@ var init_cursor = __esm(() => {
23586
23618
  };
23587
23619
  },
23588
23620
  render: render3,
23589
- addendum: (input) => input.session.id ? `<workit-session>Cursor puts no session id in the shell: prefix workit commands that record authorship with WORKIT_SESSION_ID=${input.session.id} (e.g. \`WORKIT_SESSION_ID=${input.session.id} workit git commit -m …\`). A verifier uses its own id, never this one.</workit-session>` : null
23621
+ addendum: (input) => input.session.id ? `<workit-session>Cursor puts no session id in the shell: start workit commands that record authorship with the global flag \`--session ${input.session.id}\` (e.g. \`workit --session ${input.session.id} git commit -m …\`; a leading env assignment can miss the \`Shell(workit)\` allowlist). A verifier uses its own id, never this one.</workit-session>` : null
23590
23622
  };
23591
23623
  });
23592
23624
 
@@ -18506,9 +18506,17 @@ var sessionMarkerFile = (input, session, store) => {
18506
18506
  return path20.join(dir, "hooks", `skills-${name}.json`);
18507
18507
  };
18508
18508
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
18509
- var readSessionMarker = (file) => {
18509
+ var EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
18510
+ var readRaw = (file) => {
18510
18511
  try {
18511
- const value = JSON.parse(fs16.readFileSync(file, "utf8"));
18512
+ return fs16.readFileSync(file, "utf8");
18513
+ } catch {
18514
+ return "";
18515
+ }
18516
+ };
18517
+ var parseMarker = (text) => {
18518
+ try {
18519
+ const value = JSON.parse(text);
18512
18520
  return {
18513
18521
  nudged: list2(value.nudged),
18514
18522
  loaded: list2(value.loaded),
@@ -18517,13 +18525,36 @@ var readSessionMarker = (file) => {
18517
18525
  judges: list2(value.judges)
18518
18526
  };
18519
18527
  } catch {
18520
- return { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
18528
+ return { ...EMPTY };
18529
+ }
18530
+ };
18531
+ var readSessionMarker = (file) => parseMarker(readRaw(file));
18532
+ var writeAtomic = (file, marker) => {
18533
+ fs16.mkdirSync(path20.dirname(file), { recursive: true });
18534
+ const temp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
18535
+ try {
18536
+ fs16.writeFileSync(temp, JSON.stringify(marker));
18537
+ fs16.renameSync(temp, file);
18538
+ } catch (error) {
18539
+ fs16.rmSync(temp, { force: true });
18540
+ throw error;
18521
18541
  }
18522
18542
  };
18523
18543
  var writeSessionMarker = (file, marker) => {
18524
18544
  try {
18525
- fs16.mkdirSync(path20.dirname(file), { recursive: true });
18526
- fs16.writeFileSync(file, JSON.stringify(marker));
18545
+ writeAtomic(file, marker);
18546
+ } catch {}
18547
+ };
18548
+ var updateSessionMarker = (file, change) => {
18549
+ try {
18550
+ for (let attempt = 0;attempt < 2; attempt++) {
18551
+ const before = readRaw(file);
18552
+ const next = change(parseMarker(before));
18553
+ if (attempt === 0 && readRaw(file) !== before)
18554
+ continue;
18555
+ writeAtomic(file, next);
18556
+ return;
18557
+ }
18527
18558
  } catch {}
18528
18559
  };
18529
18560
  var trackJudge = (input, agentId, running) => {
@@ -18531,9 +18562,10 @@ var trackJudge = (input, agentId, running) => {
18531
18562
  const file = session && agentId ? sessionMarkerFile(input, session) : null;
18532
18563
  if (!file || !agentId)
18533
18564
  return;
18534
- const marker = readSessionMarker(file);
18535
- const rest = marker.judges.filter((id) => id !== agentId);
18536
- writeSessionMarker(file, { ...marker, judges: running ? [...rest, agentId] : rest });
18565
+ updateSessionMarker(file, (marker) => {
18566
+ const rest = marker.judges.filter((id) => id !== agentId);
18567
+ return { ...marker, judges: running ? [...rest, agentId] : rest };
18568
+ });
18537
18569
  };
18538
18570
 
18539
18571
  // packages/workit-core/src/hooks/shell-words.ts
@@ -20182,8 +20214,8 @@ var offPolicyPush = (action, repo, facts, remote) => {
20182
20214
  var nudgeFor = (action, host, session) => {
20183
20215
  switch (action.kind) {
20184
20216
  case "commit": {
20185
- const prefix = host === "cursor" && session ? `WORKIT_SESSION_ID=${session} ` : "";
20186
- return action.amend ? `workit: raw ${quote("git commit --amend")} is recorded for this session; for new commits prefer ${quote(`${prefix}workit git commit -m '<msg>'`)} (adds the Workit-Session trailer and checks branch and commit policy).` : `workit: prefer ${quote(`${prefix}workit git commit -m '<msg>' [--all | -- <paths>]`)}: it adds the Workit-Session trailer and checks branch and commit policy.`;
20217
+ const workit = host === "cursor" && session ? `workit --session ${session}` : "workit";
20218
+ return action.amend ? `workit: raw ${quote("git commit --amend")} is recorded for this session; for new commits prefer ${quote(`${workit} git commit -m '<msg>'`)} (adds the Workit-Session trailer and checks branch and commit policy).` : `workit: prefer ${quote(`${workit} git commit -m '<msg>' [--all | -- <paths>]`)}: it adds the Workit-Session trailer and checks branch and commit policy.`;
20187
20219
  }
20188
20220
  case "push":
20189
20221
  return action.blindForce ? `workit: ${quote("git push --force")} overwrites without a lease; use ${quote("workit git push --force-with-lease")}.` : `workit: prefer ${quote("workit git push")}: it refuses protected branches and verifies the remote tip.`;
@@ -20584,7 +20616,7 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
20584
20616
  import fs18 from "node:fs";
20585
20617
  import os6 from "node:os";
20586
20618
  import path23 from "node:path";
20587
- var EMPTY = () => ({ deny: [], allow: [] });
20619
+ var EMPTY2 = () => ({ deny: [], allow: [] });
20588
20620
  var readText2 = (file) => {
20589
20621
  try {
20590
20622
  return fs18.readFileSync(file, "utf8");
@@ -20661,7 +20693,7 @@ var bashPattern = (entry) => {
20661
20693
  return match ? match[1] ?? "" : null;
20662
20694
  };
20663
20695
  function claudeRules(cwd, env = process.env) {
20664
- const rules = EMPTY();
20696
+ const rules = EMPTY2();
20665
20697
  try {
20666
20698
  for (const file of claudeSettingsFiles(cwd, env)) {
20667
20699
  const text = readText2(file);
@@ -20741,7 +20773,7 @@ var opencodeConfig = (value, rules) => {
20741
20773
  return Object.values(value.agent).every((agent) => isRecord4(agent) && opencodePermission(agent.permission, rules));
20742
20774
  };
20743
20775
  function opencodeRules(cwd, env = process.env) {
20744
- const rules = EMPTY();
20776
+ const rules = EMPTY2();
20745
20777
  try {
20746
20778
  const config = env.XDG_CONFIG_HOME || path23.join(homeOf(env), ".config");
20747
20779
  const files = [
@@ -20788,7 +20820,7 @@ var codexRule = (body) => {
20788
20820
  return { pattern: words.join(" "), decision };
20789
20821
  };
20790
20822
  function codexRules(cwd, env = process.env) {
20791
- const rules = EMPTY();
20823
+ const rules = EMPTY2();
20792
20824
  try {
20793
20825
  const home = env.CODEX_HOME || path23.join(homeOf(env), ".codex");
20794
20826
  const top = gitTop(cwd) ?? cwd;
@@ -20817,7 +20849,7 @@ function codexRules(cwd, env = process.env) {
20817
20849
  return rules;
20818
20850
  }
20819
20851
  function cursorRules(cwd, env = process.env) {
20820
- const rules = EMPTY();
20852
+ const rules = EMPTY2();
20821
20853
  try {
20822
20854
  const top = gitTop(cwd) ?? cwd;
20823
20855
  for (const file of [
@@ -22145,25 +22177,29 @@ var redChecks = (rows, pr, head, endpoint) => {
22145
22177
  reason: `PR #${pr}'s checks were last seen ${state} at ${short(head)}, and this workspace's endpoint is \`${endpoint}\`: run \`workit ci wait --pr ${pr}\`${state === "failing" ? " after fixing the failures `workit pr status` lists (then push)" : ""}.`
22146
22178
  };
22147
22179
  };
22148
- var highRisk = (cwd) => {
22180
+ var taskJudgment = (cwd) => {
22149
22181
  try {
22150
22182
  const store = new TaskStore(cwd);
22151
22183
  const listed = store.listTaskIndex();
22152
22184
  const key = store.currentKey();
22153
22185
  if (!listed.ok || !key.ok)
22154
- return false;
22186
+ return null;
22155
22187
  const entry = listed.data.filter((item) => item.key === key.data.key && item.status !== "closed").toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))[0];
22156
22188
  const task = entry ? store.readTask(entry.id) : null;
22157
- return task?.ok === true && latestJudgment(task.data)?.riskTier === "high";
22189
+ return task?.ok === true ? latestJudgment(task.data) : null;
22158
22190
  } catch {
22159
- return false;
22191
+ return null;
22160
22192
  }
22161
22193
  };
22162
22194
  var unverified = (cwd, branch, all, descriptor, verification) => {
22163
22195
  const check = checkVerdicts(cwd, branch, all);
22164
22196
  if (check.accepted.accepted || check.accepted.reasons.includes("failing_verdict"))
22165
22197
  return null;
22166
- const independent = verification === "independent" || highRisk(cwd);
22198
+ const judgment = taskJudgment(cwd);
22199
+ const high = judgment?.riskTier === "high";
22200
+ if (judgment && !judgment.behaviorChange && !high)
22201
+ return null;
22202
+ const independent = verification === "independent" || high;
22167
22203
  if (!independent && check.review === "self-reviewed")
22168
22204
  return null;
22169
22205
  const has = check.review === "self-reviewed" ? "only a self verdict" : "no current verdict";
@@ -22234,7 +22270,7 @@ function stopDecision(input, descriptor) {
22234
22270
  if (file && marker) {
22235
22271
  if (marker.stops.includes(key))
22236
22272
  return NONE4;
22237
- writeSessionMarker(file, { ...marker, stops: [...marker.stops, key] });
22273
+ updateSessionMarker(file, (fresh) => ({ ...fresh, stops: [...fresh.stops, key] }));
22238
22274
  }
22239
22275
  return {
22240
22276
  kind: "continue",
@@ -23831,7 +23867,7 @@ var cursorAdapter = {
23831
23867
  };
23832
23868
  },
23833
23869
  render: render3,
23834
- addendum: (input) => input.session.id ? `<workit-session>Cursor puts no session id in the shell: prefix workit commands that record authorship with WORKIT_SESSION_ID=${input.session.id} (e.g. \`WORKIT_SESSION_ID=${input.session.id} workit git commit -m …\`). A verifier uses its own id, never this one.</workit-session>` : null
23870
+ addendum: (input) => input.session.id ? `<workit-session>Cursor puts no session id in the shell: start workit commands that record authorship with the global flag \`--session ${input.session.id}\` (e.g. \`workit --session ${input.session.id} git commit -m …\`; a leading env assignment can miss the \`Shell(workit)\` allowlist). A verifier uses its own id, never this one.</workit-session>` : null
23835
23871
  };
23836
23872
 
23837
23873
  // packages/workit-core/src/hooks/run.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.22.1",
3
+ "version": "8.22.2",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and sixteen method skills",
6
6
  "keywords": [
@@ -46,8 +46,8 @@
46
46
  "build": "bun scripts/build.ts"
47
47
  },
48
48
  "devDependencies": {
49
- "@brainervirus/workit-core": "^8.22.1",
50
- "@brainervirus/workit-mcp": "^8.22.1"
49
+ "@brainervirus/workit-core": "^8.22.2",
50
+ "@brainervirus/workit-mcp": "^8.22.2"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"