@brainervirus/workit-cursor 2.0.1 → 2.1.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": "2.0.1",
5
+ "version": "2.1.0",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
@@ -10290,13 +10290,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
10290
10290
  throw new Error(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
10291
10291
  }
10292
10292
  return mostSpecific[0];
10293
- }, resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10294
- const result = readWorkspacesResult(dir);
10295
- if (result.status === "malformed" || result.status === "invalid")
10296
- throw new Error(result.error);
10293
+ }, resolveWorkspaceFromEntries = (cwd, entries, workspaceName) => {
10297
10294
  const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
10298
10295
  const matches = [];
10299
- for (const ws of result.entries) {
10296
+ for (const ws of entries) {
10300
10297
  const glob = ws.glob.replaceAll("\\", "/");
10301
10298
  const canonical = canonicalGlob(glob);
10302
10299
  let matched = false;
@@ -10310,6 +10307,11 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
10310
10307
  matches.push(ws);
10311
10308
  }
10312
10309
  return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
10310
+ }, resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10311
+ const result = readWorkspacesResult(dir);
10312
+ if (result.status === "malformed" || result.status === "invalid")
10313
+ throw new Error(result.error);
10314
+ return resolveWorkspaceFromEntries(cwd, result.entries, workspaceName);
10313
10315
  }, runtimeWorkspacePolicySchema = (kind) => {
10314
10316
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
10315
10317
  const policySchema = kind === "branch" ? workspaceBranchPolicySchema : kind === "commit" ? workspaceCommitPolicySchema : object({
@@ -10468,13 +10470,6 @@ var init_workspaces = __esm(() => {
10468
10470
  profiles: record(nonBlank, workspaceProfileSchema).optional(),
10469
10471
  releaseTracks: record(nonBlank, releaseTrackSchema).optional()
10470
10472
  }).passthrough().superRefine((workspace, context) => {
10471
- if (workspace.youtrack && workspace.vcs?.provider !== "gitlab") {
10472
- context.addIssue({
10473
- code: "custom",
10474
- path: ["youtrack"],
10475
- message: `YouTrack issue linking requires the gitlab provider, got ${workspace.vcs?.provider ?? "unset"}`
10476
- });
10477
- }
10478
10473
  if (workspace.issues && workspace.vcs?.provider !== "github") {
10479
10474
  context.addIssue({
10480
10475
  code: "custom",
@@ -10534,8 +10529,8 @@ function vcsConfig(mode, cwd) {
10534
10529
  const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
10535
10530
  const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
10536
10531
  const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
10537
- const linkIssues = provider === "gitlab" && typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
10538
- const youtrackBaseUrl = provider === "gitlab" && typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
10532
+ const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
10533
+ const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
10539
10534
  let issuesProvider = null;
10540
10535
  let linkOnPr = null;
10541
10536
  if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
@@ -11941,7 +11936,8 @@ let imported decisions grant authority. Never turn a host deny into allow or
11941
11936
  claim enforcement/evidence a host cannot provide. A precise request with settled
11942
11937
  constraints does not need an interview. Present genuine unresolved options with
11943
11938
  evidence and a recommendation, then continue toward the requested delivery
11944
- endpoint: investigation, implementation, PR/MR-ready, merge, or release. Run
11939
+ endpoint: investigation, implementation, branch/commit/push, PR/MR-ready,
11940
+ merge, or release. Run
11945
11941
  applicable checks and safe repairs without repeated continuation questions;
11946
11942
  stop for missing host authority, a new consequential choice, a conflicting edit,
11947
11943
  or an unresolved blocker. A tracked record may close when actual evidence
@@ -11953,6 +11949,12 @@ confirm the stop. Preserve unresolved requirements, gaps, and uncertain workers.
11953
11949
  When context changes, distinguish a quick question, same-task adjustment, and
11954
11950
  separate request. Answer a quick question without pausing/resuming task state;
11955
11951
  park a concise checkpoint only when substantial work needs to continue later.
11952
+ For work spanning repositories, bind each unfinished item to its actual checkout,
11953
+ branch, requested deliverables, and delivery endpoint. Preserve held items with
11954
+ an explicit resume condition. Resolve competing plausible targets before a
11955
+ mutation; ask only when available context cannot settle that consequential choice.
11956
+ Before reporting delivery, reconcile every requested item and observe the actual
11957
+ target result; a local commit alone is not evidence of a requested remote push.
11956
11958
 
11957
11959
  Skill routing: slash aliases /wk-* load on demand. Use workit-steer for a
11958
11960
  substantial interruption or change of direction, workit-deslop when relevant
@@ -11998,11 +12000,18 @@ function reconcileResume(view, observations = []) {
11998
12000
  });
11999
12001
  }
12000
12002
  function compactTaskContext(view) {
12001
- const decisions = view.task.decisions.slice().sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
12003
+ const decisions = view.task.decisions.slice().sort((left, right) => {
12004
+ const leftAt = compactTimestamp(left.recordedAt);
12005
+ const rightAt = compactTimestamp(right.recordedAt);
12006
+ if (leftAt !== rightAt)
12007
+ return leftAt > rightAt ? -1 : 1;
12008
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
12009
+ }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
12002
12010
  id: entry.id,
12003
12011
  purpose: entry.data.purpose,
12004
12012
  status: entry.data.response,
12005
12013
  digest: entry.data.digest,
12014
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
12006
12015
  references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
12007
12016
  }));
12008
12017
  const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
@@ -12046,7 +12055,12 @@ var COMPACT_MAX_BYTES = 4096, COMPACT_MAX_ITEMS = 8, COMPACT_TEXT_BYTES = 128, s
12046
12055
  return `${match.slice(0, separator)}=<redacted>`;
12047
12056
  const space = match.search(/\s/u);
12048
12057
  return `${match.slice(0, space)} <redacted>`;
12049
- }).slice(0, limit), compactBytes = (value) => new TextEncoder().encode(value).byteLength, compactReference = (ref) => {
12058
+ }).slice(0, limit), compactBytes = (value) => new TextEncoder().encode(value).byteLength, compactTimestamp = (value) => `${value.slice(0, 19)}.${value.slice(20, -1).padEnd(9, "0")}`, compactDecisionChoice = (entry) => {
12059
+ const stated = entry.data.binding.statedChoice?.text;
12060
+ const approved = entry.data.response === "approved" ? entry.data.binding.approvedContent : "";
12061
+ const source = stated?.trim() || approved.trim() || null;
12062
+ return compactText(source, COMPACT_TEXT_BYTES);
12063
+ }, compactReference = (ref) => {
12050
12064
  if (ref.kind === "file")
12051
12065
  return {
12052
12066
  kind: "file",
@@ -22940,13 +22940,6 @@ var workspaceConfigSchema = object4({
22940
22940
  profiles: record3(nonBlank, workspaceProfileSchema).optional(),
22941
22941
  releaseTracks: record3(nonBlank, releaseTrackSchema).optional()
22942
22942
  }).passthrough().superRefine((workspace, context) => {
22943
- if (workspace.youtrack && workspace.vcs?.provider !== "gitlab") {
22944
- context.addIssue({
22945
- code: "custom",
22946
- path: ["youtrack"],
22947
- message: `YouTrack issue linking requires the gitlab provider, got ${workspace.vcs?.provider ?? "unset"}`
22948
- });
22949
- }
22950
22943
  if (workspace.issues && workspace.vcs?.provider !== "github") {
22951
22944
  context.addIssue({
22952
22945
  code: "custom",
@@ -23138,13 +23131,10 @@ var selectWorkspaceMatch = (matches, cwd, workspaceName) => {
23138
23131
  }
23139
23132
  return mostSpecific[0];
23140
23133
  };
23141
- var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
23142
- const result = readWorkspacesResult(dir);
23143
- if (result.status === "malformed" || result.status === "invalid")
23144
- throw new Error(result.error);
23134
+ var resolveWorkspaceFromEntries = (cwd, entries, workspaceName) => {
23145
23135
  const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
23146
23136
  const matches = [];
23147
- for (const ws of result.entries) {
23137
+ for (const ws of entries) {
23148
23138
  const glob = ws.glob.replaceAll("\\", "/");
23149
23139
  const canonical = canonicalGlob(glob);
23150
23140
  let matched = false;
@@ -23159,6 +23149,12 @@ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
23159
23149
  }
23160
23150
  return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
23161
23151
  };
23152
+ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
23153
+ const result = readWorkspacesResult(dir);
23154
+ if (result.status === "malformed" || result.status === "invalid")
23155
+ throw new Error(result.error);
23156
+ return resolveWorkspaceFromEntries(cwd, result.entries, workspaceName);
23157
+ };
23162
23158
  var runtimeWorkspacePolicySchema = (kind) => {
23163
23159
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
23164
23160
  const policySchema = kind === "branch" ? workspaceBranchPolicySchema : kind === "commit" ? workspaceCommitPolicySchema : object4({
@@ -23434,8 +23430,8 @@ function vcsConfig(mode, cwd) {
23434
23430
  const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
23435
23431
  const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
23436
23432
  const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
23437
- const linkIssues = provider === "gitlab" && typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
23438
- const youtrackBaseUrl = provider === "gitlab" && typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
23433
+ const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
23434
+ const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
23439
23435
  let issuesProvider = null;
23440
23436
  let linkOnPr = null;
23441
23437
  if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
@@ -10124,13 +10124,6 @@ var workspaceConfigSchema = object({
10124
10124
  profiles: record(nonBlank, workspaceProfileSchema).optional(),
10125
10125
  releaseTracks: record(nonBlank, releaseTrackSchema).optional()
10126
10126
  }).passthrough().superRefine((workspace, context) => {
10127
- if (workspace.youtrack && workspace.vcs?.provider !== "gitlab") {
10128
- context.addIssue({
10129
- code: "custom",
10130
- path: ["youtrack"],
10131
- message: `YouTrack issue linking requires the gitlab provider, got ${workspace.vcs?.provider ?? "unset"}`
10132
- });
10133
- }
10134
10127
  if (workspace.issues && workspace.vcs?.provider !== "github") {
10135
10128
  context.addIssue({
10136
10129
  code: "custom",
@@ -10322,13 +10315,10 @@ var selectWorkspaceMatch = (matches, cwd, workspaceName) => {
10322
10315
  }
10323
10316
  return mostSpecific[0];
10324
10317
  };
10325
- var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10326
- const result = readWorkspacesResult(dir);
10327
- if (result.status === "malformed" || result.status === "invalid")
10328
- throw new Error(result.error);
10318
+ var resolveWorkspaceFromEntries = (cwd, entries, workspaceName) => {
10329
10319
  const targets = [cwd, realpathOf(cwd)].map((p) => p.replaceAll("\\", "/"));
10330
10320
  const matches = [];
10331
- for (const ws of result.entries) {
10321
+ for (const ws of entries) {
10332
10322
  const glob = ws.glob.replaceAll("\\", "/");
10333
10323
  const canonical = canonicalGlob(glob);
10334
10324
  let matched = false;
@@ -10343,6 +10333,12 @@ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10343
10333
  }
10344
10334
  return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
10345
10335
  };
10336
+ var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
10337
+ const result = readWorkspacesResult(dir);
10338
+ if (result.status === "malformed" || result.status === "invalid")
10339
+ throw new Error(result.error);
10340
+ return resolveWorkspaceFromEntries(cwd, result.entries, workspaceName);
10341
+ };
10346
10342
  var runtimeWorkspacePolicySchema = (kind) => {
10347
10343
  const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
10348
10344
  const policySchema = kind === "branch" ? workspaceBranchPolicySchema : kind === "commit" ? workspaceCommitPolicySchema : object({
@@ -10477,8 +10473,8 @@ function vcsConfig(mode, cwd) {
10477
10473
  const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
10478
10474
  const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
10479
10475
  const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
10480
- const linkIssues = provider === "gitlab" && typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
10481
- const youtrackBaseUrl = provider === "gitlab" && typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
10476
+ const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
10477
+ const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
10482
10478
  let issuesProvider = null;
10483
10479
  let linkOnPr = null;
10484
10480
  if (provider === "github" && typeof wsIssues.provider === "string" && wsIssues.provider.toLowerCase() === "github") {
@@ -11882,7 +11878,8 @@ let imported decisions grant authority. Never turn a host deny into allow or
11882
11878
  claim enforcement/evidence a host cannot provide. A precise request with settled
11883
11879
  constraints does not need an interview. Present genuine unresolved options with
11884
11880
  evidence and a recommendation, then continue toward the requested delivery
11885
- endpoint: investigation, implementation, PR/MR-ready, merge, or release. Run
11881
+ endpoint: investigation, implementation, branch/commit/push, PR/MR-ready,
11882
+ merge, or release. Run
11886
11883
  applicable checks and safe repairs without repeated continuation questions;
11887
11884
  stop for missing host authority, a new consequential choice, a conflicting edit,
11888
11885
  or an unresolved blocker. A tracked record may close when actual evidence
@@ -11894,6 +11891,12 @@ confirm the stop. Preserve unresolved requirements, gaps, and uncertain workers.
11894
11891
  When context changes, distinguish a quick question, same-task adjustment, and
11895
11892
  separate request. Answer a quick question without pausing/resuming task state;
11896
11893
  park a concise checkpoint only when substantial work needs to continue later.
11894
+ For work spanning repositories, bind each unfinished item to its actual checkout,
11895
+ branch, requested deliverables, and delivery endpoint. Preserve held items with
11896
+ an explicit resume condition. Resolve competing plausible targets before a
11897
+ mutation; ask only when available context cannot settle that consequential choice.
11898
+ Before reporting delivery, reconcile every requested item and observe the actual
11899
+ target result; a local commit alone is not evidence of a requested remote push.
11897
11900
 
11898
11901
  Skill routing: slash aliases /wk-* load on demand. Use workit-steer for a
11899
11902
  substantial interruption or change of direction, workit-deslop when relevant
@@ -11940,6 +11943,13 @@ var compactText = (value, limit) => value === null ? null : value.replace(privat
11940
11943
  return `${match.slice(0, space)} <redacted>`;
11941
11944
  }).slice(0, limit);
11942
11945
  var compactBytes = (value) => new TextEncoder().encode(value).byteLength;
11946
+ var compactTimestamp = (value) => `${value.slice(0, 19)}.${value.slice(20, -1).padEnd(9, "0")}`;
11947
+ var compactDecisionChoice = (entry) => {
11948
+ const stated = entry.data.binding.statedChoice?.text;
11949
+ const approved = entry.data.response === "approved" ? entry.data.binding.approvedContent : "";
11950
+ const source = stated?.trim() || approved.trim() || null;
11951
+ return compactText(source, COMPACT_TEXT_BYTES);
11952
+ };
11943
11953
  var compactReference = (ref) => {
11944
11954
  if (ref.kind === "file")
11945
11955
  return {
@@ -11955,11 +11965,18 @@ var compactReference = (ref) => {
11955
11965
  return { kind: ref.kind };
11956
11966
  };
11957
11967
  function compactTaskContext(view) {
11958
- const decisions = view.task.decisions.slice().sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
11968
+ const decisions = view.task.decisions.slice().sort((left, right) => {
11969
+ const leftAt = compactTimestamp(left.recordedAt);
11970
+ const rightAt = compactTimestamp(right.recordedAt);
11971
+ if (leftAt !== rightAt)
11972
+ return leftAt > rightAt ? -1 : 1;
11973
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
11974
+ }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
11959
11975
  id: entry.id,
11960
11976
  purpose: entry.data.purpose,
11961
11977
  status: entry.data.response,
11962
11978
  digest: entry.data.digest,
11979
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
11963
11980
  references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
11964
11981
  }));
11965
11982
  const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
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": "^2.0.1",
48
- "@brainervirus/workit-mcp": "^2.0.1"
47
+ "@brainervirus/workit-core": "^2.1.0",
48
+ "@brainervirus/workit-mcp": "^2.1.0"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24"
@@ -22,6 +22,14 @@ request, and a timeout is not proof that a worker stopped.
22
22
  until process exit or explicit recovery.
23
23
  4. Reconcile helper reports and run the checks appropriate to the requested
24
24
  outcome. If delegation is unavailable, continue inline when useful.
25
+ 5. Before a cross-repo mutation, resolve the actual checkout, branch and remote
26
+ from the request and current context. Ask only if competing plausible targets
27
+ remain unresolved. Branch, commit, direct push, PR-ready, merge and release
28
+ are distinct endpoints; perform only the authorized one under target rules.
29
+ Before saying done, reconcile every named deliverable against that checkout
30
+ and verify the requested result. For a push, observe the destination remote
31
+ ref and confirm it contains the delivered commit; report drift or missing
32
+ items as blockers instead of treating local success as remote delivery.
25
33
 
26
34
  Do not edit Workit metadata directly, create nested helper trees, widen paths, or
27
35
  create a second lifecycle. Read-only investigation and bounded reports do not
@@ -18,7 +18,11 @@ request. Preserve continuity when it helps; do not manufacture task mutations.
18
18
  3. For a separate request, do not silently resume an old objective. Park a
19
19
  concise checkpoint only when substantial work needs to continue later. Start
20
20
  a distinct tracked record only if the new work benefits from continuity,
21
- dependencies, coordination, or durable decisions.
21
+ dependencies, coordination, or durable decisions. For work spanning repos,
22
+ checkpoint each unfinished item with its checkout, branch, requested
23
+ deliverables, and delivery endpoint. Keep explicitly held items parked with
24
+ their resume condition until the user resumes them. A conversational
25
+ checkpoint is sufficient when no task record is needed.
22
26
  4. Before resuming a named tracked task, reconcile its checkout, branch, dirty
23
27
  state, current policy, stale evidence, uncertain effects, and ownership. Do
24
28
  not change branches, stash, fetch large histories, or seize ownership just