@brainervirus/workit-cursor 1.3.0 → 1.3.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": "1.3.0",
5
+ "version": "1.3.2",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -10270,6 +10270,26 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
10270
10270
  return glob;
10271
10271
  const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
10272
10272
  return real + (prefix.endsWith("/") ? "/" : "") + rest;
10273
+ }, globSpecificity = (glob) => glob.replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0 && !/[*?[\]{]/.test(segment)).length, selectWorkspaceMatch = (matches, cwd, workspaceName) => {
10274
+ if (workspaceName !== undefined) {
10275
+ const named = matches.filter((entry) => entry.name === workspaceName);
10276
+ if (named.length === 1)
10277
+ return named[0];
10278
+ if (named.length > 1)
10279
+ throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
10280
+ if (matches.length > 0) {
10281
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
10282
+ }
10283
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10284
+ }
10285
+ if (matches.length < 2)
10286
+ return matches[0];
10287
+ const highestSpecificity = Math.max(...matches.map((entry) => globSpecificity(entry.glob)));
10288
+ const mostSpecific = matches.filter((entry) => globSpecificity(entry.glob) === highestSpecificity);
10289
+ if (mostSpecific.length > 1) {
10290
+ throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
10291
+ }
10292
+ return mostSpecific[0];
10273
10293
  }, resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10274
10294
  const result = readWorkspacesResult(dir);
10275
10295
  if (result.status === "malformed" || result.status === "invalid")
@@ -10289,20 +10309,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
10289
10309
  if (matched)
10290
10310
  matches.push(ws);
10291
10311
  }
