@brainervirus/workit-cursor 8.31.1 → 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.31.1",
5
+ "version": "8.33.0",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -8261,6 +8261,7 @@ var init_workspaces = __esm(() => {
8261
8261
  verification: _enum(["proportional", "self", "independent"]).optional(),
8262
8262
  delegation: unknown().optional(),
8263
8263
  trailers: boolean2().optional(),
8264
+ deleteBranch: boolean2().optional(),
8264
8265
  liveSessionGuard: boolean2().optional(),
8265
8266
  fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
8266
8267
  models: object({ roles: unknown().optional() }).passthrough().optional(),
@@ -17848,7 +17849,8 @@ var sessionMarkerFile = (input, session, store) => {
17848
17849
  loaded: list2(value.loaded),
17849
17850
  raw: list2(value.raw),
17850
17851
  stops: list2(value.stops),
17851
- judges: list2(value.judges)
17852
+ judges: list2(value.judges),
17853
+ model: typeof value.model === "string" ? value.model : null
17852
17854
  };
17853
17855
  } catch {
17854
17856
  return { ...EMPTY };
@@ -17887,10 +17889,28 @@ var sessionMarkerFile = (input, session, store) => {
17887
17889
  const rest = marker.judges.filter((id) => id !== agentId);
17888
17890
  return { ...marker, judges: running ? [...rest, agentId] : rest };
17889
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;
17890
17903
  };
17891
17904
  var init_session_marker = __esm(() => {
17892
17905
  init_paths();
17893
- EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
17906
+ EMPTY = {
17907
+ nudged: [],
17908
+ loaded: [],
17909
+ raw: [],
17910
+ stops: [],
17911
+ judges: [],
17912
+ model: null
17913
+ };
17894
17914
  });
17895
17915
 
17896
17916
  // packages/workit-core/src/hooks/shell-words.ts
@@ -22642,7 +22662,9 @@ function decide(input, deps) {
22642
22662
  if (!usable2(descriptor.context.perTurn))
22643
22663
  return NONE6;
22644
22664
  const current = turnContextText(input, descriptor);
22645
- 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;
22646
22668
  return withContextLine(text ? { kind: "context", text } : NONE6, promptNudge(input, event.prompt));
22647
22669
  }
22648
22670
  case "shell.pre": {
@@ -22818,6 +22840,7 @@ var init_handle = __esm(() => {
22818
22840
  init_spawn_gate();
22819
22841
  init_standing();
22820
22842
  init_session_marker();
22843
+ init_methods();
22821
22844
  init_stop();
22822
22845
  init_live_session();
22823
22846
  init_write_gate();
@@ -23492,6 +23515,7 @@ var init_codex = __esm(() => {
23492
23515
  },
23493
23516
  permissionMode: input.permission_mode,
23494
23517
  transcriptPath: input.transcript_path,
23518
+ model: input.model,
23495
23519
  event: protocolEvent(input)
23496
23520
  }
23497
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 = [];
@@ -17331,6 +17332,7 @@ var workspaceConfigSchema = object2({
17331
17332
  verification: _enum(["proportional", "self", "independent"]).optional(),
17332
17333
  delegation: unknown().optional(),
17333
17334
  trailers: boolean2().optional(),
17335
+ deleteBranch: boolean2().optional(),
17334
17336
  liveSessionGuard: boolean2().optional(),
17335
17337
  fanout: object2({ tierModels: unknown().optional() }).passthrough().optional(),
17336
17338
  models: object2({ roles: unknown().optional() }).passthrough().optional(),
@@ -27733,6 +27735,38 @@ function run2(root, executable, args, env = {}) {
27733
27735
  };
27734
27736
  }
27735
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
+
27736
27770
  // packages/workit-mcp/src/server.ts
27737
27771
  class McpCapabilityUnavailableError extends Error {
27738
27772
  capability;
@@ -27828,8 +27862,8 @@ var sanitizeFailure = (result, workspaceRoot) => {
27828
27862
  };
27829
27863
  return sanitize(result);
27830
27864
  };
27831
- var resultForClient = (result, workspaceRoot) => {
27832
- const safe = sanitizeFailure(result, workspaceRoot);
27865
+ var resultForClient = (result, workspaceRoot, escalate = (safe) => safe) => {
27866
+ const safe = escalate(sanitizeFailure(result, workspaceRoot));
27833
27867
  return {
27834
27868
  content: [{ type: "text", text: JSON.stringify(safe) }],
27835
27869
  structuredContent: safe,
@@ -27866,6 +27900,7 @@ function createMcpServer(host, contextProvider) {
27866
27900
  path23.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
27867
27901
  ].filter((file) => existsSync9(file)));
27868
27902
  let staleWarned = false;
27903
+ const failures = new Map;
27869
27904
  const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
27870
27905
  server.setRequestHandler(ListToolsRequestSchema, async () => {
27871
27906
  let attested = false;
@@ -27988,9 +28023,10 @@ function createMcpServer(host, contextProvider) {
27988
28023
  details: { operation: family }
27989
28024
  }, workspaceRoot);
27990
28025
  }
28026
+ const escalate = (safe) => escalateToolFailure(failures, context.caller.actor || "mcp", toolName, request.params.arguments, safe);
27991
28027
  const parsed = parseAdvertisedOperation(family, request.params.arguments, host);
27992
28028
  if (!parsed.ok)
27993
- return resultForClient(parsed, workspaceRoot);
28029
+ return resultForClient(parsed, workspaceRoot, escalate);
27994
28030
  if (context.callerAttested !== true && requiresCallerIdentity(parsed.data))
27995
28031
  return resultForClient({
27996
28032
  ok: false,
@@ -28002,7 +28038,7 @@ function createMcpServer(host, contextProvider) {
28002
28038
  const core = new WorkitCore(new TaskStore(context.root), context);
28003
28039
  const run = core[family];
28004
28040
  const result = run.call(core, parsed.data);
28005
- 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);
28006
28042
  } catch (error) {
28007
28043
  return thrownResult(toolName, error, workspaceRoot);
28008
28044
  }
@@ -7861,6 +7861,7 @@ var workspaceConfigSchema = object({
7861
7861
  verification: _enum(["proportional", "self", "independent"]).optional(),
7862
7862
  delegation: unknown().optional(),
7863
7863
  trailers: boolean2().optional(),
7864
+ deleteBranch: boolean2().optional(),
7864
7865
  liveSessionGuard: boolean2().optional(),
7865
7866
  fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
7866
7867
  models: object({ roles: unknown().optional() }).passthrough().optional(),
@@ -17904,7 +17905,14 @@ var sessionMarkerFile = (input, session, store) => {
17904
17905
  return path21.join(dir, "hooks", `skills-${name}.json`);
17905
17906
  };
17906
17907
  var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
17907
- var EMPTY = { nudged: [], loaded: [], raw: [], stops: [], judges: [] };
17908
+ var EMPTY = {
17909
+ nudged: [],
17910
+ loaded: [],
17911
+ raw: [],
17912
+ stops: [],
17913
+ judges: [],
17914
+ model: null
17915
+ };
17908
17916
  var readRaw = (file) => {
17909
17917
  try {
17910
17918
  return fs16.readFileSync(file, "utf8");
@@ -17920,7 +17928,8 @@ var parseMarker = (text) => {
17920
17928
  loaded: list2(value.loaded),
17921
17929
  raw: list2(value.raw),
17922
17930
  stops: list2(value.stops),
17923
- judges: list2(value.judges)
17931
+ judges: list2(value.judges),
17932
+ model: typeof value.model === "string" ? value.model : null
17924
17933
  };
17925
17934
  } catch {
17926
17935
  return { ...EMPTY };
@@ -17965,6 +17974,18 @@ var trackJudge = (input, agentId, running) => {
17965
17974
  return { ...marker, judges: running ? [...rest, agentId] : rest };
17966
17975
  });
17967
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
+ };
17968
17989
 
17969
17990
  // packages/workit-core/src/hooks/shell-words.ts
17970
17991
  class ShellAnalysisError extends Error {
@@ -22907,7 +22928,9 @@ function decide(input, deps) {
22907
22928
  if (!usable2(descriptor.context.perTurn))
22908
22929
  return NONE6;
22909
22930
  const current = turnContextText(input, descriptor);
22910
- 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;
22911
22934
  return withContextLine(text ? { kind: "context", text } : NONE6, promptNudge(input, event.prompt));
22912
22935
  }
22913
22936
  case "shell.pre": {
@@ -23716,6 +23739,7 @@ var codexAdapter = {
23716
23739
  },
23717
23740
  permissionMode: input.permission_mode,
23718
23741
  transcriptPath: input.transcript_path,
23742
+ model: input.model,
23719
23743
  event: protocolEvent(input)
23720
23744
  }
23721
23745
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.31.1",
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.31.1",
50
- "@brainervirus/workit-mcp": "^8.31.1"
49
+ "@brainervirus/workit-core": "^8.33.0",
50
+ "@brainervirus/workit-mcp": "^8.33.0"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"