@brainervirus/workit-cursor 8.32.0 → 8.33.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.
@@ -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.32.0",
5
+ "version": "8.33.0",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -17849,7 +17849,8 @@ var sessionMarkerFile = (input, session, store) => {
17849
17849
  loaded: list2(value.loaded),
17850
17850
  raw: list2(value.raw),
17851
17851
  stops: list2(value.stops),
17852
- judges: list2(value.judges)
17852
+ judges: list2(value.judges),
17853
+ model: typeof value.model === "string" ? value.model : null
17853
17854
  };
17854
17855
  } catch {
17855
17856
  return { ...EMPTY };
@@ -17888,10 +17889,28 @@ var sessionMarkerFile = (input, session, store) => {
17888
17889
  const rest = marker.judges.filter((id) => id !== agentId);
17889
17890
  return { ...marker, judges: running ? [...rest, agentId] : rest };
17890
17891
  });
17892
+ }, modelSwitchedOnDisk = (input) => {
17893
+ const session = input.session.id;
17894
+ const model = input.model;
17895
+ const file = session && model ? sessionMarkerFile(input, session) : null;
17896
+ if (!file || !model)
17897
+ return false;
17898
+ const previous = readSessionMarker(file).model;
17899
+ if (previous === model)
17900
+ return false;
17901
+ updateSessionMarker(file, (marker) => ({ ...marker, model }));
17902
+ return previous !== null;
17891
17903
  };
17892
17904
  var init_session_marker = __esm(() => {
17893
17905
  init_paths();
17894
- EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
17906
+ EMPTY = {
17907
+ nudged: [],
17908
+ loaded: [],
17909
+ raw: [],
17910
+ stops: [],
17911
+ judges: [],
17912
+ model: null
17913
+ };
17895
17914
  });
17896
17915
 
17897
17916
  // packages/workit-core/src/hooks/shell-words.ts
@@ -22643,7 +22662,9 @@ function decide(input, deps) {
22643
22662
  if (!usable2(descriptor.context.perTurn))
22644
22663
  return NONE6;
22645
22664
  const current = turnContextText(input, descriptor);
22646
- const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
22665
+ const turn = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
22666
+ const text = input.model && modelSwitchedOnDisk(input) ? [invariantBootstrap(), turn].filter(Boolean).join(`
22667
+ `) : turn;
22647
22668
  return withContextLine(text ? { kind: "context", text } : NONE6, promptNudge(input, event.prompt));
22648
22669
  }