10292
- if (workspaceName !== undefined) {
10293
- const selected = matches.find((ws) => ws.name === workspaceName);
10294
- if (!selected && matches.length > 0) {
10295
- const matchingNames = matches.map((ws) => ws.name);
10296
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matchingNames.join(", ")}`);
10297
- }
10298
- if (selected)
10299
- return selected;
10300
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10301
- }
10302
- if (matches.length > 1) {
10303
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((ws) => ws.name).join(", ")}`);
10304
- }
10305
- return matches[0] ?? null;
10312
+ return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
10306
10313
  }, runtimeWorkspacePolicySchema = (kind) => {
10307
10314
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
10308
10315
  const policySchema = kind === "branch" ? workspaceBranchPolicySchema : kind === "commit" ? workspaceCommitPolicySchema : object({
@@ -10353,21 +10360,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
10353
10360
  return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
10354
10361
  });
10355
10362
  const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
10356
- let selected;
10357
- if (workspaceName) {
10358
- const named = matches.filter((entry) => entry.name === workspaceName);
10359
- if (named.length === 1)
10360
- selected = named[0];
10361
- else if (named.length > 1)
10362
- throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
10363
- else if (matches.length)
10364
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
10365
- else
10366
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10367
- } else if (matches.length > 1)
10368
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((entry) => entry.name).join(", ")}`);
10369
- else
10370
- selected = matches[0];
10363
+ const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
10371
10364
  if (!selected)
10372
10365
  return null;
10373
10366
  const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
@@ -11905,6 +11898,15 @@ need zero Workit task, assessment, or writer calls. Use one compact tracked
11905
11898
  record only when handoff, dependent steps, concurrent actors, or meaningful
11906
11899
  decisions make continuity useful; similar titles alone never merge tasks.
11907
11900
 
11901
+ For a routine user-authorized branch or commit, prefer native host Git/shell
11902
+ tools from the outset when managed coordination or outcome reconciliation is
11903
+ not needed. Inspect the actual target checkout and its configured conventions;
11904
+ use Workit's read-only context/policy tools when needed. Do not start a task,
11905
+ acquire a writer, or mint a decision receipt solely for a native Git action.
11906
+ Native permissions still apply. Never switch execution paths to evade a denial
11907
+ or repeat an uncertain managed effect. A local-commit endpoint does not imply
11908
+ PR readiness, a fresh review, or post-commit assessment/closure paperwork.
11909
+
11908
11910
  For tracked work, inspect its current state and use the shared operations for
11909
11911
  task, policy, evidence, finding, decision, worker, writer, and state changes.
11910
11912
  Start a record once for an explicit tracked objective; assess or reassess only
@@ -11926,6 +11928,11 @@ Preserve uncertain external outcomes and reconcile repository/provider state
11926
11928
  before retrying. Internal reservations prevent duplicate or ambiguous effects;
11927
11929
  they are not permission tickets for every edit.
11928
11930
 
11931
+ On OpenCode V1 and V2, use native host tools for external mutations. Workit
11932
+ provides read-only workit_context; it has no managed external-action executor.
11933
+ Do not create proposals or request Workit approvals merely to invoke native
11934
+ tools. Old uncertain managed effects still require evidence before any retry.
11935
+
11929
11936
  Use host-native authorization through the host's supported path. A native
11930
11937
  question receipt records an actual question interaction; it is not automatic
11931
11938
  host permission. Record a meaningful user choice once with provenance when
@@ -12266,6 +12273,7 @@ function resolveRequirements(input) {
12266
12273
  dependentAction: null,
12267
12274
  acceptanceAllowed: false
12268
12275
  }));
12276
+ const independentBehaviorReview = input.preferences?.thorough === true || input.assessment.consequences.some((consequence) => ["security", "data", "public_contract", "operations"].includes(consequence.area));
12269
12277
  if (signals.behaviorChange.value === true)
12270
12278
  requirements.push(requirement({
12271
12279
  ruleId: "behavioral-verification",
@@ -12277,14 +12285,14 @@ function resolveRequirements(input) {
12277
12285
  dependentAction: null,
12278
12286
  acceptanceAllowed: false
12279
12287
  }), requirement({
12280
- ruleId: "fresh-context-review",
12288
+ ruleId: independentBehaviorReview ? "fresh-context-review" : "self-review",
12281
12289
  dimension: "review",
12282
12290
  scope,
12283
- reason: "A non-mechanical behavior change requires fresh-context review.",
12284
- satisfaction: "A separate review context examines the current candidate and records its result.",
12291
+ reason: independentBehaviorReview ? "Consequential behavior or the thorough preference requires fresh-context review." : "Bounded behavior changes use self-review unless consequential risks or trusted rules require more.",
12292
+ satisfaction: independentBehaviorReview ? "A separate review context examines the current candidate and records its result." : "The lead reviews the resulting diff and records the relevant scope and checks.",
12285
12293
  before: "close",
12286
12294
  dependentAction: null,
12287
- acceptanceAllowed: false
12295
+ acceptanceAllowed: !independentBehaviorReview
12288
12296
  }));
12289
12297
  else if (signals.mechanicalLowRisk.value === true)
12290
12298
  requirements.push(requirement({
@@ -20757,7 +20757,47 @@ function operationJsonSchema(family) {
20757
20757
  return toJSONSchema(operationSchemas[family], { target: "draft-2020-12" });
20758
20758
  }
20759
20759
  var OPERATION_SCHEMA_DEPTH = 1;
20760
- var canonicalFieldsDescription = (fields) => `Canonical object fields: ${fields.join(", ")}. Workit validates the complete nested value.`;
20760
+ var schemaShapeDescription = (value, depth = 0) => {
20761
+ if (!value || typeof value !== "object")
20762
+ return "value";
20763
+ const schema = value;
20764
+ if (Array.isArray(schema.oneOf) || Array.isArray(schema.anyOf)) {
20765
+ const options = Array.isArray(schema.oneOf) ? schema.oneOf : schema.anyOf;
20766
+ return `(${options.map((option) => schemaShapeDescription(option, depth)).join("|")})`;
20767
+ }
20768
+ if (schema.const !== undefined)
20769
+ return `=${JSON.stringify(schema.const)}`;
20770
+ if (Array.isArray(schema.enum))
20771
+ return `[${schema.enum.map(String).join("|")}]`;
20772
+ const type = Array.isArray(schema.type) ? schema.type.join("/") : schema.type;
20773
+ if (type === "array")
20774
+ return `arr<${schemaShapeDescription(schema.items, depth)}>`;
20775
+ if (type === "object" && schema.properties && typeof schema.properties === "object") {
20776
+ if (depth >= 2)
20777
+ return "obj";
20778
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
20779
+ const properties = schema.properties;
20780
+ const fields = Object.entries(properties).map(([name, child]) => `${name}${required.has(name) ? "!" : ""}:${schemaShapeDescription(child, depth + 1)}`);
20781
+ return `obj{${fields.join(",")}}`;
20782
+ }
20783
+ if (typeof type !== "string")
20784
+ return "?";
20785
+ return type.split("/").map((part) => ({ string: "str", boolean: "bool", number: "num", null: "null" })[part] ?? part).join("|");
20786
+ };
20787
+ var canonicalFieldsDescription = (value) => {
20788
+ if (Array.isArray(value))
20789
+ return `Canonical object fields: ${value.join(", ")}. Workit validates the complete nested value.`;
20790
+ const isZodType = (schema) => ("_zod" in schema) && typeof schema._zod === "object";
20791
+ const schema = isZodType(value) ? toJSONSchema(value, { target: "draft-2020-12" }) : value;
20792
+ if (!schema.properties || typeof schema.properties !== "object") {
20793
+ const variants = Array.isArray(schema.oneOf) ? schema.oneOf : Array.isArray(schema.anyOf) ? schema.anyOf : null;
20794
+ return variants ? `Canonical shapes: ${variants.map((variant) => schemaShapeDescription(variant)).join(" | ")}. Full nested value is validated.` : "Canonical nested value; Workit validates the complete value.";
20795
+ }
20796
+ const properties = schema.properties;
20797
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
20798
+ const fields = Object.entries(properties).map(([name, child]) => `${name}${required.has(name) ? "!" : ""}:${schemaShapeDescription(child)}`);
20799
+ return `Fields (! required): ${fields.join(", ")}. Full nested value is validated.`;
20800
+ };
20761
20801
  function boundedOperationJsonSchema(family, maxDepth = OPERATION_SCHEMA_DEPTH, stringifiedObjects = false) {
20762
20802
  const tolerate = (projected) => {
20763
20803
  if (!stringifiedObjects)
@@ -20781,9 +20821,10 @@ function boundedOperationJsonSchema(family, maxDepth = OPERATION_SCHEMA_DEPTH, s
20781
20821
  return node;
20782
20822
  const record = node;
20783
20823
  if (record.properties && typeof record.properties === "object") {
20784
- const fields = Object.keys(record.properties);
20824
+ const properties = record.properties;
20825
+ const fields = Object.keys(properties);
20785
20826
  if (currentDepth >= maxDepth || fields.length === 0) {
20786
- const description = stringifiedObjects ? `${canonicalFieldsDescription(fields)} A JSON-encoded string is also accepted.` : canonicalFieldsDescription(fields);
20827
+ const description = stringifiedObjects ? `${canonicalFieldsDescription(record)} A JSON-encoded string is also accepted.` : canonicalFieldsDescription(record);
20787
20828
  return tolerate({ type: "object", description });
20788
20829
  }
20789
20830
  return tolerate({
@@ -23075,6 +23116,28 @@ var canonicalGlob = (glob) => {
23075
23116
  const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
23076
23117
  return real + (prefix.endsWith("/") ? "/" : "") + rest;
23077
23118
  };
23119
+ var globSpecificity = (glob) => glob.replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0 && !/[*?[\]{]/.test(segment)).length;
23120
+ var selectWorkspaceMatch = (matches, cwd, workspaceName) => {
23121
+ if (workspaceName !== undefined) {
23122
+ const named = matches.filter((entry) => entry.name === workspaceName);
23123
+ if (named.length === 1)
23124
+ return named[0];
23125
+ if (named.length > 1)
23126
+ throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
23127
+ if (matches.length > 0) {
23128
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
23129
+ }
23130
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
23131
+ }
23132
+ if (matches.length < 2)
23133
+ return matches[0];
23134
+ const highestSpecificity = Math.max(...matches.map((entry) => globSpecificity(entry.glob)));
23135
+ const mostSpecific = matches.filter((entry) => globSpecificity(entry.glob) === highestSpecificity);
23136
+ if (mostSpecific.length > 1) {
23137
+ throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
23138
+ }
23139
+ return mostSpecific[0];
23140
+ };
23078
23141
  var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
23079
23142
  const result = readWorkspacesResult(dir);
23080
23143
  if (result.status === "malformed" || result.status === "invalid")
@@ -23094,20 +23157,7 @@ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
23094
23157
  if (matched)
23095
23158
  matches.push(ws);
23096
23159
  }
23097
- if (workspaceName !== undefined) {
23098
- const selected = matches.find((ws) => ws.name === workspaceName);
23099
- if (!selected && matches.length > 0) {
23100
- const matchingNames = matches.map((ws) => ws.name);
23101
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matchingNames.join(", ")}`);
23102
- }
23103
- if (selected)
23104
- return selected;
23105
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
23106
- }
23107
- if (matches.length > 1) {
23108
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((ws) => ws.name).join(", ")}`);
23109
- }
23110
- return matches[0] ?? null;
23160
+ return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
23111
23161
  };
23112
23162
  var runtimeWorkspacePolicySchema = (kind) => {
23113
23163
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
@@ -23164,21 +23214,7 @@ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
23164
23214
  return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
23165
23215
  });
23166
23216
  const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
23167
- let selected;
23168
- if (workspaceName) {
23169
- const named = matches.filter((entry) => entry.name === workspaceName);
23170
- if (named.length === 1)
23171
- selected = named[0];
23172
- else if (named.length > 1)
23173
- throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
23174
- else if (matches.length)
23175
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
23176
- else
23177
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
23178
- } else if (matches.length > 1)
23179
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((entry) => entry.name).join(", ")}`);
23180
- else
23181
- selected = matches[0];
23217
+ const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
23182
23218
  if (!selected)
