@brainervirus/workit-cursor 0.5.6 → 0.6.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": "OpenCode-style verify, PR, changelog, commit, and session handoff for Cursor",
5
- "version": "0.5.6",
5
+ "version": "0.6.1",
6
6
  "skills": "../skills/",
7
7
  "rules": "../rules/",
8
8
  "mcpServers": "../mcp.json",
package/marketplace.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "displayName": "Workflow Toolkit",
4
4
  "description": "Workflow rails for agentic coding: specs, plans, YouTrack, CI-gated commits",
5
5
  "publisher": "cristhofer-pincetti",
6
- "version": "0.5.6",
6
+ "version": "0.6.1",
7
7
  "homepage": "https://github.com/BrainerVirus/workit",
8
8
  "repository": "https://github.com/BrainerVirus/workit.git",
9
9
  "license": "MIT"
package/mcp/server.ts CHANGED
@@ -3,12 +3,24 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
5
  import { runScript } from "@brainervirus/workit-core/src/core/scripts";
6
- import { parseSections, parseKeyValueLines } from "@brainervirus/workit-core/src/core/parse-sections";
6
+ import {
7
+ parseSections,
8
+ parseKeyValueLines,
9
+ } from "@brainervirus/workit-core/src/core/parse-sections";
7
10
  import { parseVerifyOutput } from "@brainervirus/workit-core/src/core/verify-parse";
8
11
  import { gitContext } from "@brainervirus/workit-core/src/core/git";
9
- import { parsePlanTasks, resolveHandoffBranch } from "@brainervirus/workit-core/src/core/plan-tasks";
12
+ import {
13
+ parsePlanTasks,
14
+ resolveHandoffBranch,
15
+ } from "@brainervirus/workit-core/src/core/plan-tasks";
10
16
  import { buildHandoffPrompt } from "@brainervirus/workit-core/src/tools/handoff";
11
- import { readFlowState, transitionSpec, transitionPlan, recordMenuChoice, slugFromPath } from "@brainervirus/workit-core/src/core/flow-state";
17
+ import {
18
+ readFlowState,
19
+ transitionSpec,
20
+ transitionPlan,
21
+ recordMenuChoice,
22
+ slugFromPath,
23
+ } from "@brainervirus/workit-core/src/core/flow-state";
12
24
  import { linkDocsRepo, listSpecs, promoteSpec } from "@brainervirus/workit-core/src/core/docs-repo";
13
25
  import { configDir, readConfig, writeConfig } from "@brainervirus/workit-core/src/core/config";
14
26
  import { ensureProjectGitignore } from "@brainervirus/workit-core/src/core/gitignore";
