@brainervirus/workit-cursor 0.6.0 → 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.
- package/.cursor-plugin/plugin.json +1 -1
- package/marketplace.json +1 -1
- package/mcp/server.ts +61 -91
- package/package.json +4 -4
|
@@ -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.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.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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
|
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(
|
|
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(), {
|
|
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({
|
|
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
|
|
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:
|
|
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:
|
|
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({
|
|
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.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"
|