23183
23219
  return null;
23184
23220
  const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
@@ -25107,6 +25143,7 @@ function resolveRequirements(input) {
25107
25143
  dependentAction: null,
25108
25144
  acceptanceAllowed: false
25109
25145
  }));
25146
+ const independentBehaviorReview = input.preferences?.thorough === true || input.assessment.consequences.some((consequence) => ["security", "data", "public_contract", "operations"].includes(consequence.area));
25110
25147
  if (signals.behaviorChange.value === true)
25111
25148
  requirements.push(requirement({
25112
25149
  ruleId: "behavioral-verification",
@@ -25118,14 +25155,14 @@ function resolveRequirements(input) {
25118
25155
  dependentAction: null,
25119
25156
  acceptanceAllowed: false
25120
25157
  }), requirement({
25121
- ruleId: "fresh-context-review",
25158
+ ruleId: independentBehaviorReview ? "fresh-context-review" : "self-review",
25122
25159
  dimension: "review",
25123
25160
  scope,
25124
- reason: "A non-mechanical behavior change requires fresh-context review.",
25125
- satisfaction: "A separate review context examines the current candidate and records its result.",
25161
+ reason: independentBehaviorReview ? "Consequential behavior or the thorough preference requires fresh-context review." : "Bounded behavior changes use self-review unless consequential risks or trusted rules require more.",
25162
+ satisfaction: independentBehaviorReview ? "A separate review context examines the current candidate and records its result." : "The lead reviews the resulting diff and records the relevant scope and checks.",
25126
25163
  before: "close",
25127
25164
  dependentAction: null,
25128
- acceptanceAllowed: false
25165
+ acceptanceAllowed: !independentBehaviorReview
25129
25166
  }));
25130
25167
  else if (signals.mechanicalLowRisk.value === true)
25131
25168
  requirements.push(requirement({
@@ -27694,7 +27731,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
27694
27731
  - Entries should be human-readable and user-facing.
27695
27732
  - Do not use raw commit messages as changelog bullets.
27696
27733
  - MERGE into existing ### Category under [Unreleased] — never append a second ### Added / ### Fixed block.
27697
- - Apply with the native workit_changelog_apply tool only (not hand-edits under Unreleased).
27734
+ - Apply with the host-native editor, preserving the repository changelog conventions.
27698
27735
  - If Unreleased already has duplicate category headings, normalize_only first.`;
27699
27736
  function changelogContext(root, range) {
27700
27737
  const cwd = path13.resolve(repoRoot(root));
@@ -10300,6 +10300,28 @@ var canonicalGlob = (glob) => {
10300
10300
  const real = realpathOf(prefix.replace(/\/+$/, "") || "/");
10301
10301
  return real + (prefix.endsWith("/") ? "/" : "") + rest;
10302
10302
  };
10303
+ var globSpecificity = (glob) => glob.replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0 && !/[*?[\]{]/.test(segment)).length;
10304
+ var selectWorkspaceMatch = (matches, cwd, workspaceName) => {
10305
+ if (workspaceName !== undefined) {
10306
+ const named = matches.filter((entry) => entry.name === workspaceName);
10307
+ if (named.length === 1)
10308
+ return named[0];
10309
+ if (named.length > 1)
10310
+ throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
10311
+ if (matches.length > 0) {
10312
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
10313
+ }
10314
+ throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10315
+ }
10316
+ if (matches.length < 2)
10317
+ return matches[0];
10318
+ const highestSpecificity = Math.max(...matches.map((entry) => globSpecificity(entry.glob)));
10319
+ const mostSpecific = matches.filter((entry) => globSpecificity(entry.glob) === highestSpecificity);
10320
+ if (mostSpecific.length > 1) {
10321
+ throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
10322
+ }
10323
+ return mostSpecific[0];
10324
+ };
10303
10325
  var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10304
10326
  const result = readWorkspacesResult(dir);
10305
10327
  if (result.status === "malformed" || result.status === "invalid")
@@ -10319,20 +10341,7 @@ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10319
10341
  if (matched)
10320
10342
  matches.push(ws);
10321
10343
  }
10322
- if (workspaceName !== undefined) {
10323
- const selected = matches.find((ws) => ws.name === workspaceName);
10324
- if (!selected && matches.length > 0) {
10325
- const matchingNames = matches.map((ws) => ws.name);
10326
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matchingNames.join(", ")}`);
10327
- }
10328
- if (selected)
10329
- return selected;
10330
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10331
- }
10332
- if (matches.length > 1) {
10333
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((ws) => ws.name).join(", ")}`);
10334
- }
10335
- return matches[0] ?? null;
10344
+ return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
10336
10345
  };
10337
10346
  var runtimeWorkspacePolicySchema = (kind) => {
10338
10347
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
@@ -10389,21 +10398,7 @@ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
10389
10398
  return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
10390
10399
  });
10391
10400
  const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
10392
- let selected;
10393
- if (workspaceName) {
10394
- const named = matches.filter((entry) => entry.name === workspaceName);
10395
- if (named.length === 1)
10396
- selected = named[0];
10397
- else if (named.length > 1)
10398
- throw new Error(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
10399
- else if (matches.length)
10400
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
10401
- else
10402
- throw new Error(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
10403
- } else if (matches.length > 1)
10404
- throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${matches.map((entry) => entry.name).join(", ")}`);
10405
- else
10406
- selected = matches[0];
10401
+ const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
10407
10402
  if (!selected)