@@ -44,30 +56,16 @@ import {
44
56
  const workspaceRootSchema = z
45
57
  .string()
46
58
  .optional()
47
- .describe(
48
- "Git repository root. Defaults to the Cursor workspace folder (${workspaceFolder}).",
49
- );
59
+ .describe("Git repository root. Defaults to the Cursor workspace folder (${workspaceFolder}).");
50
60
 
51
61
  const server = new McpServer({
52
62
  name: "workit",
53
63
  // Runtime read, not hardcoded: semantic-release bumps versions only in CI
54
64
  // (no commit-back), so any literal here would drift from the published tag.
55
65
  // package.json ships in the tarball regardless of the files whitelist.
56
- version: JSON.parse(
57
- readFileSync(new URL("../package.json", import.meta.url), "utf8"),
58
- ).version,
66
+ version: JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version,
59
67
  });
60
68
 
61
- function extractPlanPath(prompt) {
62
- const match = prompt.match(/\*\*Plan:\*\* (.+)/);
63
- return match?.[1]?.trim() ?? null;
64
- }
65
-
66
- function extractSpecPath(prompt) {
67
- const match = prompt.match(/\*\*Spec:\*\* (.+)/);
68
- return match?.[1]?.trim() ?? null;
69
- }
70
-
71
69
  function jsonResult(data) {
72
70
  return {
73
71
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
@@ -87,11 +85,7 @@ server.registerTool(
87
85
  },
88
86
  async ({ dry_run, workspace_root }) => {
89
87
  const args = dry_run ? ["--dry-run"] : [];
90
- const { stdout, stderr, exitCode, cwd } = runScript(
91
- "verify-project.sh",
92
- args,
93
- workspace_root,
94
- );
88
+ const { stdout, stderr, exitCode, cwd } = runScript("verify-project.sh", args, workspace_root);
95
89
  const parsed = parseVerifyOutput(stdout);
96
90
  return jsonResult(
97
91
  withWorkspace(workspace_root, {
@@ -125,9 +119,7 @@ server.registerTool(
125
119
  if (exitCode !== 0) {
126
120
  const errLines = (stderr + "\n" + stdout).split("\n");
127
121
  const error =
128
- errLines.find((l) => l.startsWith("ERROR:")) ??
129
- stderr.trim() ??
130
- "pr-ready-context failed";
122
+ errLines.find((l) => l.startsWith("ERROR:")) ?? stderr.trim() ?? "pr-ready-context failed";
131
123
  return jsonResult(
132
124
  withWorkspace(workspace_root, {
133
125
  error,
@@ -203,27 +195,15 @@ server.registerTool(
203
195
  workspace_root: workspaceRootSchema,
204
196
  },
205
197
  },
206
- async ({
207
- confirmed,
208
- title,
209
- body,
210
- draft,
211
- target_branch,
212
- workspace_root,
213
- }) => {
198
+ async ({ confirmed, title, body, draft, target_branch, workspace_root }) => {
214
199
  if (!confirmed) return jsonResult({ error: "confirmed: true required" });
215
- const { stdout, stderr, exitCode, cwd } = runScript(
216
- "pr-create.sh",
217
- [],
218
- workspace_root,
219
- {
220
- WF_PR_TITLE: title,
221
- WF_PR_BODY: body ?? "",
222
- WF_PR_CONFIRMED: "true",
223
- WF_PR_DRAFT: draft ? "true" : "false",
224
- WF_PR_TARGET: target_branch ?? "",
225
- },
226
- );
200
+ const { stdout, stderr, exitCode, cwd } = runScript("pr-create.sh", [], workspace_root, {
201
+ WF_PR_TITLE: title,
202
+ WF_PR_BODY: body ?? "",
203
+ WF_PR_CONFIRMED: "true",
204
+ WF_PR_DRAFT: draft ? "true" : "false",
205
+ WF_PR_TARGET: target_branch ?? "",
206
+ });
227
207
  try {
228
208
  const data = JSON.parse(stdout.trim());
229
209
  if (data.error) {
@@ -350,10 +330,7 @@ server.registerTool(
350
330
  workspace_root,
351
331
  );
352
332
  const sections = parseSections(stdout);
353
- const repo = parseKeyValueLines(sections.Repository ?? "", [
354
- "requested",
355
- "range",
356
- ]);
333
+ const repo = parseKeyValueLines(sections.Repository ?? "", ["requested", "range"]);
357
334
  return jsonResult(
358
335
  withWorkspace(workspace_root, {
359
336
  requested: repo.requested,
@@ -550,7 +527,7 @@ server.registerTool(
550
527
  "workflow_docs_branch",
551
528
  {
552
529
  description:
553
- "Resolve branch for spec/plan authors: keep current feature|bugfix or create from develop.",
530
+ "Resolve branch for spec/plan authors: keep current feature|bugfix or create from the configured base.",
554
531
  inputSchema: {
555
532
  plan_path: z.string().optional(),
556
533
  kind: z.enum(["feature", "bugfix"]).optional(),
@@ -578,7 +555,9 @@ server.registerTool(
578
555
  async ({ spec_path, plan_path, workspace_root }) => {
579
556
  const data = docsValidate({ spec_path, plan_path, workspace_root });
580
557
  if (data.error) {
581
- return jsonResult(withWorkspace(workspace_root, { error: data.error, errors: data.errors ?? [] }));
558
+ return jsonResult(
559
+ withWorkspace(workspace_root, { error: data.error, errors: data.errors ?? [] }),
560
+ );
582
561
  }
583
562
  return jsonResult(withWorkspace(workspace_root, data));
584
563
  },
@@ -601,11 +580,7 @@ server.registerTool(
601
580
  return jsonResult(withWorkspace(workspace_root, { error: data.error }));
602
581
  }
603
582
  if (spec_path) {
604
- const branchData = resolveHandoffBranch(
605
- spec_path,
606
- plan_path,
607
- workspace_root,
608
- );
583
+ const branchData = resolveHandoffBranch(spec_path, plan_path, workspace_root);
609
584
  if (branchData.error) {
610
585
  return jsonResult(
611
586
  withWorkspace(workspace_root, {
@@ -614,9 +589,7 @@ server.registerTool(
614
589
  }),
615
590
  );
616
591
  }
617
- return jsonResult(
618
- withWorkspace(workspace_root, { ...data, branch: branchData.branch }),
619
- );
592
+ return jsonResult(withWorkspace(workspace_root, { ...data, branch: branchData.branch }));
620
593
  }
621
594
  return jsonResult(withWorkspace(workspace_root, data));
622
595
  },
@@ -657,11 +630,7 @@ server.registerTool(
657
630
  workspace_root: root,
658
631
  };
659
632
  if (specPath) {
660
- const branchData = resolveHandoffBranch(
661
- specPath,
662
- planPath,
663
- root,
664
- );
633
+ const branchData = resolveHandoffBranch(specPath, planPath, root);
665
634
  if (!branchData.error) {
666
635
  payload.branch = branchData.branch;
667
636
  }
@@ -689,8 +658,7 @@ server.registerTool(
689
658
  server.registerTool(
690
659
  "workflow_toolkit_init_status",
691
660
  {
692
- description:
693
- "Check workit setup (MCP deps, YouTrack config, token)",
661
+ description: "Check workit setup (MCP deps, YouTrack config, token)",
694
662
  inputSchema: {},
695
663
  },
696
664
  async () => {
@@ -762,7 +730,10 @@ server.registerTool(
762
730
  include_open_source,
763
731
  }) => {
764
732
  if (action === "hygiene") {
765
- const result = ensureHygieneFiles(workspace_root ?? process.cwd(), { confirmed, includeOpenSource: include_open_source });
733
+ const result = ensureHygieneFiles(workspace_root ?? process.cwd(), {
734
+ confirmed,
735
+ includeOpenSource: include_open_source,
736
+ });
766
737
  if (!result.ok) return jsonResult({ error: result.error });
767
738
  return jsonResult(result);
768
739
  }
@@ -773,7 +744,9 @@ server.registerTool(
773
744
  }
774
745
  if (action === "config") {
775
746
  if (locale !== undefined && !/^[a-z]{2,3}(-[A-Z]{2})?$/.test(locale)) {
776
- return jsonResult({ error: `invalid locale: ${JSON.stringify(locale)} — expected BCP-47 like en or es-CL` });
747
+ return jsonResult({
748
+ error: `invalid locale: ${JSON.stringify(locale)} — expected BCP-47 like en or es-CL`,
749
+ });
777
750
  }
778
751
  const current = readConfig();
779
752
  const next = {
@@ -804,16 +777,14 @@ server.registerTool(
804
777
  server.registerTool(
805
778
  "workflow_youtrack_verify_token",
806
779
  {
807
- description:
808
- "Read-only YouTrack token test (GET /api/users/me). No work items created.",
780
+ description: "Read-only YouTrack token test (GET /api/users/me). No work items created.",
809
781
  inputSchema: {},
810
782
  },
811
783
  async () => {
812
784
  const result = verifyYouTrackToken();
813
785
  if (result.error) return jsonResult({ error: result.error });
814
786
  const data = result.data;
815
- if (!data.ok)
816
- return jsonResult({ error: data.error ?? "token invalid", ...data });
787
+ if (!data.ok) return jsonResult({ error: data.error ?? "token invalid", ...data });
817
788
  return jsonResult(data);
818
789
  },
819
790
  );
@@ -821,8 +792,7 @@ server.registerTool(
821
792
  server.registerTool(
822
793
  "workflow_youtrack_parse_issue",
823
794
  {
824
- description:
825
- "Parse YouTrack issue URL or bare id (e.g. NSR-40) into issueId",
795
+ description: "Parse YouTrack issue URL or bare id (e.g. NSR-40) into issueId",
826
796
  inputSchema: {
827
797
  issue_ref: z
828
798
  .string()
@@ -839,8 +809,7 @@ server.registerTool(
839
809
  server.registerTool(
840
810
  "workflow_youtrack_context",
841
811
  {
842
- description:
843
- "YouTrack config, greeting, issue resolution (from issue_url/id or meetings)",
812
+ description: "YouTrack config, greeting, issue resolution (from issue_url/id or meetings)",
844
813
  inputSchema: {
845
814
  mode: z.enum(["meetings", "task"]).optional(),
846
815
  issue_id: z.string().optional(),
@@ -851,15 +820,7 @@ server.registerTool(
851
820
  workspace_root: workspaceRootSchema,
852
821
  },
853
822
  },
854
- async ({
855
- mode,
856
- issue_id,
857
- issue_url,
858
- issue_ref,
859
- spec_path,
860
- plan_path,
861
- workspace_root,
862
- }) => {
823
+ async ({ mode, issue_id, issue_url, issue_ref, spec_path, plan_path, workspace_root }) => {
863
824
  const data = youtrackContext({
864
825
  mode,
865
826
  issue_id,
@@ -903,7 +864,10 @@ server.registerTool(
903
864
  issueId: z.string(),
904
865
  minutes: z.number(),
905
866
  text: z.string().optional(),
906
- dateMs: z.number().optional().describe("Epoch ms for work item date; omit for today in config timezone"),
867
+ dateMs: z
868
+ .number()
869
+ .optional()
870
+ .describe("Epoch ms for work item date; omit for today in config timezone"),
907
871
  workspace_root: workspaceRootSchema,
908
872
  },
909
873
  },
@@ -1037,7 +1001,8 @@ server.registerTool(
1037
1001
  server.registerTool(
1038
1002
  "workflow_spec_approve",
1039
1003
  {
1040
- description: "Advance spec status: first call self_reviewed, second call approved (after user approval)",
1004
+ description:
1005
+ "Advance spec status: first call self_reviewed, second call approved (after user approval)",
1041
1006
  inputSchema: {
1042
1007
  confirmed: z.boolean(),
1043
1008
  spec_path: z.string(),
@@ -1056,7 +1021,8 @@ server.registerTool(
1056
1021
  server.registerTool(
1057
1022
  "workflow_plan_approve",
1058
1023
  {
1059
- description: "Advance plan status: first call self_reviewed, second call approved. Requires approved spec.",
1024
+ description:
1025
+ "Advance plan status: first call self_reviewed, second call approved. Requires approved spec.",
1060
1026
  inputSchema: {
1061
1027
  confirmed: z.boolean(),
1062
1028
  plan_path: z.string(),
@@ -1131,7 +1097,11 @@ server.registerTool(
1131
1097
  async ({ slug, confirmed, force, workspace_root }) => {
1132
1098
  const result = promoteSpec(workspace_root ?? process.cwd(), slug, { confirmed, force });
1133
1099
  if (!result.ok) return jsonResult({ error: result.error, findings: result.findings ?? [] });
1134
- return jsonResult({ target_dir: result.target_dir, files: result.files, index_updated: result.index_updated });
1100
+ return jsonResult({
1101
+ target_dir: result.target_dir,
1102
+ files: result.files,
1103
+ index_updated: result.index_updated,
1104
+ });
1135
1105
  },
1136
1106
  );
1137
1107
 
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "0.5.6",
3
+ "version": "0.6.1",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin: MCP server, hooks, rules, marketplace manifest (thin over @brainervirus/workit-core)",
6
- "license": "MIT",
7
6
  "keywords": [
7
+ "agent",
8
8
  "cursor",
9
9
  "mcp",
10
- "workflow",
11
- "agent"
10
+ "workflow"
12
11
  ],
13
12
  "bugs": {
14
13
  "url": "https://github.com/BrainerVirus/workit/issues"
15
14
  },
15
+ "license": "MIT",
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "https://github.com/BrainerVirus/workit.git"
@@ -5,11 +5,11 @@ description: Draft or create PR/MR via workflow_pr_context + glab/gh. Squash on
5
5
 
6
6
  # PR — Draft or Create
7
7
 
8
- Draft a merge request / pull request body, or create it on GitLab (`glab`) / GitHub (`gh`) using `~/.config/workflow-toolkit/vcs.json`.
8
+ Draft a merge request / pull request body, or create it on GitLab (`glab`) / GitHub (`gh`) using `~/.config/workit/vcs.json`.
9
9
 
10
10
  **Setup:** `/wk-init` → pick provider → VCS scaffold → edit active token file.
11
11
 
12
- **Active provider:** read `vcs_config.provider` from `workflow_pr_context` (or `provider` in `~/.config/workflow-toolkit/vcs.json`). That decides `glab` vs `gh`.
12
+ **Active provider:** read `vcs_config.provider` from `workflow_pr_context` (or `provider` in `~/.config/workit/vcs.json`). That decides `glab` vs `gh`.
13
13
 
14
14
  ## Step 1 — Gather facts (required)
15
15