@vornrun/mcp 0.7.4 → 0.8.0-beta.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/dist/index.js +176 -7
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -589,6 +589,7 @@ function createSchema() {
|
|
|
589
589
|
CREATE INDEX IF NOT EXISTS idx_connector_inbox_connection
|
|
590
590
|
ON connector_inbox(connection_id, created_at);
|
|
591
591
|
`);
|
|
592
|
+
d.exec(ARTIFACT_DDL);
|
|
592
593
|
migrateSchema(d);
|
|
593
594
|
verifySchema(d);
|
|
594
595
|
seedLegacyConnectorPollState(d);
|
|
@@ -1135,7 +1136,59 @@ function migrateSchema(d) {
|
|
|
1135
1136
|
})();
|
|
1136
1137
|
logger_default.info("[database] migrated schema to version 24 (the text a reviewer edited at a gate)");
|
|
1137
1138
|
}
|
|
1139
|
+
if (version < 25) {
|
|
1140
|
+
d.transaction(() => {
|
|
1141
|
+
d.exec(ARTIFACT_DDL);
|
|
1142
|
+
d.prepare(
|
|
1143
|
+
"INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('schema_version', '25')"
|
|
1144
|
+
).run();
|
|
1145
|
+
})();
|
|
1146
|
+
logger_default.info("[database] migrated schema to version 25 (published artifacts and their comments)");
|
|
1147
|
+
}
|
|
1138
1148
|
}
|
|
1149
|
+
var ARTIFACT_DDL = `
|
|
1150
|
+
CREATE TABLE IF NOT EXISTS artifacts (
|
|
1151
|
+
id TEXT PRIMARY KEY,
|
|
1152
|
+
kind TEXT NOT NULL,
|
|
1153
|
+
title TEXT NOT NULL,
|
|
1154
|
+
session_id TEXT,
|
|
1155
|
+
project_name TEXT,
|
|
1156
|
+
token TEXT NOT NULL,
|
|
1157
|
+
latest_version INTEGER NOT NULL DEFAULT 0,
|
|
1158
|
+
gate_run_id TEXT,
|
|
1159
|
+
gate_node_id TEXT,
|
|
1160
|
+
created_at TEXT NOT NULL,
|
|
1161
|
+
updated_at TEXT NOT NULL
|
|
1162
|
+
);
|
|
1163
|
+
|
|
1164
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_session ON artifacts(session_id, updated_at DESC);
|
|
1165
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_project ON artifacts(project_name, updated_at DESC);
|
|
1166
|
+
|
|
1167
|
+
CREATE TABLE IF NOT EXISTS artifact_versions (
|
|
1168
|
+
artifact_id TEXT NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
|
|
1169
|
+
version INTEGER NOT NULL,
|
|
1170
|
+
author TEXT NOT NULL,
|
|
1171
|
+
answers_batch_id TEXT,
|
|
1172
|
+
created_at TEXT NOT NULL,
|
|
1173
|
+
PRIMARY KEY (artifact_id, version)
|
|
1174
|
+
);
|
|
1175
|
+
|
|
1176
|
+
CREATE TABLE IF NOT EXISTS artifact_comments (
|
|
1177
|
+
id TEXT PRIMARY KEY,
|
|
1178
|
+
artifact_id TEXT NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
|
|
1179
|
+
version INTEGER NOT NULL,
|
|
1180
|
+
anchor TEXT,
|
|
1181
|
+
body TEXT NOT NULL,
|
|
1182
|
+
state TEXT NOT NULL DEFAULT 'draft',
|
|
1183
|
+
batch_id TEXT,
|
|
1184
|
+
created_at TEXT NOT NULL,
|
|
1185
|
+
updated_at TEXT NOT NULL,
|
|
1186
|
+
sent_at TEXT
|
|
1187
|
+
);
|
|
1188
|
+
|
|
1189
|
+
CREATE INDEX IF NOT EXISTS idx_artifact_comments_artifact
|
|
1190
|
+
ON artifact_comments(artifact_id, created_at);
|
|
1191
|
+
`;
|
|
1139
1192
|
var GATE_COLUMNS = [
|
|
1140
1193
|
["message", "TEXT"],
|
|
1141
1194
|
["view_token", "TEXT"],
|
|
@@ -1258,7 +1311,7 @@ function verifySchema(d) {
|
|
|
1258
1311
|
},
|
|
1259
1312
|
// Which pass of a loop produced this row.
|
|
1260
1313
|
{ column: "iteration", ddl: "ALTER TABLE workflow_run_nodes ADD COLUMN iteration INTEGER" },
|
|
1261
|
-
...GATE_COLUMNS.map(([column, type]) => ({
|
|
1314
|
+
...[...GATE_COLUMNS, ...GATE_EDIT_COLUMNS].map(([column, type]) => ({
|
|
1262
1315
|
column,
|
|
1263
1316
|
ddl: `ALTER TABLE workflow_run_nodes ADD COLUMN ${column} ${type}`
|
|
1264
1317
|
}))
|
|
@@ -1435,9 +1488,18 @@ function loadDefaults(d) {
|
|
|
1435
1488
|
},
|
|
1436
1489
|
...map.worktreeRetention !== void 0 && {
|
|
1437
1490
|
worktreeRetention: map.worktreeRetention
|
|
1438
|
-
}
|
|
1491
|
+
},
|
|
1492
|
+
...isPlainObject(map.experimental) && { experimental: experimentalFlags(map.experimental) }
|
|
1439
1493
|
};
|
|
1440
1494
|
}
|
|
1495
|
+
function isPlainObject(value) {
|
|
1496
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1497
|
+
}
|
|
1498
|
+
function experimentalFlags(raw) {
|
|
1499
|
+
const flags = {};
|
|
1500
|
+
for (const [key, value] of Object.entries(raw)) if (typeof value === "boolean") flags[key] = value;
|
|
1501
|
+
return flags;
|
|
1502
|
+
}
|
|
1441
1503
|
function loadProjects(d) {
|
|
1442
1504
|
const rows = d.prepare("SELECT * FROM projects").all();
|
|
1443
1505
|
return rows.map(rowToProject);
|
|
@@ -4215,9 +4277,18 @@ The run is stopped by the instance holding it, so confirm with list_workflow_run
|
|
|
4215
4277
|
edited: z6.string().max(2e5).optional().describe(
|
|
4216
4278
|
"Your rewrite of the gate's editable text, when it has one. Kept beside the original, and read by later steps as {{steps.<gate>.text}}. Ignored on reject."
|
|
4217
4279
|
),
|
|
4280
|
+
comments: z6.array(
|
|
4281
|
+
z6.object({
|
|
4282
|
+
quote: z6.string().max(2e3).optional().describe("The words on the review page it is about"),
|
|
4283
|
+
comment: z6.string().min(1).max(4e3)
|
|
4284
|
+
})
|
|
4285
|
+
).max(100).optional().describe(
|
|
4286
|
+
"Comments on the review page, each on the words it quotes. Carried back with changes and read by the redone steps as {{steps.<gate>.comments}}; ignored on approve and reject."
|
|
4287
|
+
),
|
|
4218
4288
|
node_id: V.id.optional().describe("The waiting node, when a run has more than one gate open")
|
|
4219
4289
|
},
|
|
4220
4290
|
async (args) => {
|
|
4291
|
+
const comments = (args.comments ?? []).filter((c) => c.comment.trim());
|
|
4221
4292
|
const run = await runById(args.run_id);
|
|
4222
4293
|
if (!run) {
|
|
4223
4294
|
return {
|
|
@@ -4247,7 +4318,7 @@ The run is stopped by the instance holding it, so confirm with list_workflow_run
|
|
|
4247
4318
|
isError: true
|
|
4248
4319
|
};
|
|
4249
4320
|
}
|
|
4250
|
-
if (args.decision === "changes" && !args.comment?.trim()) {
|
|
4321
|
+
if (args.decision === "changes" && !args.comment?.trim() && comments.length === 0) {
|
|
4251
4322
|
return {
|
|
4252
4323
|
content: [
|
|
4253
4324
|
{ type: "text", text: "Error: changes needs a comment saying what to change." }
|
|
@@ -4266,7 +4337,8 @@ The run is stopped by the instance holding it, so confirm with list_workflow_run
|
|
|
4266
4337
|
nodeId: target.nodeId,
|
|
4267
4338
|
decision: args.decision,
|
|
4268
4339
|
...args.comment?.trim() && { comment: args.comment.trim() },
|
|
4269
|
-
...args.edited?.trim() && { edited: args.edited.trim() }
|
|
4340
|
+
...args.edited?.trim() && { edited: args.edited.trim() },
|
|
4341
|
+
...args.decision === "changes" && comments.length > 0 && { comments }
|
|
4270
4342
|
}
|
|
4271
4343
|
);
|
|
4272
4344
|
if (answer?.accepted === false) {
|
|
@@ -4610,8 +4682,12 @@ var DOCS = {
|
|
|
4610
4682
|
field: "items",
|
|
4611
4683
|
description: "When the editable text is a JSON list of records: the rows the reviewer kept, as a list, ready for a forEach loop"
|
|
4612
4684
|
},
|
|
4613
|
-
{
|
|
4614
|
-
|
|
4685
|
+
{
|
|
4686
|
+
field: "comments",
|
|
4687
|
+
description: "Comments pinned to the review page in the latest round, as a JSON list of {quote, comment, anchored}"
|
|
4688
|
+
},
|
|
4689
|
+
{ field: "feedback", description: "The general note from the latest round" },
|
|
4690
|
+
{ field: "feedbackAll", description: "Every note, one line per round" },
|
|
4615
4691
|
{ field: "round", description: "Which time the gate asked, from 1" },
|
|
4616
4692
|
...COMMON_OUTPUTS
|
|
4617
4693
|
],
|
|
@@ -5767,6 +5843,98 @@ Screen is ${r.screen.width}x${r.screen.height} points. Image pixels are ${r.scal
|
|
|
5767
5843
|
);
|
|
5768
5844
|
}
|
|
5769
5845
|
|
|
5846
|
+
// src/tools/artifacts.ts
|
|
5847
|
+
import { z as z12 } from "zod";
|
|
5848
|
+
var MAX_CONTENT = 5 * 1024 * 1024;
|
|
5849
|
+
var text = (value) => ({ content: [{ type: "text", text: value }] });
|
|
5850
|
+
function registerArtifactTools(server) {
|
|
5851
|
+
server.tool(
|
|
5852
|
+
"publish_artifact",
|
|
5853
|
+
"Publish a page, doc or design for the person to review. It opens in your session browser pane, where they can comment on the exact words and send their notes back to you as one message. Pass artifactId to publish the next version of an artifact after addressing comments. A page or design is self-contained HTML (no network: inline styles, scripts and images as data: URIs); a doc is Markdown.",
|
|
5854
|
+
{
|
|
5855
|
+
kind: z12.enum(["page", "doc", "design"]).describe("page: any HTML; doc: Markdown; design: HTML with a design manifest"),
|
|
5856
|
+
title: V.shortText.min(1).describe("What the artifact is called in the pane"),
|
|
5857
|
+
file: z12.string().min(1).max(1e3).optional().describe("A .html or .md file inside your project or worktree; give this or content"),
|
|
5858
|
+
content: z12.string().max(MAX_CONTENT).optional().describe("The HTML or Markdown itself"),
|
|
5859
|
+
artifactId: V.id.optional().describe("Publish the next version of this artifact"),
|
|
5860
|
+
open: z12.boolean().optional().describe("Open it in the browser pane (default true)")
|
|
5861
|
+
},
|
|
5862
|
+
async (args) => withSession(async (id) => {
|
|
5863
|
+
const result = await rpcCall("artifact:publish", { sessionId: id, ...args });
|
|
5864
|
+
const lines = [
|
|
5865
|
+
`Published ${result.artifact.kind} "${result.artifact.title}" v${result.version.version} (artifactId ${result.artifact.id}).`,
|
|
5866
|
+
result.opened ? "It is open in your browser pane." : `Not opened in a pane. Served at ${result.url}`
|
|
5867
|
+
];
|
|
5868
|
+
if (result.answered > 0) lines.push(`This version answers ${result.answered} comments.`);
|
|
5869
|
+
return text(lines.join("\n"));
|
|
5870
|
+
})
|
|
5871
|
+
);
|
|
5872
|
+
server.tool(
|
|
5873
|
+
"list_artifacts",
|
|
5874
|
+
"List the artifacts published by your session or in your project, newest first.",
|
|
5875
|
+
{ limit: z12.number().int().min(1).max(100).optional() },
|
|
5876
|
+
async (args) => withSession(async (id) => {
|
|
5877
|
+
const artifacts = await rpcCall("artifact:list", {
|
|
5878
|
+
sessionId: id,
|
|
5879
|
+
limit: args.limit
|
|
5880
|
+
});
|
|
5881
|
+
if (artifacts.length === 0) return text("No artifacts yet.");
|
|
5882
|
+
return text(
|
|
5883
|
+
artifacts.map(
|
|
5884
|
+
(a) => `${a.id} ${a.kind} v${a.latestVersion} "${a.title}" updated ${a.updatedAt}`
|
|
5885
|
+
).join("\n")
|
|
5886
|
+
);
|
|
5887
|
+
})
|
|
5888
|
+
);
|
|
5889
|
+
server.tool(
|
|
5890
|
+
"read_artifact_comments",
|
|
5891
|
+
"Read the comments the person left on an artifact: the quoted words or point each one is about, the comment, which version it was written on, and whether it was sent to you.",
|
|
5892
|
+
{
|
|
5893
|
+
artifactId: V.id,
|
|
5894
|
+
version: z12.number().int().min(1).optional().describe("Only comments written on this version")
|
|
5895
|
+
},
|
|
5896
|
+
async (args) => withSession(async (id) => {
|
|
5897
|
+
const comments = await rpcCall("artifact:readComments", {
|
|
5898
|
+
sessionId: id,
|
|
5899
|
+
artifactId: args.artifactId,
|
|
5900
|
+
version: args.version
|
|
5901
|
+
});
|
|
5902
|
+
return pageResult(
|
|
5903
|
+
comments.map((c) => ({
|
|
5904
|
+
version: c.version,
|
|
5905
|
+
state: c.state,
|
|
5906
|
+
anchor: c.anchor,
|
|
5907
|
+
comment: c.body
|
|
5908
|
+
})),
|
|
5909
|
+
"ARTIFACT COMMENTS ON WEB PAGE CONTENT"
|
|
5910
|
+
);
|
|
5911
|
+
})
|
|
5912
|
+
);
|
|
5913
|
+
server.tool(
|
|
5914
|
+
"read_artifact",
|
|
5915
|
+
"Read the source of an artifact version: Markdown for a doc, HTML for a page or design. Use it before publishing the next version when the person saved edits of their own.",
|
|
5916
|
+
{
|
|
5917
|
+
artifactId: V.id,
|
|
5918
|
+
version: z12.number().int().min(1).optional().describe("Defaults to the latest version")
|
|
5919
|
+
},
|
|
5920
|
+
async (args) => withSession(async (id) => {
|
|
5921
|
+
const found = await rpcCall(
|
|
5922
|
+
"artifact:readSource",
|
|
5923
|
+
{ sessionId: id, artifactId: args.artifactId, version: args.version }
|
|
5924
|
+
);
|
|
5925
|
+
if (!found) return text(`No such version of artifact ${args.artifactId}.`);
|
|
5926
|
+
return pageResult(
|
|
5927
|
+
{
|
|
5928
|
+
version: found.version.version,
|
|
5929
|
+
author: found.version.author === "user" ? "the person" : "an agent",
|
|
5930
|
+
source: found.body
|
|
5931
|
+
},
|
|
5932
|
+
"WEB PAGE CONTENT: ARTIFACT SOURCE"
|
|
5933
|
+
);
|
|
5934
|
+
})
|
|
5935
|
+
);
|
|
5936
|
+
}
|
|
5937
|
+
|
|
5770
5938
|
// src/server.ts
|
|
5771
5939
|
function createMcpServer(version) {
|
|
5772
5940
|
const server = new McpServer({ name: "vorn", version }, { capabilities: { tools: {} } });
|
|
@@ -5775,6 +5943,7 @@ function createMcpServer(version) {
|
|
|
5775
5943
|
registerConnectorTools(server);
|
|
5776
5944
|
registerBrowserTools(server);
|
|
5777
5945
|
registerDeviceTools(server);
|
|
5946
|
+
registerArtifactTools(server);
|
|
5778
5947
|
registerProjectTools(server);
|
|
5779
5948
|
registerTaskTools(server);
|
|
5780
5949
|
registerWorkflowTools(server);
|
|
@@ -5792,7 +5961,7 @@ console.warn = (...args) => _origError("[mcp:warn]", ...args);
|
|
|
5792
5961
|
console.error = (...args) => _origError("[mcp:error]", ...args);
|
|
5793
5962
|
async function main() {
|
|
5794
5963
|
configManager.init();
|
|
5795
|
-
const version = true ? "0.
|
|
5964
|
+
const version = true ? "0.8.0-beta.1" : createRequire(import.meta.url)("../package.json").version;
|
|
5796
5965
|
const server = createMcpServer(version);
|
|
5797
5966
|
const transport = new StdioServerTransport();
|
|
5798
5967
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vornrun/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-beta.1",
|
|
4
4
|
"description": "Vorn MCP server — task management, git, and workflow tools for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"zod": "^4.5.4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@vornrun/server": "0.
|
|
42
|
-
"@vornrun/shared": "0.
|
|
41
|
+
"@vornrun/server": "0.8.0-beta.1",
|
|
42
|
+
"@vornrun/shared": "0.8.0-beta.1",
|
|
43
43
|
"tsup": "^8.5.1",
|
|
44
44
|
"tsx": "^4.23.1",
|
|
45
45
|
"typescript": "^6.0.3"
|