10408
10403
  return null;
10409
10404
  const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
@@ -11844,6 +11839,15 @@ need zero Workit task, assessment, or writer calls. Use one compact tracked
11844
11839
  record only when handoff, dependent steps, concurrent actors, or meaningful
11845
11840
  decisions make continuity useful; similar titles alone never merge tasks.
11846
11841
 
11842
+ For a routine user-authorized branch or commit, prefer native host Git/shell
11843
+ tools from the outset when managed coordination or outcome reconciliation is
11844
+ not needed. Inspect the actual target checkout and its configured conventions;
11845
+ use Workit's read-only context/policy tools when needed. Do not start a task,
11846
+ acquire a writer, or mint a decision receipt solely for a native Git action.
11847
+ Native permissions still apply. Never switch execution paths to evade a denial
11848
+ or repeat an uncertain managed effect. A local-commit endpoint does not imply
11849
+ PR readiness, a fresh review, or post-commit assessment/closure paperwork.
11850
+
11847
11851
  For tracked work, inspect its current state and use the shared operations for
11848
11852
  task, policy, evidence, finding, decision, worker, writer, and state changes.
11849
11853
  Start a record once for an explicit tracked objective; assess or reassess only
@@ -11865,6 +11869,11 @@ Preserve uncertain external outcomes and reconcile repository/provider state
11865
11869
  before retrying. Internal reservations prevent duplicate or ambiguous effects;
