@brainervirus/workit-cursor 8.28.0 → 8.29.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.28.0",
5
+ "version": "8.29.0",
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
@@ -14806,9 +14811,22 @@ function detectedChecks(root) {
14806
14811
  add(plain("test", ["make", "test"]));
14807
14812
  return checks;
14808
14813
  }
14814
+ function configFileFor(root) {
14815
+ const own = checksConfigFile(root);
14816
+ if (fs13.existsSync(own))
14817
+ return own;
14818
+ const common = git4(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
14819
+ if (!common || path18.basename(common) !== ".git")
14820
+ return own;
14821
+ const main = path18.dirname(common);
14822
+ if (path18.resolve(main) === path18.resolve(root))
14823
+ return own;
14824
+ const shared = checksConfigFile(main);
14825
+ return fs13.existsSync(shared) ? shared : own;
14826
+ }
14809
14827
  function loadCheckConfig(cwd) {
14810
14828
  const root = checkRoot(cwd);
14811
- const file = checksConfigFile(root);
14829
+ const file = configFileFor(root);
14812
14830
  const legacy = path18.basename(file) === LEGACY_CHECKS_FILE;
14813
14831
  const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
14814
14832
  const note = legacy ? {
@@ -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";
@@ -21557,9 +21645,22 @@ function detectedChecks(root) {
21557
21645
  return checks;
21558
21646
  }
21559
21647
  var GATES = ["testing", "verification"];
21648
+ function configFileFor(root) {
21649
+ const own = checksConfigFile(root);
21650
+ if (fs11.existsSync(own))
21651
+ return own;
21652
+ const common = git3(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
21653
+ if (!common || path13.basename(common) !== ".git")
21654
+ return own;
21655
+ const main = path13.dirname(common);
21656
+ if (path13.resolve(main) === path13.resolve(root))
21657
+ return own;
21658
+ const shared = checksConfigFile(main);
21659
+ return fs11.existsSync(shared) ? shared : own;
21660
+ }
21560
21661
  function loadCheckConfig(cwd) {
21561
21662
  const root = checkRoot(cwd);
21562
- const file = checksConfigFile(root);
21663
+ const file = configFileFor(root);
21563
21664
  const legacy = path13.basename(file) === LEGACY_CHECKS_FILE;
21564
21665
  const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
21565
21666
  const note = legacy ? {
@@ -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);
@@ -14847,9 +14853,22 @@ function detectedChecks(root) {
14847
14853
  return checks;
14848
14854
  }
14849
14855
  var GATES = ["testing", "verification"];
14856
+ function configFileFor(root) {
14857
+ const own = checksConfigFile(root);
14858
+ if (fs13.existsSync(own))
14859
+ return own;
14860
+ const common = git4(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
14861
+ if (!common || path18.basename(common) !== ".git")
14862
+ return own;
14863
+ const main = path18.dirname(common);
14864
+ if (path18.resolve(main) === path18.resolve(root))
14865
+ return own;
14866
+ const shared = checksConfigFile(main);
14867
+ return fs13.existsSync(shared) ? shared : own;
14868
+ }
14850
14869
  function loadCheckConfig(cwd) {
14851
14870
  const root = checkRoot(cwd);
14852
- const file = checksConfigFile(root);
14871
+ const file = configFileFor(root);
14853
14872
  const legacy = path18.basename(file) === LEGACY_CHECKS_FILE;
14854
14873
  const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
14855
14874
  const note = legacy ? {
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.29.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.28.0",
50
- "@brainervirus/workit-mcp": "^8.28.0"
49
+ "@brainervirus/workit-core": "^8.29.0",
50
+ "@brainervirus/workit-mcp": "^8.29.0"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"