@brainervirus/workit-cursor 8.28.0 → 8.28.1

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.28.0",
5
+ "version": "8.28.1",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -9739,11 +9739,15 @@ var withReleaseTracks = (workspaceRoot, policy) => {
9739
9739
  source,
9740
9740
  fingerprint
9741
9741
  };
9742
+ }, rethrowRuntimeBug = (error) => {
9743
+ if (error instanceof TypeError || error instanceof ReferenceError)
9744
+ throw error;
9742
9745
  }, validateBranchNameFor = (workspaceRoot, name) => {
9743
9746
  try {
9744
9747
  const resolved = branchPolicySnapshotFor(workspaceRoot);
9745
9748
  return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
9746
9749
  } catch (error) {
9750
+ rethrowRuntimeBug(error);
9747
9751
  const correction = "repair or select a valid workspace policy before creating a branch";
9748
9752
  return {
9749
9753
  ok: false,
@@ -11523,7 +11527,7 @@ var str2 = (d, values) => ({
11523
11527
  description: typeof description === "string" ? description : "",
11524
11528
  paths: ["."],
11525
11529
  exclusions: []
11526
- }), LISTS, ENVELOPE;
11530
+ }), LISTS, ENVELOPE, NOT_FLAT;
11527
11531
  var init_operation_input = __esm(() => {
11528
11532
  init_task_contract();
11529
11533
  scopeFields = {
@@ -11645,6 +11649,7 @@ var init_operation_input = __esm(() => {
11645
11649
  "expectedWorkspaceRevision",
11646
11650
  "judgment"
11647
11651
  ]);
11652
+ NOT_FLAT = new Set(["schemaVersion", "action", "workspaceId"]);
11648
11653
  });
11649
11654
 
11650
11655
  // packages/workit-core/src/core/policy/judgment.ts
@@ -15951,8 +15951,9 @@ function flatOperationJsonSchema(family, options = {}) {
15951
15951
  };
15952
15952
  const properties = { action: { type: "string", enum: actions } };
15953
15953
  const readField = (name) => name === "taskId" || (family === "task" ? READ_TASK_FIELDS.has(name) : family === "policy");
15954
+ const taken = (name) => family === "policy" || actions.some((action) => actionKeys(family, action)?.accepted.has(name));
15954
15955
  for (const [name, field] of Object.entries({ ...COMMON, ...spec.fields }))
15955
- if (options.readOnly ? readField(name) : !(family === "state" && name === "expectedRevision"))
15956
+ if (options.readOnly ? readField(name) : taken(name))
15956
15957
  properties[name] = property(field);
15957
15958
  return {
15958
15959
  $schema: "https://json-schema.org/draft/2020-12/schema",
@@ -16194,6 +16195,98 @@ function normalizeOperationInput(family, input, host) {
16194
16195
  request[key] = strings(request[key]);
16195
16196
  return request;
16196
16197
  }
16198
+ var defOf = (node) => node._zod.def;
16199
+ var unwrap = (node) => {
16200
+ let inner = node;
16201
+ while (["optional", "nullable"].includes(defOf(inner).type) && defOf(inner).innerType)
16202
+ inner = defOf(inner).innerType;
16203
+ return inner;
16204
+ };
16205
+ var FLAT_NAME = {
16206
+ authorityRefs: "refs",
16207
+ contentRefs: "refs",
16208
+ statedChoice: "choice",
16209
+ reviewContext: "reviewSession"
16210
+ };
16211
+ var NOT_FLAT = new Set(["schemaVersion", "action", "workspaceId"]);
16212
+ function actionKeys(family, action) {
16213
+ const options = advertisedOperationSchemas[family].options;
16214
+ const option = options.find((item) => {
16215
+ const literal = defOf(item).shape?.action;
16216
+ return literal._zod.def.values.includes(action);
16217
+ });
16218
+ if (!option)
16219
+ return null;
16220
+ const out = { accepted: new Set, required: [] };
16221
+ const walk = (shape, nested) => {
16222
+ for (const [key, node] of Object.entries(shape)) {
16223
+ if (NOT_FLAT.has(key) || nested && key === "taskId")
16224
+ continue;
16225
+ const inner = unwrap(node);
16226
+ const type = defOf(inner).type;
16227
+ const needed = !["optional", "nullable"].includes(defOf(node).type);
16228
+ if (key === "scope")
16229
+ for (const name of ["scope", "paths", "exclusions"])
16230
+ out.accepted.add(name);
16231
+ else if (type === "object" && key !== "bundle" && !(key in FLAT_NAME)) {
16232
+ out.accepted.add(key);
16233
+ walk(defOf(inner).shape, true);
16234
+ } else {
16235
+ const name = FLAT_NAME[key] ?? key;
16236
+ out.accepted.add(name);
16237
+ if (needed && type !== "array" && type !== "record" && !out.required.includes(name))
16238
+ out.required.push(name);
16239
+ }
16240
+ }
16241
+ };
16242
+ walk(defOf(option).shape, false);
16243
+ return out;
16244
+ }
16245
+ function exampleOperation(family, action) {
16246
+ const keys = actionKeys(family, action);
16247
+ const example = { action };
16248
+ for (const name of keys?.required ?? [])
16249
+ example[name] = FLAT[family].fields[name]?.enum?.[0] ?? `<${name}>`;
16250
+ if (family === "policy" && !keys?.required.length && action !== "explain")
16251
+ example.riskTier = "normal";
16252
+ return example;
16253
+ }
16254
+ var oneOf = (values) => values.join(" | ");
16255
+ function invalidOperation(family, input, error) {
16256
+ const request = isObject2(input) ? input : {};
16257
+ const action = typeof request.action === "string" ? request.action : "";
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
+ });
16263
+ const own = actionKeys(family, action);
16264
+ const fields = [];
16265
+ const sentence = [];
16266
+ for (const issue of error.issues) {
16267
+ if (issue.code === "unrecognized_keys") {
16268
+ for (const key of issue.keys) {
16269
+ const home = actions.find((other) => other !== action && actionKeys(family, other).accepted.has(key));
16270
+ const reason = home ? `${key} belongs to action: ${home}` : `${key} is not a field of ${family} ${action}; it takes ${[...own.accepted].join(", ")}`;
16271
+ fields.push({ path: key, reason });
16272
+ sentence.push(reason);
16273
+ }
16274
+ continue;
16275
+ }
16276
+ const last = String(issue.path.at(-1) ?? "");
16277
+ const name = Object.entries(FLAT_NAME).find(([contract]) => contract === last)?.[1] ?? last;
16278
+ const missing = issue.code === "invalid_type" && /received undefined/.test(issue.message);
16279
+ const absent = own.required.filter((key) => !(key in request));
16280
+ const needs = missing && issue.path.length === 1 && absent.length ? absent.join(", ") : name;
16281
+ const reason = missing ? `${family} ${action} requires ${needs}` : `${name}: ${issue.message}`;
16282
+ fields.push({ path: issue.path.join("."), reason });
16283
+ sentence.push(reason);
16284
+ }
16285
+ const example = JSON.stringify(exampleOperation(family, action));
16286
+ return failure2("invalid_input", `${[...new Set(sentence)].join("; ")}. Example: ${example}`, {
16287
+ fields
16288
+ });
16289
+ }
16197
16290
  function parseAdvertisedOperation(family, input, host) {
16198
16291
  const request = normalizeOperationInput(family, input, host);
16199
16292
  if (isObject2(request) && request.schemaVersion !== SCHEMA_VERSION)
@@ -16201,12 +16294,7 @@ function parseAdvertisedOperation(family, input, host) {
16201
16294
  const parsed = advertisedOperationSchemas[family].safeParse(request);
16202
16295
  if (parsed.success)
16203
16296
  return success(null, null, request);
16204
- return failure2("invalid_input", "operation input is invalid", {
16205
- fields: parsed.error.issues.map((issue) => ({
16206
- path: issue.code === "unrecognized_keys" ? issue.keys.join(".") : issue.path.join("."),
16207
- reason: issue.message
16208
- }))
16209
- });
16297
+ return invalidOperation(family, request, parsed.error);
16210
16298
  }
16211
16299
  // packages/workit-core/src/core/task-store.ts
16212
16300
  import { createHash as createHash8, randomUUID as randomUUID3 } from "node:crypto";
@@ -9728,11 +9728,16 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
9728
9728
  fingerprint
9729
9729
  };
9730
9730
  };
