@rucher/carnet 0.0.0-stage → 0.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.
- package/LICENSE +21 -0
- package/README.md +20 -2
- package/dist/carnet-CSdqWDas.d.mts +261 -0
- package/dist/carnet-CSdqWDas.d.mts.map +1 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +71 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mcp.d.mts +40 -0
- package/dist/mcp.d.mts.map +1 -0
- package/dist/mcp.mjs +417 -0
- package/dist/mcp.mjs.map +1 -0
- package/dist/resume-Daotqfdq.mjs +985 -0
- package/dist/resume-Daotqfdq.mjs.map +1 -0
- package/package.json +54 -3
package/dist/mcp.mjs
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { B as hostById, M as reportPathFor, N as reportsDirectoryOf, R as DEFAULT_HOST, a as sessionLabel, at as EMOJI, ct as OPEN_AGENT_STATUSES, ft as EVENT_TYPES, g as renderTableLine, i as resumeContext, lt as USER_ACTION_STATUSES, mt as CarnetError, p as renderAgentLine, r as formatEventLine, s as openCarnet } from "./resume-Daotqfdq.mjs";
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
4
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
|
+
import * as z from "zod/v4";
|
|
6
|
+
// src/mcp/instructions.ts
|
|
7
|
+
const INSTRUCTIONS = `Carnet tracks the status of sub-agents (forks) for the human, in a shared database. Views are rendered by the \`rucher\` CLI.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
- Never write status files (agents-status.md or similar) and never describe status updates in the chat. When a fork finishes, the main agent says only "<name> finished, report ready".
|
|
11
|
+
- Update BEFORE and AFTER each piece of work, never batched at the end of a turn.
|
|
12
|
+
- Your session is resolved automatically. Pass \`session\` only to target another session.
|
|
13
|
+
|
|
14
|
+
Main agent:
|
|
15
|
+
- agent_start before dispatching a fork (name, task), in an earlier message than the launch; launch parallel forks in the same order. Names are short, no paths.
|
|
16
|
+
- table_set with main_working=true before applying, testing or fixing yourself; table_set with a status (or table_clear) when done.
|
|
17
|
+
- log_event when a step is answered, applied, tested, committed or dropped.
|
|
18
|
+
- When a fork finishes: say one line "<name> finished, report ready", copy its report to the report destination agent_start gave (.rucher/reports/<name>.md in the group meta directory) and call agent_update with that report_path. Present the report only when asked.
|
|
19
|
+
- For dispatching, applying or reviewing forks, load the rucher skill: it holds the full workflow.
|
|
20
|
+
- agent_drop when a fork's work is committed or abandoned. queue_reorder to change the handling order.
|
|
21
|
+
- agent_list to recall where things stand.
|
|
22
|
+
- Sessions: session_new when the human names this session (then ask them to /rename it the same way); session_list, session_resume_info and log_read to recall other sessions or the journal; session_drop only when the human asks.
|
|
23
|
+
|
|
24
|
+
Forks:
|
|
25
|
+
- agent_update (status running, short note) at meaningful progress.
|
|
26
|
+
- agent_done with the report path as your LAST tool action; has_questions=true when the report asks the human something. Then reply with one line only: the report holds the detail.
|
|
27
|
+
- Never agent_start, never table_set.
|
|
28
|
+
|
|
29
|
+
Statuses (emoji shown to the human = the NEXT action): running ⏳ fork working · discussing 💬 · answer ❓ human must answer · review 👀 human must review · apply 📥 · test 🧪 · commit ✅ · branch 🌿. Only the human applies, tests and commits.
|
|
30
|
+
|
|
31
|
+
Notes and table text: under 60 characters, no paths, no backticks.`;
|
|
32
|
+
// src/mcp/session.ts
|
|
33
|
+
const FULL_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
34
|
+
function createSessionResolver({ carnet, env = process.env, ppid = process.ppid, cwd = process.cwd(), host = hostById(DEFAULT_HOST) }) {
|
|
35
|
+
function resolveOwn() {
|
|
36
|
+
const hooked = carnet.sessions.byHostProcess(host.id, ppid);
|
|
37
|
+
if (hooked) return hooked.id;
|
|
38
|
+
const fromEnvironment = host.sessionIdFromEnvironment(env);
|
|
39
|
+
if (fromEnvironment) return carnet.sessions.ensure(fromEnvironment, cwd).id;
|
|
40
|
+
throw new CarnetError("NO_SESSION", `Cannot tell which ${host.displayName} session this is: pass \`session\`, or install the rucher SessionStart hook`);
|
|
41
|
+
}
|
|
42
|
+
function resolveOverride(override) {
|
|
43
|
+
try {
|
|
44
|
+
return carnet.sessions.find(override).id;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (!(error instanceof CarnetError) || error.code !== "SESSION_NOT_FOUND") throw error;
|
|
47
|
+
if (FULL_ID.test(override)) return carnet.sessions.ensure(override, cwd).id;
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { resolve(override) {
|
|
52
|
+
const id = override ? resolveOverride(override) : resolveOwn();
|
|
53
|
+
carnet.sessions.touch(id);
|
|
54
|
+
return id;
|
|
55
|
+
} };
|
|
56
|
+
}
|
|
57
|
+
// src/mcp/tools.ts
|
|
58
|
+
function defineTool(definition) {
|
|
59
|
+
return definition;
|
|
60
|
+
}
|
|
61
|
+
const session = z.string().optional().describe("Session to target (name, id or id prefix). Omit for the current session.");
|
|
62
|
+
const agentName = z.string().min(1).describe("Short agent name, no paths");
|
|
63
|
+
const agentStart = defineTool({
|
|
64
|
+
name: "agent_start",
|
|
65
|
+
description: "Main agent only. Register a fork before dispatching it (launch it in a later message). The agent appears as ⏳ running and a `started` event is logged. The result gives the report destination: where main copies the fork report once it finishes, in the group meta directory, outside the repos.",
|
|
66
|
+
schema: z.object({
|
|
67
|
+
name: agentName,
|
|
68
|
+
task: z.string().min(1).describe("One-line task given to the fork"),
|
|
69
|
+
base_commit: z.string().optional().describe("Commit the fork starts from"),
|
|
70
|
+
worktree: z.string().optional().describe("Worktree path when the fork has one"),
|
|
71
|
+
session
|
|
72
|
+
}),
|
|
73
|
+
run: (carnet, sessionId, args) => {
|
|
74
|
+
const agent = carnet.agents.start(sessionId, {
|
|
75
|
+
name: args.name,
|
|
76
|
+
task: args.task,
|
|
77
|
+
baseCommit: args.base_commit,
|
|
78
|
+
worktree: args.worktree
|
|
79
|
+
});
|
|
80
|
+
mkdirSync(reportsDirectoryOf(carnet.group), { recursive: true });
|
|
81
|
+
const reportDestination = reportPathFor(carnet.group, agent.name);
|
|
82
|
+
return {
|
|
83
|
+
text: `${EMOJI.running} ${agent.name} started\nReport destination: ${reportDestination}`,
|
|
84
|
+
data: {
|
|
85
|
+
agent,
|
|
86
|
+
reportDestination
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const agentUpdate = defineTool({
|
|
92
|
+
name: "agent_update",
|
|
93
|
+
description: "Change an agent's status and displayed note. Forks use it with status `running` to show progress; the main agent uses user-action statuses (discussing, answer, review, apply, test, commit, branch) as the next step moves, and sets report_path after copying a report to its final place. Use agent_drop to close.",
|
|
94
|
+
schema: z.object({
|
|
95
|
+
name: agentName,
|
|
96
|
+
status: z.enum(OPEN_AGENT_STATUSES).describe("Next action: running means the fork is working"),
|
|
97
|
+
note: z.string().optional().describe("Under 60 characters, no paths, no backticks"),
|
|
98
|
+
report_path: z.string().optional().describe("New absolute path of the report, when it moved"),
|
|
99
|
+
session
|
|
100
|
+
}),
|
|
101
|
+
run: (carnet, sessionId, args) => {
|
|
102
|
+
const agent = carnet.agents.update(sessionId, args.name, {
|
|
103
|
+
status: args.status,
|
|
104
|
+
note: args.note,
|
|
105
|
+
reportPath: args.report_path
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
text: renderAgentLine({
|
|
109
|
+
name: agent.name,
|
|
110
|
+
status: agent.status,
|
|
111
|
+
emoji: agent.status === "closed" ? "" : EMOJI[agent.status],
|
|
112
|
+
note: agent.note
|
|
113
|
+
}),
|
|
114
|
+
data: { agent }
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const agentDone = defineTool({
|
|
119
|
+
name: "agent_done",
|
|
120
|
+
description: "Forks call this as their LAST tool action, then reply with one line. Records the report path and the outcome: ❓ answer (has_questions=true) or 👀 review, shown once the fork has really stopped. Logs a `finished` event then.",
|
|
121
|
+
schema: z.object({
|
|
122
|
+
name: agentName,
|
|
123
|
+
report_path: z.string().min(1).describe("Absolute path of the markdown report"),
|
|
124
|
+
has_questions: z.boolean().describe("true when the report asks the human something"),
|
|
125
|
+
session
|
|
126
|
+
}),
|
|
127
|
+
run: (carnet, sessionId, args) => {
|
|
128
|
+
const agent = carnet.agents.finish(sessionId, args.name, {
|
|
129
|
+
reportPath: args.report_path,
|
|
130
|
+
hasQuestions: args.has_questions
|
|
131
|
+
});
|
|
132
|
+
const outcome = args.has_questions ? `${EMOJI.answer} ${agent.name} needs answers` : `${EMOJI.review} ${agent.name} ready for review`;
|
|
133
|
+
return {
|
|
134
|
+
text: agent.status === "running" ? `${outcome} once you stop; reply with one line now` : outcome,
|
|
135
|
+
data: { agent }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const agentDrop = defineTool({
|
|
140
|
+
name: "agent_drop",
|
|
141
|
+
description: "Main agent only. Close an agent once its work is committed or abandoned. It leaves the status view; history stays in the journal.",
|
|
142
|
+
schema: z.object({
|
|
143
|
+
name: agentName,
|
|
144
|
+
reason: z.string().optional().describe("Why it is closed, for the journal"),
|
|
145
|
+
session
|
|
146
|
+
}),
|
|
147
|
+
run: (carnet, sessionId, args) => {
|
|
148
|
+
const agent = carnet.agents.drop(sessionId, args.name, args.reason);
|
|
149
|
+
return {
|
|
150
|
+
text: `${agent.name} closed`,
|
|
151
|
+
data: { agent }
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
const agentList = defineTool({
|
|
156
|
+
name: "agent_list",
|
|
157
|
+
description: "List the open agents of the session with status, note, task and report path.",
|
|
158
|
+
schema: z.object({ session }),
|
|
159
|
+
run: (carnet, sessionId) => {
|
|
160
|
+
const agents = carnet.agents.list(sessionId);
|
|
161
|
+
const lines = agents.map((agent) => {
|
|
162
|
+
const emoji = agent.status === "closed" ? "" : EMOJI[agent.status];
|
|
163
|
+
const note = agent.note ? ` — ${agent.note}` : "";
|
|
164
|
+
const report = agent.reportPath ? ` (report: ${agent.reportPath})` : "";
|
|
165
|
+
return `${emoji} ${agent.name} [${agent.status}]${note}${report}`;
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
text: lines.length ? lines.join("\n") : "no open agents",
|
|
169
|
+
data: { agents }
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const queueReorder = defineTool({
|
|
174
|
+
name: "queue_reorder",
|
|
175
|
+
description: "Main agent only. Set the order of the 'Waiting on you' list. Named agents come first in the given order, the others follow the default order (answer, review, rest).",
|
|
176
|
+
schema: z.object({
|
|
177
|
+
names: z.array(agentName).min(1).describe("Agent names in handling order"),
|
|
178
|
+
session
|
|
179
|
+
}),
|
|
180
|
+
run: (carnet, sessionId, args) => {
|
|
181
|
+
carnet.agents.reorderQueue(sessionId, args.names);
|
|
182
|
+
const view = carnet.status.view(carnet.sessions.require(sessionId));
|
|
183
|
+
const order = view.waiting.map((line) => line.name).join(", ");
|
|
184
|
+
return {
|
|
185
|
+
text: order ? `Waiting order: ${order}` : "nothing waiting",
|
|
186
|
+
data: { waiting: view.waiting }
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
const tableSet = defineTool({
|
|
191
|
+
name: "table_set",
|
|
192
|
+
description: "Main agent only. Set the 'On the table' line: what the main agent is handling now. main_working=true while you apply, test or fix yourself (shown ⚙️, not ready for the human). Otherwise give the status of the next human action.",
|
|
193
|
+
schema: z.object({
|
|
194
|
+
text: z.string().min(1).describe("Under 60 characters, no paths, no backticks"),
|
|
195
|
+
main_working: z.boolean().describe("true while the main agent itself is working on it"),
|
|
196
|
+
status: z.enum(USER_ACTION_STATUSES).optional().describe("Next human action when main_working is false; defaults to discussing"),
|
|
197
|
+
session
|
|
198
|
+
}),
|
|
199
|
+
run: (carnet, sessionId, args) => {
|
|
200
|
+
const item = carnet.table.set(sessionId, {
|
|
201
|
+
text: args.text,
|
|
202
|
+
mainWorking: args.main_working,
|
|
203
|
+
status: args.status
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
text: renderTableLine(item),
|
|
207
|
+
data: { table: item }
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const tableClear = defineTool({
|
|
212
|
+
name: "table_clear",
|
|
213
|
+
description: "Main agent only. Empty the 'On the table' line.",
|
|
214
|
+
schema: z.object({ session }),
|
|
215
|
+
run: (carnet, sessionId) => {
|
|
216
|
+
carnet.table.clear(sessionId);
|
|
217
|
+
return { text: "On the table cleared" };
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
const logEvent = defineTool({
|
|
221
|
+
name: "log_event",
|
|
222
|
+
description: "Append a journal event: started, finished, answered, applied, tested, committed, dropped. agent_start, agent_done and agent_drop already log theirs; use this for the human's steps (answered, applied, tested, committed).",
|
|
223
|
+
schema: z.object({
|
|
224
|
+
type: z.enum(EVENT_TYPES),
|
|
225
|
+
agent: z.string().optional().describe("Agent concerned"),
|
|
226
|
+
commit: z.string().optional().describe("Commit sha"),
|
|
227
|
+
link: z.string().optional().describe("Report path or URL"),
|
|
228
|
+
note: z.string().optional(),
|
|
229
|
+
session
|
|
230
|
+
}),
|
|
231
|
+
run: (carnet, sessionId, args) => {
|
|
232
|
+
const event = carnet.events.log(sessionId, {
|
|
233
|
+
type: args.type,
|
|
234
|
+
agent: args.agent,
|
|
235
|
+
commit: args.commit,
|
|
236
|
+
link: args.link,
|
|
237
|
+
note: args.note
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
text: [
|
|
241
|
+
"logged",
|
|
242
|
+
event.type,
|
|
243
|
+
event.agent,
|
|
244
|
+
event.commit
|
|
245
|
+
].filter(Boolean).join(" "),
|
|
246
|
+
data: { event }
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
const sessionName = z.string().trim().min(1).describe("Short session name, used by rucher resume");
|
|
251
|
+
const sessionNew = defineTool({
|
|
252
|
+
name: "session_new",
|
|
253
|
+
description: "Name the current session (or rename it) so it can be resumed later with `rucher resume <name>`. Promotes a temporary session to active.",
|
|
254
|
+
schema: z.object({
|
|
255
|
+
name: sessionName,
|
|
256
|
+
purpose: z.string().optional().describe("One line: what this session is for"),
|
|
257
|
+
session
|
|
258
|
+
}),
|
|
259
|
+
run: (carnet, sessionId, args) => {
|
|
260
|
+
const named = carnet.sessions.name(sessionId, args.name, args.purpose);
|
|
261
|
+
return {
|
|
262
|
+
text: `Session named ${named.name}. ${hostById(named.host).renameInstruction(named.name ?? args.name)}`,
|
|
263
|
+
data: { session: named }
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const sessionList = defineTool({
|
|
268
|
+
name: "session_list",
|
|
269
|
+
description: "List the group's sessions, most recently active first. Temporary and dropped ones are hidden unless asked.",
|
|
270
|
+
schema: z.object({
|
|
271
|
+
include_temporary: z.boolean().optional(),
|
|
272
|
+
include_dropped: z.boolean().optional(),
|
|
273
|
+
session
|
|
274
|
+
}),
|
|
275
|
+
run: (carnet, sessionId, args) => {
|
|
276
|
+
const sessions = carnet.sessions.list({
|
|
277
|
+
includeTemporary: args.include_temporary,
|
|
278
|
+
includeDropped: args.include_dropped
|
|
279
|
+
});
|
|
280
|
+
const lines = sessions.map((listed) => {
|
|
281
|
+
const current = listed.id === sessionId ? " (current)" : "";
|
|
282
|
+
return `${sessionLabel(listed)} [${listed.status}]${current}`;
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
text: lines.length ? lines.join("\n") : "no sessions",
|
|
286
|
+
data: { sessions }
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
const sessionDrop = defineTool({
|
|
291
|
+
name: "session_drop",
|
|
292
|
+
description: "Main agent only. Drop a session by name, id or id prefix: its open agents are closed and it leaves the lists. History stays in the journal.",
|
|
293
|
+
schema: z.object({
|
|
294
|
+
name: z.string().trim().min(1).describe("Session name, id or id prefix"),
|
|
295
|
+
session
|
|
296
|
+
}),
|
|
297
|
+
run: (carnet, _sessionId, args) => {
|
|
298
|
+
const dropped = carnet.sessions.drop(carnet.sessions.find(args.name).id);
|
|
299
|
+
return {
|
|
300
|
+
text: `Session ${sessionLabel(dropped)} dropped`,
|
|
301
|
+
data: { session: dropped }
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
const sessionResumeInfo = defineTool({
|
|
306
|
+
name: "session_resume_info",
|
|
307
|
+
description: "What a session was doing: its status view and last events, plus the command to resume it. Defaults to the current session.",
|
|
308
|
+
schema: z.object({
|
|
309
|
+
name: z.string().trim().min(1).optional().describe("Session name, id or id prefix"),
|
|
310
|
+
session
|
|
311
|
+
}),
|
|
312
|
+
run: (carnet, sessionId, args) => {
|
|
313
|
+
const target = args.name ? carnet.sessions.find(args.name) : carnet.sessions.require(sessionId);
|
|
314
|
+
const resume = `rucher resume ${target.name ?? target.id}`;
|
|
315
|
+
return {
|
|
316
|
+
text: `${resumeContext(carnet, target)}\n\nResume with: ${resume}`,
|
|
317
|
+
data: {
|
|
318
|
+
session: target,
|
|
319
|
+
resume
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
const TOOLS = [
|
|
325
|
+
agentStart,
|
|
326
|
+
agentUpdate,
|
|
327
|
+
agentDone,
|
|
328
|
+
agentDrop,
|
|
329
|
+
agentList,
|
|
330
|
+
queueReorder,
|
|
331
|
+
tableSet,
|
|
332
|
+
tableClear,
|
|
333
|
+
logEvent,
|
|
334
|
+
defineTool({
|
|
335
|
+
name: "log_read",
|
|
336
|
+
description: "Read the last journal events of the session, oldest first.",
|
|
337
|
+
schema: z.object({
|
|
338
|
+
limit: z.number().int().min(1).max(200).optional().describe("Number of events, default 20"),
|
|
339
|
+
session
|
|
340
|
+
}),
|
|
341
|
+
run: (carnet, sessionId, args) => {
|
|
342
|
+
const events = carnet.events.read(sessionId, args.limit ?? 20);
|
|
343
|
+
return {
|
|
344
|
+
text: events.length ? events.map(formatEventLine).join("\n") : "no events yet",
|
|
345
|
+
data: { events }
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}),
|
|
349
|
+
sessionNew,
|
|
350
|
+
sessionList,
|
|
351
|
+
sessionDrop,
|
|
352
|
+
sessionResumeInfo
|
|
353
|
+
];
|
|
354
|
+
// src/mcp/server.ts
|
|
355
|
+
const SERVER_NAME = "carnet";
|
|
356
|
+
const SERVER_VERSION = "0.0.0";
|
|
357
|
+
function errorResult(error) {
|
|
358
|
+
return {
|
|
359
|
+
isError: true,
|
|
360
|
+
content: [{
|
|
361
|
+
type: "text",
|
|
362
|
+
text: `${error.code}: ${error.message}`
|
|
363
|
+
}]
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function createCarnetServer(options) {
|
|
367
|
+
let carnet;
|
|
368
|
+
let resolver;
|
|
369
|
+
const open = () => {
|
|
370
|
+
carnet ??= typeof options.carnet === "function" ? options.carnet() : options.carnet;
|
|
371
|
+
resolver ??= createSessionResolver({
|
|
372
|
+
...options,
|
|
373
|
+
carnet
|
|
374
|
+
});
|
|
375
|
+
return {
|
|
376
|
+
carnet,
|
|
377
|
+
resolver
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
const server = new McpServer({
|
|
381
|
+
name: SERVER_NAME,
|
|
382
|
+
version: SERVER_VERSION
|
|
383
|
+
}, { instructions: INSTRUCTIONS });
|
|
384
|
+
for (const tool of TOOLS) server.registerTool(tool.name, {
|
|
385
|
+
description: tool.description,
|
|
386
|
+
inputSchema: tool.schema
|
|
387
|
+
}, (args) => {
|
|
388
|
+
try {
|
|
389
|
+
const { carnet, resolver } = open();
|
|
390
|
+
const sessionId = resolver.resolve(args.session);
|
|
391
|
+
const out = tool.run(carnet, sessionId, args);
|
|
392
|
+
return {
|
|
393
|
+
content: [{
|
|
394
|
+
type: "text",
|
|
395
|
+
text: out.text
|
|
396
|
+
}],
|
|
397
|
+
structuredContent: out.data
|
|
398
|
+
};
|
|
399
|
+
} catch (error) {
|
|
400
|
+
if (error instanceof CarnetError) return errorResult(error);
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
return server;
|
|
405
|
+
}
|
|
406
|
+
function serveCarnet(options = {}) {
|
|
407
|
+
const carnet = options.carnet ?? (() => openCarnet(options));
|
|
408
|
+
return serveStdio(() => createCarnetServer({
|
|
409
|
+
carnet,
|
|
410
|
+
env: options.env,
|
|
411
|
+
ppid: options.ppid,
|
|
412
|
+
cwd: options.cwd
|
|
413
|
+
}), { onerror: (error) => console.error(`[carnet] ${error.message}`) });
|
|
414
|
+
}
|
|
415
|
+
export { INSTRUCTIONS, SERVER_NAME, SERVER_VERSION, TOOLS, createCarnetServer, createSessionResolver, serveCarnet };
|
|
416
|
+
|
|
417
|
+
//# sourceMappingURL=mcp.mjs.map
|
package/dist/mcp.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.mjs","names":[],"sources":["../src/mcp/instructions.ts","../src/mcp/session.ts","../src/mcp/tools.ts","../src/mcp/server.ts"],"sourcesContent":["export const INSTRUCTIONS = `Carnet tracks the status of sub-agents (forks) for the human, in a shared database. Views are rendered by the \\`rucher\\` CLI.\n\nRules:\n- Never write status files (agents-status.md or similar) and never describe status updates in the chat. When a fork finishes, the main agent says only \"<name> finished, report ready\".\n- Update BEFORE and AFTER each piece of work, never batched at the end of a turn.\n- Your session is resolved automatically. Pass \\`session\\` only to target another session.\n\nMain agent:\n- agent_start before dispatching a fork (name, task), in an earlier message than the launch; launch parallel forks in the same order. Names are short, no paths.\n- table_set with main_working=true before applying, testing or fixing yourself; table_set with a status (or table_clear) when done.\n- log_event when a step is answered, applied, tested, committed or dropped.\n- When a fork finishes: say one line \"<name> finished, report ready\", copy its report to the report destination agent_start gave (.rucher/reports/<name>.md in the group meta directory) and call agent_update with that report_path. Present the report only when asked.\n- For dispatching, applying or reviewing forks, load the rucher skill: it holds the full workflow.\n- agent_drop when a fork's work is committed or abandoned. queue_reorder to change the handling order.\n- agent_list to recall where things stand.\n- Sessions: session_new when the human names this session (then ask them to /rename it the same way); session_list, session_resume_info and log_read to recall other sessions or the journal; session_drop only when the human asks.\n\nForks:\n- agent_update (status running, short note) at meaningful progress.\n- agent_done with the report path as your LAST tool action; has_questions=true when the report asks the human something. Then reply with one line only: the report holds the detail.\n- Never agent_start, never table_set.\n\nStatuses (emoji shown to the human = the NEXT action): running ⏳ fork working · discussing 💬 · answer ❓ human must answer · review 👀 human must review · apply 📥 · test 🧪 · commit ✅ · branch 🌿. Only the human applies, tests and commits.\n\nNotes and table text: under 60 characters, no paths, no backticks.`;\n","import type { Carnet } from '../carnet.ts';\nimport { CarnetError } from '../errors.ts';\nimport { DEFAULT_HOST, type Host, hostById } from '../hosts/host.ts';\n\nconst FULL_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport interface SessionResolverOptions {\n carnet: Carnet;\n env?: NodeJS.ProcessEnv | undefined;\n ppid?: number | undefined;\n cwd?: string | undefined;\n host?: Host | undefined;\n}\n\nexport interface SessionResolver {\n resolve(override?: string): string;\n}\n\nexport function createSessionResolver({\n carnet,\n env = process.env,\n ppid = process.ppid,\n cwd = process.cwd(),\n host = hostById(DEFAULT_HOST),\n}: SessionResolverOptions): SessionResolver {\n // Not cached: after --continue or the resume picker, the server env keeps a provisional\n // startup id, and the hook that records the real one can arrive after the server starts.\n function resolveOwn(): string {\n const hooked = carnet.sessions.byHostProcess(host.id, ppid);\n if (hooked) return hooked.id;\n const fromEnvironment = host.sessionIdFromEnvironment(env);\n if (fromEnvironment) return carnet.sessions.ensure(fromEnvironment, cwd).id;\n throw new CarnetError(\n 'NO_SESSION',\n `Cannot tell which ${host.displayName} session this is: pass \\`session\\`, or install the rucher SessionStart hook`,\n );\n }\n\n function resolveOverride(override: string): string {\n try {\n return carnet.sessions.find(override).id;\n } catch (error) {\n if (!(error instanceof CarnetError) || error.code !== 'SESSION_NOT_FOUND') throw error;\n // A full session id the hook never recorded still gets its row.\n if (FULL_ID.test(override)) return carnet.sessions.ensure(override, cwd).id;\n throw error;\n }\n }\n\n return {\n resolve(override) {\n const id = override ? resolveOverride(override) : resolveOwn();\n carnet.sessions.touch(id);\n return id;\n },\n };\n}\n","import { mkdirSync } from 'node:fs';\nimport * as z from 'zod/v4';\nimport type { Carnet } from '../carnet.ts';\nimport { EVENT_TYPES } from '../events.ts';\nimport { reportPathFor, reportsDirectoryOf } from '../group/locate.ts';\nimport { hostById } from '../hosts/host.ts';\nimport { formatEventLine, resumeContext, sessionLabel } from '../resume.ts';\nimport { EMOJI, OPEN_AGENT_STATUSES, USER_ACTION_STATUSES } from '../status/model.ts';\nimport { renderAgentLine, renderTableLine } from '../status/render.ts';\n\nexport interface ToolOutput {\n text: string;\n data?: Record<string, unknown>;\n}\n\nexport interface ToolDefinition<Schema extends z.ZodObject = z.ZodObject> {\n name: string;\n description: string;\n schema: Schema;\n run: (carnet: Carnet, sessionId: string, args: z.infer<Schema>) => ToolOutput;\n}\n\nfunction defineTool<Schema extends z.ZodObject>(\n definition: ToolDefinition<Schema>,\n): ToolDefinition<Schema> {\n return definition;\n}\n\nconst session = z\n .string()\n .optional()\n .describe('Session to target (name, id or id prefix). Omit for the current session.');\n\nconst agentName = z.string().min(1).describe('Short agent name, no paths');\n\nconst agentStart = defineTool({\n name: 'agent_start',\n description:\n 'Main agent only. Register a fork before dispatching it (launch it in a later message). The agent appears as ⏳ running and a `started` event is logged. The result gives the report destination: where main copies the fork report once it finishes, in the group meta directory, outside the repos.',\n schema: z.object({\n name: agentName,\n task: z.string().min(1).describe('One-line task given to the fork'),\n base_commit: z.string().optional().describe('Commit the fork starts from'),\n worktree: z.string().optional().describe('Worktree path when the fork has one'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const agent = carnet.agents.start(sessionId, {\n name: args.name,\n task: args.task,\n baseCommit: args.base_commit,\n worktree: args.worktree,\n });\n mkdirSync(reportsDirectoryOf(carnet.group), { recursive: true });\n const reportDestination = reportPathFor(carnet.group, agent.name);\n return {\n text: `${EMOJI.running} ${agent.name} started\\nReport destination: ${reportDestination}`,\n data: { agent, reportDestination },\n };\n },\n});\n\nconst agentUpdate = defineTool({\n name: 'agent_update',\n description:\n \"Change an agent's status and displayed note. Forks use it with status `running` to show progress; the main agent uses user-action statuses (discussing, answer, review, apply, test, commit, branch) as the next step moves, and sets report_path after copying a report to its final place. Use agent_drop to close.\",\n schema: z.object({\n name: agentName,\n status: z.enum(OPEN_AGENT_STATUSES).describe('Next action: running means the fork is working'),\n note: z.string().optional().describe('Under 60 characters, no paths, no backticks'),\n report_path: z.string().optional().describe('New absolute path of the report, when it moved'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const agent = carnet.agents.update(sessionId, args.name, {\n status: args.status,\n note: args.note,\n reportPath: args.report_path,\n });\n const text = renderAgentLine({\n name: agent.name,\n status: agent.status,\n emoji: agent.status === 'closed' ? '' : EMOJI[agent.status],\n note: agent.note,\n });\n return { text, data: { agent } };\n },\n});\n\nconst agentDone = defineTool({\n name: 'agent_done',\n description:\n 'Forks call this as their LAST tool action, then reply with one line. Records the report path and the outcome: ❓ answer (has_questions=true) or 👀 review, shown once the fork has really stopped. Logs a `finished` event then.',\n schema: z.object({\n name: agentName,\n report_path: z.string().min(1).describe('Absolute path of the markdown report'),\n has_questions: z.boolean().describe('true when the report asks the human something'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const agent = carnet.agents.finish(sessionId, args.name, {\n reportPath: args.report_path,\n hasQuestions: args.has_questions,\n });\n const outcome = args.has_questions\n ? `${EMOJI.answer} ${agent.name} needs answers`\n : `${EMOJI.review} ${agent.name} ready for review`;\n const text =\n agent.status === 'running' ? `${outcome} once you stop; reply with one line now` : outcome;\n return { text, data: { agent } };\n },\n});\n\nconst agentDrop = defineTool({\n name: 'agent_drop',\n description:\n 'Main agent only. Close an agent once its work is committed or abandoned. It leaves the status view; history stays in the journal.',\n schema: z.object({\n name: agentName,\n reason: z.string().optional().describe('Why it is closed, for the journal'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const agent = carnet.agents.drop(sessionId, args.name, args.reason);\n return { text: `${agent.name} closed`, data: { agent } };\n },\n});\n\nconst agentList = defineTool({\n name: 'agent_list',\n description: 'List the open agents of the session with status, note, task and report path.',\n schema: z.object({ session }),\n run: (carnet, sessionId) => {\n const agents = carnet.agents.list(sessionId);\n const lines = agents.map((agent) => {\n const emoji = agent.status === 'closed' ? '' : EMOJI[agent.status];\n const note = agent.note ? ` — ${agent.note}` : '';\n const report = agent.reportPath ? ` (report: ${agent.reportPath})` : '';\n return `${emoji} ${agent.name} [${agent.status}]${note}${report}`;\n });\n return { text: lines.length ? lines.join('\\n') : 'no open agents', data: { agents } };\n },\n});\n\nconst queueReorder = defineTool({\n name: 'queue_reorder',\n description:\n \"Main agent only. Set the order of the 'Waiting on you' list. Named agents come first in the given order, the others follow the default order (answer, review, rest).\",\n schema: z.object({\n names: z.array(agentName).min(1).describe('Agent names in handling order'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n carnet.agents.reorderQueue(sessionId, args.names);\n const view = carnet.status.view(carnet.sessions.require(sessionId));\n const order = view.waiting.map((line) => line.name).join(', ');\n return {\n text: order ? `Waiting order: ${order}` : 'nothing waiting',\n data: { waiting: view.waiting },\n };\n },\n});\n\nconst tableSet = defineTool({\n name: 'table_set',\n description:\n \"Main agent only. Set the 'On the table' line: what the main agent is handling now. main_working=true while you apply, test or fix yourself (shown ⚙️, not ready for the human). Otherwise give the status of the next human action.\",\n schema: z.object({\n text: z.string().min(1).describe('Under 60 characters, no paths, no backticks'),\n main_working: z.boolean().describe('true while the main agent itself is working on it'),\n status: z\n .enum(USER_ACTION_STATUSES)\n .optional()\n .describe('Next human action when main_working is false; defaults to discussing'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const item = carnet.table.set(sessionId, {\n text: args.text,\n mainWorking: args.main_working,\n status: args.status,\n });\n return { text: renderTableLine(item), data: { table: item } };\n },\n});\n\nconst tableClear = defineTool({\n name: 'table_clear',\n description: \"Main agent only. Empty the 'On the table' line.\",\n schema: z.object({ session }),\n run: (carnet, sessionId) => {\n carnet.table.clear(sessionId);\n return { text: 'On the table cleared' };\n },\n});\n\nconst logEvent = defineTool({\n name: 'log_event',\n description:\n \"Append a journal event: started, finished, answered, applied, tested, committed, dropped. agent_start, agent_done and agent_drop already log theirs; use this for the human's steps (answered, applied, tested, committed).\",\n schema: z.object({\n type: z.enum(EVENT_TYPES),\n agent: z.string().optional().describe('Agent concerned'),\n commit: z.string().optional().describe('Commit sha'),\n link: z.string().optional().describe('Report path or URL'),\n note: z.string().optional(),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const event = carnet.events.log(sessionId, {\n type: args.type,\n agent: args.agent,\n commit: args.commit,\n link: args.link,\n note: args.note,\n });\n const parts = ['logged', event.type, event.agent, event.commit].filter(Boolean);\n return { text: parts.join(' '), data: { event } };\n },\n});\n\nconst sessionName = z.string().trim().min(1).describe('Short session name, used by rucher resume');\n\nconst sessionNew = defineTool({\n name: 'session_new',\n description:\n 'Name the current session (or rename it) so it can be resumed later with `rucher resume <name>`. Promotes a temporary session to active.',\n schema: z.object({\n name: sessionName,\n purpose: z.string().optional().describe('One line: what this session is for'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const named = carnet.sessions.name(sessionId, args.name, args.purpose);\n return {\n text: `Session named ${named.name}. ${hostById(named.host).renameInstruction(named.name ?? args.name)}`,\n data: { session: named },\n };\n },\n});\n\nconst sessionList = defineTool({\n name: 'session_list',\n description:\n \"List the group's sessions, most recently active first. Temporary and dropped ones are hidden unless asked.\",\n schema: z.object({\n include_temporary: z.boolean().optional(),\n include_dropped: z.boolean().optional(),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const sessions = carnet.sessions.list({\n includeTemporary: args.include_temporary,\n includeDropped: args.include_dropped,\n });\n const lines = sessions.map((listed) => {\n const current = listed.id === sessionId ? ' (current)' : '';\n return `${sessionLabel(listed)} [${listed.status}]${current}`;\n });\n return { text: lines.length ? lines.join('\\n') : 'no sessions', data: { sessions } };\n },\n});\n\nconst sessionDrop = defineTool({\n name: 'session_drop',\n description:\n 'Main agent only. Drop a session by name, id or id prefix: its open agents are closed and it leaves the lists. History stays in the journal.',\n schema: z.object({\n name: z.string().trim().min(1).describe('Session name, id or id prefix'),\n session,\n }),\n run: (carnet, _sessionId, args) => {\n const dropped = carnet.sessions.drop(carnet.sessions.find(args.name).id);\n return { text: `Session ${sessionLabel(dropped)} dropped`, data: { session: dropped } };\n },\n});\n\nconst sessionResumeInfo = defineTool({\n name: 'session_resume_info',\n description:\n 'What a session was doing: its status view and last events, plus the command to resume it. Defaults to the current session.',\n schema: z.object({\n name: z.string().trim().min(1).optional().describe('Session name, id or id prefix'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const target = args.name ? carnet.sessions.find(args.name) : carnet.sessions.require(sessionId);\n const resume = `rucher resume ${target.name ?? target.id}`;\n return {\n text: `${resumeContext(carnet, target)}\\n\\nResume with: ${resume}`,\n data: { session: target, resume },\n };\n },\n});\n\nconst logRead = defineTool({\n name: 'log_read',\n description: 'Read the last journal events of the session, oldest first.',\n schema: z.object({\n limit: z.number().int().min(1).max(200).optional().describe('Number of events, default 20'),\n session,\n }),\n run: (carnet, sessionId, args) => {\n const events = carnet.events.read(sessionId, args.limit ?? 20);\n return {\n text: events.length ? events.map(formatEventLine).join('\\n') : 'no events yet',\n data: { events },\n };\n },\n});\n\nexport const TOOLS: readonly ToolDefinition[] = [\n agentStart,\n agentUpdate,\n agentDone,\n agentDrop,\n agentList,\n queueReorder,\n tableSet,\n tableClear,\n logEvent,\n logRead,\n sessionNew,\n sessionList,\n sessionDrop,\n sessionResumeInfo,\n] as readonly ToolDefinition[];\n","import { type CallToolResult, McpServer } from '@modelcontextprotocol/server';\nimport { serveStdio, type StdioServerHandle } from '@modelcontextprotocol/server/stdio';\nimport type { Carnet } from '../carnet.ts';\nimport { openCarnet, type OpenCarnetOptions } from '../carnet.ts';\nimport { CarnetError } from '../errors.ts';\nimport { INSTRUCTIONS } from './instructions.ts';\nimport {\n createSessionResolver,\n type SessionResolver,\n type SessionResolverOptions,\n} from './session.ts';\nimport { TOOLS } from './tools.ts';\n\nexport const SERVER_NAME = 'carnet';\nexport const SERVER_VERSION = '0.0.0';\n\nexport interface CarnetServerOptions extends Omit<SessionResolverOptions, 'carnet'> {\n carnet: Carnet | (() => Carnet);\n}\n\nfunction errorResult(error: CarnetError): CallToolResult {\n return { isError: true, content: [{ type: 'text', text: `${error.code}: ${error.message}` }] };\n}\n\nexport function createCarnetServer(options: CarnetServerOptions): McpServer {\n let carnet: Carnet | undefined;\n let resolver: SessionResolver | undefined;\n const open = (): { carnet: Carnet; resolver: SessionResolver } => {\n carnet ??= typeof options.carnet === 'function' ? options.carnet() : options.carnet;\n resolver ??= createSessionResolver({ ...options, carnet });\n return { carnet, resolver };\n };\n const server = new McpServer(\n { name: SERVER_NAME, version: SERVER_VERSION },\n { instructions: INSTRUCTIONS },\n );\n for (const tool of TOOLS) {\n server.registerTool(\n tool.name,\n { description: tool.description, inputSchema: tool.schema },\n (args: Record<string, unknown>): CallToolResult => {\n try {\n const { carnet, resolver } = open();\n const sessionId = resolver.resolve(args.session as string | undefined);\n const out = tool.run(carnet, sessionId, args);\n return { content: [{ type: 'text', text: out.text }], structuredContent: out.data };\n } catch (error) {\n if (error instanceof CarnetError) return errorResult(error);\n throw error;\n }\n },\n );\n }\n return server;\n}\n\nexport interface ServeCarnetOptions extends OpenCarnetOptions {\n carnet?: Carnet;\n ppid?: number;\n}\n\nexport function serveCarnet(options: ServeCarnetOptions = {}): StdioServerHandle {\n const carnet = options.carnet ?? (() => openCarnet(options));\n return serveStdio(\n () => createCarnetServer({ carnet, env: options.env, ppid: options.ppid, cwd: options.cwd }),\n { onerror: (error) => console.error(`[carnet] ${error.message}`) },\n );\n}\n"],"mappings":"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"}
|