22649
22670
  case "shell.pre": {
@@ -22819,6 +22840,7 @@ var init_handle = __esm(() => {
22819
22840
  init_spawn_gate();
22820
22841
  init_standing();
22821
22842
  init_session_marker();
22843
+ init_methods();
22822
22844
  init_stop();
22823
22845
  init_live_session();
22824
22846
  init_write_gate();
@@ -23493,6 +23515,7 @@ var init_codex = __esm(() => {
23493
23515
  },
23494
23516
  permissionMode: input.permission_mode,
23495
23517
  transcriptPath: input.transcript_path,
23518
+ model: input.model,
23496
23519
  event: protocolEvent(input)
23497
23520
  }
23498
23521
  };
@@ -16256,10 +16256,11 @@ function invalidOperation(family, input, error) {
16256
16256
  const request = isObject2(input) ? input : {};
16257
16257
  const action = typeof request.action === "string" ? request.action : "";
16258
16258
  const actions = OPERATION_ACTIONS[family];
16259
- if (!actions.includes(action))
16260
- return failure2("invalid_input", `${family}: action must be one of ${oneOf(actions)}`, {
16261
- fields: [{ path: "action", reason: `got ${JSON.stringify(request.action ?? null)}` }]
16262
- });
16259
+ if (!actions.includes(action)) {
16260
+ const common = actions.find((name) => READ_ONLY_ACTIONS.has(name)) ?? actions[0];
16261
+ const example = JSON.stringify(exampleOperation(family, common));
16262
+ return failure2("invalid_input", `${family}: action must be one of ${oneOf(actions)}. Example: ${example}`, { fields: [{ path: "action", reason: `got ${JSON.stringify(request.action ?? null)}` }] });
16263
+ }
16263
16264
  const own = actionKeys(family, action);
16264
16265
  const fields = [];
16265
16266
  const sentence = [];
@@ -27734,6 +27735,38 @@ function run2(root, executable, args, env = {}) {
27734
27735
  };
27735
27736
  }
27736
27737
 
27738
+ // packages/workit-core/src/hooks/repeat-failure.ts
27739
+ import { createHash as createHash11 } from "node:crypto";
27740
+ var SAME_CALL_FAILED = "Same call failed twice:";
27741
+ var MAX_SESSIONS = 256;
27742
+ var stable = (value) => JSON.stringify(value, (_key, entry) => entry && typeof entry === "object" && !Array.isArray(entry) ? Object.fromEntries(Object.entries(entry).toSorted(([a], [b]) => a.localeCompare(b))) : entry) ?? "null";
27743
+ var hashOf = (call) => createHash11("sha256").update(call).digest("hex").slice(0, 32);
27744
+ var record3 = (memo, sessionId, call, failed, next) => {
27745
+ const previous = memo.get(sessionId);
27746
+ memo.delete(sessionId);
27747
+ if (!failed)
27748
+ return null;
27749
+ const hash = hashOf(call);
27750
+ memo.set(sessionId, hash);
27751
+ if (memo.size > MAX_SESSIONS)
27752
+ memo.delete(memo.keys().next().value);
27753
+ return previous === hash && next ? `${SAME_CALL_FAILED} ${next}` : null;
27754
+ };
27755
+ var isFailure = (result) => result !== null && typeof result === "object" && result.ok === false && typeof result.error === "string";
27756
+ var correctedPayload = (tool, result) => {
27757
+ const example = /Example: (\{.*\})\s*$/.exec(result.error)?.[1];
27758
+ if (example)
27759
+ return `${tool} ${example}`;
27760
+ const guidance = result.details?.guidance;
27761
+ return typeof guidance === "string" && guidance ? guidance : null;
27762
+ };
27763
+ var escalateToolFailure = (memo, sessionId, tool, input, result) => {
27764
+ const failed = isFailure(result);
27765
+ const line = record3(memo, sessionId, `tool\x00${tool}\x00${stable(input)}`, failed, failed ? correctedPayload(tool, result) : null);
27766
+ return line && failed ? { ...result, error: `${result.error}
27767
+ ${line}` } : result;
27768
+ };
27769
+
27737
27770
  // packages/workit-mcp/src/server.ts
27738
27771
  class McpCapabilityUnavailableError extends Error {
27739
27772
  capability;
@@ -27829,8 +27862,8 @@ var sanitizeFailure = (result, workspaceRoot) => {
27829
27862
  };
27830
27863
  return sanitize(result);
27831
27864
  };
27832
- var resultForClient = (result, workspaceRoot) => {
27833
- const safe = sanitizeFailure(result, workspaceRoot);
27865
+ var resultForClient = (result, workspaceRoot, escalate = (safe) => safe) => {
27866
+ const safe = escalate(sanitizeFailure(result, workspaceRoot));
27834
27867
  return {
27835
27868
  content: [{ type: "text", text: JSON.stringify(safe) }],
27836
27869
  structuredContent: safe,
@@ -27867,6 +27900,7 @@ function createMcpServer(host, contextProvider) {
27867
27900
  path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
27868
27901
  ].filter((file) => existsSync9(file)));
27869
27902
  let staleWarned = false;
27903
+ const failures = new Map;
27870
27904
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
27871
27905
  server.setRequestHandler(ListToolsRequestSchema, async () => {
27872
27906
  let attested = false;
@@ -27989,9 +28023,10 @@ function createMcpServer(host, contextProvider) {
27989
28023
  details: { operation: family }
27990
28024
  }, workspaceRoot);
27991
28025
  }
28026
+ const escalate = (safe) => escalateToolFailure(failures, context.caller.actor || "mcp", toolName, request.params.arguments, safe);
27992
28027
  const parsed = parseAdvertisedOperation(family, request.params.arguments, host);
27993
28028
  if (!parsed.ok)
27994
- return resultForClient(parsed, workspaceRoot);
28029
+ return resultForClient(parsed, workspaceRoot, escalate);
27995
28030
  if (context.callerAttested !== true && requiresCallerIdentity(parsed.data))
27996
28031
  return resultForClient({
27997
28032
  ok: false,
@@ -28003,7 +28038,7 @@ function createMcpServer(host, contextProvider) {
28003
28038
  const core = new WorkitCore(new TaskStore(context.root), context);
28004
28039
  const run = core[family];
28005
28040
  const result = run.call(core, parsed.data);
28006
- return resultForClient(family === "task" && context.callerAttested !== true ? briefInspectResult(parsed.data, result) : result, workspaceRoot);
28041
+ return resultForClient(family === "task" && context.callerAttested !== true ? briefInspectResult(parsed.data, result) : result, workspaceRoot, escalate);
28007
28042
  } catch (error) {
28008
28043
  return thrownResult(toolName, error, workspaceRoot);
28009
28044
  }
@@ -17905,7 +17905,14 @@ var sessionMarkerFile = (input, session, store) => {
17905
17905
  return path21.join(dir, "hooks", `skills-${name}.json`);
17906
17906
  };
17907
17907
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
17908
- var EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
17908
+ var EMPTY = {
17909
+ nudged: [],
17910
+ loaded: [],
17911
+ raw: [],
17912
+ stops: [],
17913
+ judges: [],
17914
+ model: null
17915
+ };
17909
17916
  var readRaw = (file) => {
17910
17917
  try {
17911
17918
  return fs16.readFileSync(file, "utf8");
@@ -17921,7 +17928,8 @@ var parseMarker = (text) => {
17921
17928
  loaded: list2(value.loaded),
17922
17929
  raw: list2(value.raw),
17923
17930
  stops: list2(value.stops),
17924
- judges: list2(value.judges)
17931
+ judges: list2(value.judges),
17932
+ model: typeof value.model === "string" ? value.model : null
17925
17933
  };
17926
17934
  } catch {
17927
17935
  return { ...EMPTY };
@@ -17966,6 +17974,18 @@ var trackJudge = (input, agentId, running) => {
17966
17974
  return { ...marker, judges: running ? [...rest, agentId] : rest };
17967
17975
  });
17968
17976
  };
17977
+ var modelSwitchedOnDisk = (input) => {
17978
+ const session = input.session.id;
17979
+ const model = input.model;
17980
+ const file = session && model ? sessionMarkerFile(input, session) : null;
17981
+ if (!file || !model)
17982
+ return false;
17983
+ const previous = readSessionMarker(file).model;
17984
+ if (previous === model)
17985
+ return false;
17986
+ updateSessionMarker(file, (marker) => ({ ...marker, model }));
17987
+ return previous !== null;
17988
+ };
17969
17989
 
17970
17990
  // packages/workit-core/src/hooks/shell-words.ts
17971
17991
  class ShellAnalysisError extends Error {
@@ -22908,7 +22928,9 @@ function decide(input, deps) {
22908
22928
  if (!usable2(descriptor.context.perTurn))
22909
22929
  return NONE6;
22910
22930
  const current = turnContextText(input, descriptor);
22911
- const text = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
22931
+ const turn = resendsOnChange(descriptor) ? changedTurnContext(input, current) : current;
22932
+ const text = input.model && modelSwitchedOnDisk(input) ? [invariantBootstrap(), turn].filter(Boolean).join(`
22933
+ `) : turn;
22912
22934
  return withContextLine(text ? { kind: "context", text } : NONE6, promptNudge(input, event.prompt));
22913
22935
  }
22914
22936
  case "shell.pre": {
@@ -23717,6 +23739,7 @@ var codexAdapter = {
23717
23739
  },
23718
23740
  permissionMode: input.permission_mode,
23719
23741
  transcriptPath: input.transcript_path,
23742
+ model: input.model,
23720
23743
  event: protocolEvent(input)
23721
23744
  }
23722
23745
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.32.0",
3
+ "version": "8.33.0",
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.32.0",
50
- "@brainervirus/workit-mcp": "^8.32.0"
49
+ "@brainervirus/workit-core": "^8.33.0",
50
+ "@brainervirus/workit-mcp": "^8.33.0"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"