9731
+ var rethrowRuntimeBug = (error) => {
9732
+ if (error instanceof TypeError || error instanceof ReferenceError)
9733
+ throw error;
9734
+ };
9731
9735
  var validateBranchNameFor = (workspaceRoot, name) => {
9732
9736
  try {
9733
9737
  const resolved = branchPolicySnapshotFor(workspaceRoot);
9734
9738
  return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
9735
9739
  } catch (error) {
9740
+ rethrowRuntimeBug(error);
9736
9741
  const correction = "repair or select a valid workspace policy before creating a branch";
9737
9742
  return {
9738
9743
  ok: false,
@@ -11636,6 +11641,7 @@ function normalizeOperationInput(family, input, host) {
11636
11641
  request[key] = strings(request[key]);
11637
11642
  return request;
11638
11643
  }
11644
+ var NOT_FLAT = new Set(["schemaVersion", "action", "workspaceId"]);
11639
11645
 
11640
11646
  // packages/workit-core/src/core/policy/judgment.ts
11641
11647
  var isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
package/hooks/launch.mjs CHANGED
@@ -15,6 +15,7 @@
15
15
  // failure, npx network error, timeout, a crash) prints `{}`, exits 0 and
16
16
  // writes one `[workit] Cursor hook unavailable: …` line on stderr. Only a
17
17
  // policy deny from the hook itself (exit 2 with Cursor's deny JSON) blocks.
18
+ import { readFileSync } from "node:fs";
18
19
  import path from "node:path";
19
20
  import { fileURLToPath } from "node:url";
20
21
  import {
@@ -25,6 +26,35 @@ import {
25
26
 
26
27
  const pluginRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
27
28
 
29
+ // A Node below this package's own engines minimum cannot run the bundled hook:
30
+ // fail open with one clear line. WORKIT_HOOK_NODE_VERSION stands in for
31
+ // process.versions.node (tests). An unreadable minimum never blocks.
32
+ const nodeFloorMessage = () => {
33
+ try {
34
+ const found = process.env.WORKIT_HOOK_NODE_VERSION || process.versions.node;
35
+ const range = JSON.parse(readFileSync(path.join(pluginRoot, "package.json"), "utf8")).engines
36
+ ?.node;
37
+ const min = /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(String(range ?? ""));
38
+ if (!min) return null;
39
+ const need = [min[1], min[2] ?? 0, min[3] ?? 0].map(Number);
40
+ const have = String(found).replace(/^v/, "").split(".").map(Number);
41
+ for (let i = 0; i < 3; i++) {
42
+ const a = have[i] ?? 0;
43
+ if (Number.isNaN(a)) return null;
44
+ if (a !== need[i]) return a < need[i] ? `needs Node ${range}, found ${found}` : null;
45
+ }
46
+ return null;
47
+ } catch {
48
+ return null;
49
+ }
50
+ };
51
+ const tooOld = nodeFloorMessage();
52
+ if (tooOld && process.argv[2] !== "--probe") {
53
+ process.stderr.write(`[workit] Cursor hook unavailable: ${tooOld}\n`);
54
+ process.stdout.write("{}\n");
55
+ process.exit(0);
56
+ }
57
+
28
58
  // `--probe <bin>` (for `workit doctor`): run one no-op preCompact through
29
59
  // the candidate Cursor would use and print which one it was and how it went.
30
60
  if (process.argv[2] === "--probe") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.28.0",
3
+ "version": "8.28.1",
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.28.0",
50
- "@brainervirus/workit-mcp": "^8.28.0"
49
+ "@brainervirus/workit-core": "^8.28.1",
50
+ "@brainervirus/workit-mcp": "^8.28.1"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"