11866
11870
  they are not permission tickets for every edit.
11867
11871
 
11872
+ On OpenCode V1 and V2, use native host tools for external mutations. Workit
11873
+ provides read-only workit_context; it has no managed external-action executor.
11874
+ Do not create proposals or request Workit approvals merely to invoke native
11875
+ tools. Old uncertain managed effects still require evidence before any retry.
11876
+
11868
11877
  Use host-native authorization through the host's supported path. A native
11869
11878
  question receipt records an actual question interaction; it is not automatic
11870
11879
  host permission. Record a meaningful user choice once with provenance when
@@ -12281,6 +12290,7 @@ function resolveRequirements(input) {
12281
12290
  dependentAction: null,
12282
12291
  acceptanceAllowed: false
12283
12292
  }));
12293
+ const independentBehaviorReview = input.preferences?.thorough === true || input.assessment.consequences.some((consequence) => ["security", "data", "public_contract", "operations"].includes(consequence.area));
12284
12294
  if (signals.behaviorChange.value === true)
12285
12295
  requirements.push(requirement({
12286
12296
  ruleId: "behavioral-verification",
@@ -12292,14 +12302,14 @@ function resolveRequirements(input) {
12292
12302
  dependentAction: null,
12293
12303
  acceptanceAllowed: false
12294
12304
  }), requirement({
12295
- ruleId: "fresh-context-review",
12305
+ ruleId: independentBehaviorReview ? "fresh-context-review" : "self-review",
12296
12306
  dimension: "review",
12297
12307
  scope,
12298
- reason: "A non-mechanical behavior change requires fresh-context review.",
12299
- satisfaction: "A separate review context examines the current candidate and records its result.",
12308
+ reason: independentBehaviorReview ? "Consequential behavior or the thorough preference requires fresh-context review." : "Bounded behavior changes use self-review unless consequential risks or trusted rules require more.",
12309
+ satisfaction: independentBehaviorReview ? "A separate review context examines the current candidate and records its result." : "The lead reviews the resulting diff and records the relevant scope and checks.",
12300
12310
  before: "close",
12301
12311
  dependentAction: null,
12302
- acceptanceAllowed: false
12312
+ acceptanceAllowed: !independentBehaviorReview
12303
12313
  }));
12304
12314
  else if (signals.mechanicalLowRisk.value === true)
12305
12315
  requirements.push(requirement({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and fourteen method skills",
6
6
  "keywords": [
@@ -44,8 +44,8 @@
44
44
  "build": "bun scripts/build.ts"
45
45
  },
46
46
  "dependencies": {
47
- "@brainervirus/workit-core": "^1.3.0",
48
- "@brainervirus/workit-mcp": "^1.3.0"
47
+ "@brainervirus/workit-core": "^1.3.2",
48
+ "@brainervirus/workit-mcp": "^1.3.2"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24"