create-byan-agent 2.12.0 → 2.12.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/_byan/mcp/byan-mcp-server/LICENSE +21 -0
- package/_byan/mcp/byan-mcp-server/README.md +56 -0
- package/_byan/mcp/byan-mcp-server/lib/cli.js +108 -0
- package/_byan/mcp/byan-mcp-server/lib/copilot.js +148 -0
- package/_byan/mcp/byan-mcp-server/lib/dispatch.js +23 -0
- package/_byan/mcp/byan-mcp-server/lib/fd-state.js +163 -0
- package/_byan/mcp/byan-mcp-server/lib/kanban.js +226 -0
- package/_byan/mcp/byan-mcp-server/lib/peer-review.js +187 -0
- package/_byan/mcp/byan-mcp-server/lib/soul.js +64 -0
- package/_byan/mcp/byan-mcp-server/lib/workflow-scripts.js +156 -0
- package/_byan/mcp/byan-mcp-server/package.json +43 -0
- package/_byan/mcp/byan-mcp-server/server.js +1047 -0
- package/install/bin/create-byan-agent-v2.js +30 -3
- package/package.json +7 -1
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import {
|
|
5
|
+
CallToolRequestSchema,
|
|
6
|
+
ListToolsRequestSchema,
|
|
7
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { dispatch } from './lib/dispatch.js';
|
|
9
|
+
import { readSoul, appendSoulMemory } from './lib/soul.js';
|
|
10
|
+
import { listSessions, readSessionEvents, searchSessions } from './lib/copilot.js';
|
|
11
|
+
import {
|
|
12
|
+
start as fdStart,
|
|
13
|
+
status as fdStatus,
|
|
14
|
+
advance as fdAdvance,
|
|
15
|
+
update as fdUpdate,
|
|
16
|
+
abort as fdAbort,
|
|
17
|
+
ALL_PHASES as FD_PHASES,
|
|
18
|
+
} from './lib/fd-state.js';
|
|
19
|
+
import {
|
|
20
|
+
requestReview,
|
|
21
|
+
recordVerdict,
|
|
22
|
+
getReview,
|
|
23
|
+
listPending,
|
|
24
|
+
pickReviewer,
|
|
25
|
+
} from './lib/peer-review.js';
|
|
26
|
+
import {
|
|
27
|
+
createBoard,
|
|
28
|
+
addCard,
|
|
29
|
+
moveCard,
|
|
30
|
+
assignCard,
|
|
31
|
+
getBoard,
|
|
32
|
+
postStandup,
|
|
33
|
+
readStandups,
|
|
34
|
+
detectBlockedStreaks,
|
|
35
|
+
KANBAN_COLUMNS,
|
|
36
|
+
} from './lib/kanban.js';
|
|
37
|
+
import {
|
|
38
|
+
eloSummary,
|
|
39
|
+
eloContext,
|
|
40
|
+
eloDashboard,
|
|
41
|
+
eloRecord,
|
|
42
|
+
fcCheck,
|
|
43
|
+
fcParse,
|
|
44
|
+
} from './lib/cli.js';
|
|
45
|
+
import {
|
|
46
|
+
listScripts,
|
|
47
|
+
getScript,
|
|
48
|
+
createScript,
|
|
49
|
+
updateScript,
|
|
50
|
+
deleteScript,
|
|
51
|
+
getScriptHistory,
|
|
52
|
+
rollbackScript,
|
|
53
|
+
importScript,
|
|
54
|
+
validateScriptSyntax,
|
|
55
|
+
ALLOWED_LANGUAGES as WF_SCRIPT_LANGUAGES,
|
|
56
|
+
ALLOWED_EXEC_MODES as WF_SCRIPT_EXEC_MODES,
|
|
57
|
+
} from './lib/workflow-scripts.js';
|
|
58
|
+
|
|
59
|
+
const BYAN_API_URL = process.env.BYAN_API_URL || 'http://localhost:3737';
|
|
60
|
+
const BYAN_API_TOKEN = process.env.BYAN_API_TOKEN || '';
|
|
61
|
+
|
|
62
|
+
const authHeaders = () => {
|
|
63
|
+
if (!BYAN_API_TOKEN) return {};
|
|
64
|
+
// byan_web issues API keys prefixed with `byan_` and requires the
|
|
65
|
+
// `ApiKey` scheme. Any other token (JWT, etc.) falls back to Bearer.
|
|
66
|
+
const scheme = BYAN_API_TOKEN.startsWith('byan_') ? 'ApiKey' : 'Bearer';
|
|
67
|
+
return { Authorization: `${scheme} ${BYAN_API_TOKEN}` };
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
async function apiRequest(path, options = {}) {
|
|
71
|
+
const url = `${BYAN_API_URL}${path}`;
|
|
72
|
+
const headers = {
|
|
73
|
+
'Content-Type': 'application/json',
|
|
74
|
+
...authHeaders(),
|
|
75
|
+
...(options.headers || {}),
|
|
76
|
+
};
|
|
77
|
+
const res = await fetch(url, { ...options, headers });
|
|
78
|
+
const text = await res.text();
|
|
79
|
+
let body;
|
|
80
|
+
try {
|
|
81
|
+
body = text ? JSON.parse(text) : null;
|
|
82
|
+
} catch {
|
|
83
|
+
body = text;
|
|
84
|
+
}
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
const err = new Error(`${res.status} ${res.statusText}: ${text}`);
|
|
87
|
+
err.status = res.status;
|
|
88
|
+
err.body = body;
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
return body;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const tools = [
|
|
95
|
+
{
|
|
96
|
+
name: 'byan_ping',
|
|
97
|
+
description:
|
|
98
|
+
'Healthcheck the byan_web API. Returns status and version. No auth required. Also reports round-trip latency and whether BYAN_API_TOKEN is configured.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {},
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'byan_list_projects',
|
|
107
|
+
description:
|
|
108
|
+
'List all BYAN projects stored in byan_web. Returns projects ordered by creation date (most recent first). Requires BYAN_API_TOKEN env var set to a valid JWT.',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {
|
|
112
|
+
limit: {
|
|
113
|
+
type: 'number',
|
|
114
|
+
description:
|
|
115
|
+
'Optional client-side limit (server returns all, truncated here). Default: 50.',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
additionalProperties: false,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'byan_import_project',
|
|
123
|
+
description:
|
|
124
|
+
'Import a local project directory into byan_web. Scans BMAD artifacts (_bmad-output/, docs/, _bmad/_memory/). Requires auth.',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
path: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: 'Absolute path to the project directory to import.',
|
|
131
|
+
},
|
|
132
|
+
name: { type: 'string', description: 'Optional project name override.' },
|
|
133
|
+
type: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
enum: ['dev', 'training'],
|
|
136
|
+
description: 'Project type. Default: dev.',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
required: ['path'],
|
|
140
|
+
additionalProperties: false,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'byan_dispatch',
|
|
145
|
+
description:
|
|
146
|
+
'BYAN Dispatcher: given a task description and complexity score (0-100), route it to the optimal execution target. Rule-based, no API call. Returns route and reasoning.',
|
|
147
|
+
inputSchema: {
|
|
148
|
+
type: 'object',
|
|
149
|
+
properties: {
|
|
150
|
+
task: { type: 'string', description: 'Short task description.' },
|
|
151
|
+
complexity: {
|
|
152
|
+
type: 'number',
|
|
153
|
+
description: 'Complexity score 0-100 (optional, will estimate from task length if absent).',
|
|
154
|
+
},
|
|
155
|
+
parallelizable: {
|
|
156
|
+
type: 'boolean',
|
|
157
|
+
description: 'Is the task parallelizable with other tasks?',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
required: ['task'],
|
|
161
|
+
additionalProperties: false,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'byan_soul_read',
|
|
166
|
+
description:
|
|
167
|
+
'Read the BYAN soul/tao/soul-memory files from the current project. No auth. Useful when the agent needs to reference the current soul configuration mid-session without relying solely on the SessionStart hook injection.',
|
|
168
|
+
inputSchema: {
|
|
169
|
+
type: 'object',
|
|
170
|
+
properties: {
|
|
171
|
+
which: {
|
|
172
|
+
type: 'string',
|
|
173
|
+
enum: ['soul', 'tao', 'soul-memory', 'all'],
|
|
174
|
+
description: 'Which file to read. Default: all.',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
additionalProperties: false,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'byan_soul_memory_append',
|
|
182
|
+
description:
|
|
183
|
+
'Append a validated entry to _byan/soul-memory.md. Requires validated=true — the caller must have explicit user confirmation before invoking this tool (per BYAN rule: never write silently to soul-memory).',
|
|
184
|
+
inputSchema: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
entry: { type: 'string', description: 'The entry text (markdown allowed).' },
|
|
188
|
+
validated: {
|
|
189
|
+
type: 'boolean',
|
|
190
|
+
description: 'Must be true. Confirms the entry was validated by the user.',
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
required: ['entry', 'validated'],
|
|
194
|
+
additionalProperties: false,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'byan_elo_summary',
|
|
199
|
+
description:
|
|
200
|
+
'ELO trust summary across all technical domains. Wraps `byan-v2-cli elo summary`. No auth. Returns ratings, trends, session counts.',
|
|
201
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'byan_elo_context',
|
|
205
|
+
description:
|
|
206
|
+
'Challenge-context for a specific domain (returns promptInstructions BYAN should apply when challenging a claim). Wraps `byan-v2-cli elo context <domain>`.',
|
|
207
|
+
inputSchema: {
|
|
208
|
+
type: 'object',
|
|
209
|
+
properties: {
|
|
210
|
+
domain: { type: 'string', description: 'Domain name (security|javascript|performance|...)' },
|
|
211
|
+
},
|
|
212
|
+
required: ['domain'],
|
|
213
|
+
additionalProperties: false,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: 'byan_elo_record',
|
|
218
|
+
description:
|
|
219
|
+
'Record the outcome of a user claim on a domain. Wraps `byan-v2-cli elo record <domain> <VALIDATED|BLOCKED|PARTIAL>`.',
|
|
220
|
+
inputSchema: {
|
|
221
|
+
type: 'object',
|
|
222
|
+
properties: {
|
|
223
|
+
domain: { type: 'string' },
|
|
224
|
+
result: { type: 'string', enum: ['VALIDATED', 'BLOCKED', 'PARTIAL'] },
|
|
225
|
+
reason: { type: 'string' },
|
|
226
|
+
},
|
|
227
|
+
required: ['domain', 'result'],
|
|
228
|
+
additionalProperties: false,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'byan_fc_check',
|
|
233
|
+
description:
|
|
234
|
+
'Run fact-check on a claim string. Returns assertion type (REASONING|HYPOTHESIS|CLAIM L{n}|FACT), level, score. Wraps `byan-v2-cli fc check <text>`.',
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: { text: { type: 'string', description: 'Assertion to fact-check.' } },
|
|
238
|
+
required: ['text'],
|
|
239
|
+
additionalProperties: false,
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'byan_fc_parse',
|
|
244
|
+
description:
|
|
245
|
+
'Parse a text for auto-detection patterns (absolutes, superlatives, unsourced best-practice claims). Wraps `byan-v2-cli fc parse <text>`.',
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: 'object',
|
|
248
|
+
properties: { text: { type: 'string' } },
|
|
249
|
+
required: ['text'],
|
|
250
|
+
additionalProperties: false,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'byan_copilot_sessions',
|
|
255
|
+
description:
|
|
256
|
+
'List GitHub Copilot CLI sessions stored locally at ~/.copilot/session-state/. Returns sessionId, start/end time, cwd, branch, agent name, message and tool call counts. Sorted most-recent-first. Use to discover past Copilot CLI conversations for reference or import.',
|
|
257
|
+
inputSchema: {
|
|
258
|
+
type: 'object',
|
|
259
|
+
properties: {
|
|
260
|
+
limit: { type: 'number', description: 'Max sessions to return (default 20).' },
|
|
261
|
+
sinceIso: { type: 'string', description: 'ISO timestamp filter — only sessions started after this.' },
|
|
262
|
+
cwdFilter: { type: 'string', description: 'Substring match on session cwd (e.g. "byan_web").' },
|
|
263
|
+
},
|
|
264
|
+
additionalProperties: false,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'byan_copilot_session_events',
|
|
269
|
+
description:
|
|
270
|
+
'Read events of a specific Copilot CLI session (events.jsonl). Optionally filter by event type (user.message, assistant.message, tool.execution_start, etc.). Useful to inspect the flow of a past session.',
|
|
271
|
+
inputSchema: {
|
|
272
|
+
type: 'object',
|
|
273
|
+
properties: {
|
|
274
|
+
sessionId: { type: 'string', description: 'Session UUID from byan_copilot_sessions.' },
|
|
275
|
+
types: {
|
|
276
|
+
type: 'array',
|
|
277
|
+
items: { type: 'string' },
|
|
278
|
+
description: 'Filter to these event types only.',
|
|
279
|
+
},
|
|
280
|
+
limit: { type: 'number', description: 'Max events (default 200).' },
|
|
281
|
+
},
|
|
282
|
+
required: ['sessionId'],
|
|
283
|
+
additionalProperties: false,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: 'byan_fd_start',
|
|
288
|
+
description:
|
|
289
|
+
'Start a new Feature Development (FD) cycle for BYAN. Writes _byan-output/fd-state.json with phase=BRAINSTORM. Rejects if another FD is already in progress (unless force=true).',
|
|
290
|
+
inputSchema: {
|
|
291
|
+
type: 'object',
|
|
292
|
+
properties: {
|
|
293
|
+
featureName: { type: 'string', description: 'Short slug for the feature.' },
|
|
294
|
+
force: { type: 'boolean', description: 'Overwrite an existing in-progress FD.' },
|
|
295
|
+
},
|
|
296
|
+
required: ['featureName'],
|
|
297
|
+
additionalProperties: false,
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: 'byan_fd_status',
|
|
302
|
+
description:
|
|
303
|
+
'Return the current FD state (phase, backlog, dispatch_table, history) or { active: false } if none. Use at the start of a turn to know which phase to be in.',
|
|
304
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: 'byan_fd_advance',
|
|
308
|
+
description:
|
|
309
|
+
'Transition the current FD session to another phase. Valid targets : BRAINSTORM | PRUNE | DISPATCH | BUILD | VALIDATE | COMPLETED | ABORTED. Rejects backward moves (except abort).',
|
|
310
|
+
inputSchema: {
|
|
311
|
+
type: 'object',
|
|
312
|
+
properties: {
|
|
313
|
+
to: {
|
|
314
|
+
type: 'string',
|
|
315
|
+
enum: ['BRAINSTORM', 'PRUNE', 'DISPATCH', 'BUILD', 'VALIDATE', 'COMPLETED', 'ABORTED'],
|
|
316
|
+
},
|
|
317
|
+
note: { type: 'string', description: 'Optional gate-crossing rationale.' },
|
|
318
|
+
},
|
|
319
|
+
required: ['to'],
|
|
320
|
+
additionalProperties: false,
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: 'byan_fd_update',
|
|
325
|
+
description:
|
|
326
|
+
'Patch fields on the active FD state. Allowed keys : backlog, dispatch_table, commits, notes, feature_name. Rejects unknown keys.',
|
|
327
|
+
inputSchema: {
|
|
328
|
+
type: 'object',
|
|
329
|
+
properties: {
|
|
330
|
+
patch: { type: 'object', description: 'Partial object of allowed keys.' },
|
|
331
|
+
},
|
|
332
|
+
required: ['patch'],
|
|
333
|
+
additionalProperties: false,
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: 'byan_fd_abort',
|
|
338
|
+
description:
|
|
339
|
+
'Abort the current FD session (phase → ABORTED). Preserves the state file for inspection.',
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: 'object',
|
|
342
|
+
properties: { reason: { type: 'string' } },
|
|
343
|
+
additionalProperties: false,
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: 'byan_review_request',
|
|
348
|
+
description:
|
|
349
|
+
'Open a peer review request for a task/commit. Another agent (≠ author) must subsequently call byan_review_verdict. Persists under _byan-output/reviews/<task_id>.json.',
|
|
350
|
+
inputSchema: {
|
|
351
|
+
type: 'object',
|
|
352
|
+
properties: {
|
|
353
|
+
task_id: { type: 'string', description: 'Unique id (commit sha or feature id).' },
|
|
354
|
+
author: { type: 'string', description: 'Agent name that produced the artefact.' },
|
|
355
|
+
artifact_paths: { type: 'array', items: { type: 'string' } },
|
|
356
|
+
description: { type: 'string' },
|
|
357
|
+
},
|
|
358
|
+
required: ['task_id', 'author'],
|
|
359
|
+
additionalProperties: false,
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: 'byan_review_verdict',
|
|
364
|
+
description:
|
|
365
|
+
'Record a verdict on an open review request. reviewer must differ from author (enforced). Valid verdicts : approve | changes | block.',
|
|
366
|
+
inputSchema: {
|
|
367
|
+
type: 'object',
|
|
368
|
+
properties: {
|
|
369
|
+
task_id: { type: 'string' },
|
|
370
|
+
reviewer: { type: 'string' },
|
|
371
|
+
verdict: { type: 'string', enum: ['approve', 'changes', 'block'] },
|
|
372
|
+
comments: { type: 'array', items: { type: 'string' } },
|
|
373
|
+
must_fix: { type: 'array', items: { type: 'string' } },
|
|
374
|
+
},
|
|
375
|
+
required: ['task_id', 'reviewer', 'verdict'],
|
|
376
|
+
additionalProperties: false,
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: 'byan_review_get',
|
|
381
|
+
description: 'Fetch the current state of a review by task_id.',
|
|
382
|
+
inputSchema: {
|
|
383
|
+
type: 'object',
|
|
384
|
+
properties: { task_id: { type: 'string' } },
|
|
385
|
+
required: ['task_id'],
|
|
386
|
+
additionalProperties: false,
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
name: 'byan_review_pending',
|
|
391
|
+
description: 'List all open (pending or changes_requested) reviews, newest first.',
|
|
392
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: 'byan_review_pick_reviewer',
|
|
396
|
+
description:
|
|
397
|
+
'Suggest a reviewer distinct from the author. Uses domain pairs (dev↔quinn, architect↔tea, pm↔sm, ux↔pm) then falls back to the roster.',
|
|
398
|
+
inputSchema: {
|
|
399
|
+
type: 'object',
|
|
400
|
+
properties: {
|
|
401
|
+
author: { type: 'string' },
|
|
402
|
+
preferredDomain: { type: 'string' },
|
|
403
|
+
},
|
|
404
|
+
required: ['author'],
|
|
405
|
+
additionalProperties: false,
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
name: 'byan_kanban_create',
|
|
410
|
+
description:
|
|
411
|
+
'Create (or fetch existing) kanban board for a party-mode session. Columns : todo | doing | blocked | review | done. Persisted under _byan-output/party-mode-sessions/<session_id>/kanban.json.',
|
|
412
|
+
inputSchema: {
|
|
413
|
+
type: 'object',
|
|
414
|
+
properties: { sessionId: { type: 'string' } },
|
|
415
|
+
required: ['sessionId'],
|
|
416
|
+
additionalProperties: false,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'byan_kanban_add',
|
|
421
|
+
description: 'Add a card to the kanban. card = { id, title, assignee?, priority? (P1|P2|P3), column? }.',
|
|
422
|
+
inputSchema: {
|
|
423
|
+
type: 'object',
|
|
424
|
+
properties: {
|
|
425
|
+
sessionId: { type: 'string' },
|
|
426
|
+
card: {
|
|
427
|
+
type: 'object',
|
|
428
|
+
properties: {
|
|
429
|
+
id: { type: 'string' },
|
|
430
|
+
title: { type: 'string' },
|
|
431
|
+
assignee: { type: 'string' },
|
|
432
|
+
priority: { type: 'string' },
|
|
433
|
+
column: { type: 'string' },
|
|
434
|
+
},
|
|
435
|
+
required: ['id', 'title'],
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
required: ['sessionId', 'card'],
|
|
439
|
+
additionalProperties: false,
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: 'byan_kanban_move',
|
|
444
|
+
description:
|
|
445
|
+
'Move a card between columns. toColumn must be one of todo | doing | blocked | review | done. Provide blocker_reason when moving to blocked.',
|
|
446
|
+
inputSchema: {
|
|
447
|
+
type: 'object',
|
|
448
|
+
properties: {
|
|
449
|
+
sessionId: { type: 'string' },
|
|
450
|
+
cardId: { type: 'string' },
|
|
451
|
+
toColumn: { type: 'string', enum: ['todo', 'doing', 'blocked', 'review', 'done'] },
|
|
452
|
+
blocker_reason: { type: 'string' },
|
|
453
|
+
},
|
|
454
|
+
required: ['sessionId', 'cardId', 'toColumn'],
|
|
455
|
+
additionalProperties: false,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
name: 'byan_kanban_assign',
|
|
460
|
+
description: 'Assign a card to an agent.',
|
|
461
|
+
inputSchema: {
|
|
462
|
+
type: 'object',
|
|
463
|
+
properties: {
|
|
464
|
+
sessionId: { type: 'string' },
|
|
465
|
+
cardId: { type: 'string' },
|
|
466
|
+
assignee: { type: 'string' },
|
|
467
|
+
},
|
|
468
|
+
required: ['sessionId', 'cardId', 'assignee'],
|
|
469
|
+
additionalProperties: false,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: 'byan_kanban_get',
|
|
474
|
+
description: 'Fetch the current kanban board for a session.',
|
|
475
|
+
inputSchema: {
|
|
476
|
+
type: 'object',
|
|
477
|
+
properties: { sessionId: { type: 'string' } },
|
|
478
|
+
required: ['sessionId'],
|
|
479
|
+
additionalProperties: false,
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: 'byan_standup_post',
|
|
484
|
+
description:
|
|
485
|
+
'Append a stand-up entry to _byan-output/party-mode-sessions/<session_id>/standup.jsonl. Format : { agent, did, blockers[], next }.',
|
|
486
|
+
inputSchema: {
|
|
487
|
+
type: 'object',
|
|
488
|
+
properties: {
|
|
489
|
+
sessionId: { type: 'string' },
|
|
490
|
+
agent: { type: 'string' },
|
|
491
|
+
did: { type: 'string' },
|
|
492
|
+
blockers: { type: 'array', items: { type: 'string' } },
|
|
493
|
+
next: { type: 'string' },
|
|
494
|
+
},
|
|
495
|
+
required: ['sessionId', 'agent'],
|
|
496
|
+
additionalProperties: false,
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: 'byan_standup_read',
|
|
501
|
+
description: 'Read the stand-up feed for a session, newest entries last.',
|
|
502
|
+
inputSchema: {
|
|
503
|
+
type: 'object',
|
|
504
|
+
properties: {
|
|
505
|
+
sessionId: { type: 'string' },
|
|
506
|
+
limit: { type: 'number' },
|
|
507
|
+
},
|
|
508
|
+
required: ['sessionId'],
|
|
509
|
+
additionalProperties: false,
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: 'byan_standup_blocked',
|
|
514
|
+
description:
|
|
515
|
+
'Return agents with >= minStreak consecutive blocked stand-ups (default minStreak=2). Hermes uses this to trigger redispatch.',
|
|
516
|
+
inputSchema: {
|
|
517
|
+
type: 'object',
|
|
518
|
+
properties: {
|
|
519
|
+
sessionId: { type: 'string' },
|
|
520
|
+
minStreak: { type: 'number' },
|
|
521
|
+
},
|
|
522
|
+
required: ['sessionId'],
|
|
523
|
+
additionalProperties: false,
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
name: 'byan_copilot_search',
|
|
528
|
+
description:
|
|
529
|
+
'Full-text search across all Copilot CLI sessions. Finds messages (user + assistant by default) containing the query string. Returns sessionId + timestamp + excerpt. Use to recall past discussions without knowing which session they were in.',
|
|
530
|
+
inputSchema: {
|
|
531
|
+
type: 'object',
|
|
532
|
+
properties: {
|
|
533
|
+
query: { type: 'string', description: 'Substring to search for (case-insensitive).' },
|
|
534
|
+
types: {
|
|
535
|
+
type: 'array',
|
|
536
|
+
items: { type: 'string' },
|
|
537
|
+
description: 'Event types to scan (default: user.message, assistant.message).',
|
|
538
|
+
},
|
|
539
|
+
limit: { type: 'number', description: 'Max matches (default 50).' },
|
|
540
|
+
},
|
|
541
|
+
required: ['query'],
|
|
542
|
+
additionalProperties: false,
|
|
543
|
+
},
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: 'byan_workflow_script_list',
|
|
547
|
+
description:
|
|
548
|
+
'List scripts attached to a workflow node (metadata only, no content). Returns { data, total } sorted by order_idx then created_at. Requires auth + "view" access on the parent workflow.',
|
|
549
|
+
inputSchema: {
|
|
550
|
+
type: 'object',
|
|
551
|
+
properties: {
|
|
552
|
+
nodeId: { type: 'string', description: 'Workflow node id (e.g. "p0-preflight").' },
|
|
553
|
+
},
|
|
554
|
+
required: ['nodeId'],
|
|
555
|
+
additionalProperties: false,
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
name: 'byan_workflow_script_get',
|
|
560
|
+
description:
|
|
561
|
+
'Fetch a single script by id — returns decrypted content. Requires "view" access on the parent workflow.',
|
|
562
|
+
inputSchema: {
|
|
563
|
+
type: 'object',
|
|
564
|
+
properties: { id: { type: 'string', description: 'Script UUID.' } },
|
|
565
|
+
required: ['id'],
|
|
566
|
+
additionalProperties: false,
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
name: 'byan_workflow_script_create',
|
|
571
|
+
description:
|
|
572
|
+
'Create a new script attached to a workflow node. Content is encrypted at rest. Server runs a syntax check unless bypassValidation=true. Requires "edit" access.',
|
|
573
|
+
inputSchema: {
|
|
574
|
+
type: 'object',
|
|
575
|
+
properties: {
|
|
576
|
+
nodeId: { type: 'string' },
|
|
577
|
+
name: { type: 'string', description: 'Display name (<=128 chars).' },
|
|
578
|
+
language: {
|
|
579
|
+
type: 'string',
|
|
580
|
+
enum: ['bash', 'python', 'javascript', 'typescript'],
|
|
581
|
+
},
|
|
582
|
+
content: { type: 'string', description: 'Script source (max 64 kB).' },
|
|
583
|
+
execution_mode: {
|
|
584
|
+
type: 'string',
|
|
585
|
+
enum: ['context', 'local'],
|
|
586
|
+
description: 'Default "context".',
|
|
587
|
+
},
|
|
588
|
+
order_idx: { type: 'number', description: 'Position within the node. Appends if omitted.' },
|
|
589
|
+
bypassValidation: { type: 'boolean', description: 'Skip the syntax pre-check.' },
|
|
590
|
+
},
|
|
591
|
+
required: ['nodeId', 'name', 'language', 'content'],
|
|
592
|
+
additionalProperties: false,
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: 'byan_workflow_script_update',
|
|
597
|
+
description:
|
|
598
|
+
'Partial update of an existing script. Pass expected_version to enforce optimistic locking (409 VERSION_CONFLICT if stale). Any of name/language/content/execution_mode/order_idx can be patched.',
|
|
599
|
+
inputSchema: {
|
|
600
|
+
type: 'object',
|
|
601
|
+
properties: {
|
|
602
|
+
id: { type: 'string' },
|
|
603
|
+
expected_version: { type: 'number', description: 'Current version the caller saw.' },
|
|
604
|
+
name: { type: 'string' },
|
|
605
|
+
language: {
|
|
606
|
+
type: 'string',
|
|
607
|
+
enum: ['bash', 'python', 'javascript', 'typescript'],
|
|
608
|
+
},
|
|
609
|
+
content: { type: 'string' },
|
|
610
|
+
execution_mode: { type: 'string', enum: ['context', 'local'] },
|
|
611
|
+
order_idx: { type: 'number' },
|
|
612
|
+
bypassValidation: { type: 'boolean' },
|
|
613
|
+
},
|
|
614
|
+
required: ['id'],
|
|
615
|
+
additionalProperties: false,
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
name: 'byan_workflow_script_delete',
|
|
620
|
+
description:
|
|
621
|
+
'Soft-delete a script (sets deleted_at). History is retained. Requires "edit" access.',
|
|
622
|
+
inputSchema: {
|
|
623
|
+
type: 'object',
|
|
624
|
+
properties: { id: { type: 'string' } },
|
|
625
|
+
required: ['id'],
|
|
626
|
+
additionalProperties: false,
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
name: 'byan_workflow_script_history',
|
|
631
|
+
description:
|
|
632
|
+
'Return the last 50 versions of a script (metadata, no content). Ordered by version DESC.',
|
|
633
|
+
inputSchema: {
|
|
634
|
+
type: 'object',
|
|
635
|
+
properties: { id: { type: 'string' } },
|
|
636
|
+
required: ['id'],
|
|
637
|
+
additionalProperties: false,
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: 'byan_workflow_script_rollback',
|
|
642
|
+
description:
|
|
643
|
+
'Rollback a script to a prior version. Writes a new version row with change_kind="rollback".',
|
|
644
|
+
inputSchema: {
|
|
645
|
+
type: 'object',
|
|
646
|
+
properties: {
|
|
647
|
+
id: { type: 'string' },
|
|
648
|
+
version: { type: 'number', description: 'Target version from history (integer >= 1).' },
|
|
649
|
+
},
|
|
650
|
+
required: ['id', 'version'],
|
|
651
|
+
additionalProperties: false,
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
name: 'byan_workflow_script_import',
|
|
656
|
+
description:
|
|
657
|
+
'Import a script from a whitelisted URL (raw.githubusercontent.com, gitlab.com, bitbucket.org, codeberg.org). HTTPS only. Language is detected from extension if not provided.',
|
|
658
|
+
inputSchema: {
|
|
659
|
+
type: 'object',
|
|
660
|
+
properties: {
|
|
661
|
+
nodeId: { type: 'string' },
|
|
662
|
+
url: { type: 'string', description: 'https:// URL on a whitelisted host.' },
|
|
663
|
+
name: { type: 'string' },
|
|
664
|
+
language: {
|
|
665
|
+
type: 'string',
|
|
666
|
+
enum: ['bash', 'python', 'javascript', 'typescript'],
|
|
667
|
+
},
|
|
668
|
+
execution_mode: { type: 'string', enum: ['context', 'local'] },
|
|
669
|
+
},
|
|
670
|
+
required: ['nodeId', 'url'],
|
|
671
|
+
additionalProperties: false,
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
name: 'byan_workflow_script_validate',
|
|
676
|
+
description:
|
|
677
|
+
'Run a dry syntax check on arbitrary content without persisting anything. Returns { ok, validator, exit_code?, error? }.',
|
|
678
|
+
inputSchema: {
|
|
679
|
+
type: 'object',
|
|
680
|
+
properties: {
|
|
681
|
+
language: {
|
|
682
|
+
type: 'string',
|
|
683
|
+
enum: ['bash', 'python', 'javascript', 'typescript'],
|
|
684
|
+
},
|
|
685
|
+
content: { type: 'string' },
|
|
686
|
+
},
|
|
687
|
+
required: ['language', 'content'],
|
|
688
|
+
additionalProperties: false,
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
];
|
|
692
|
+
|
|
693
|
+
const server = new Server(
|
|
694
|
+
{ name: 'byan-mcp', version: '0.1.0' },
|
|
695
|
+
{ capabilities: { tools: {} } }
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
699
|
+
|
|
700
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
701
|
+
const { name, arguments: args = {} } = request.params;
|
|
702
|
+
|
|
703
|
+
try {
|
|
704
|
+
if (name === 'byan_ping') {
|
|
705
|
+
const t0 = Date.now();
|
|
706
|
+
const body = await apiRequest('/api/health');
|
|
707
|
+
return {
|
|
708
|
+
content: [
|
|
709
|
+
{
|
|
710
|
+
type: 'text',
|
|
711
|
+
text: JSON.stringify(
|
|
712
|
+
{
|
|
713
|
+
...body,
|
|
714
|
+
latency_ms: Date.now() - t0,
|
|
715
|
+
token_configured: Boolean(BYAN_API_TOKEN),
|
|
716
|
+
api_url: BYAN_API_URL,
|
|
717
|
+
},
|
|
718
|
+
null,
|
|
719
|
+
2
|
|
720
|
+
),
|
|
721
|
+
},
|
|
722
|
+
],
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (name === 'byan_list_projects') {
|
|
727
|
+
if (!BYAN_API_TOKEN) {
|
|
728
|
+
throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
729
|
+
}
|
|
730
|
+
const body = await apiRequest('/api/projects');
|
|
731
|
+
const limit = args.limit || 50;
|
|
732
|
+
const projects = (body.data || []).slice(0, limit);
|
|
733
|
+
return {
|
|
734
|
+
content: [
|
|
735
|
+
{
|
|
736
|
+
type: 'text',
|
|
737
|
+
text: JSON.stringify(
|
|
738
|
+
{ projects, total: body.total ?? projects.length, returned: projects.length },
|
|
739
|
+
null,
|
|
740
|
+
2
|
|
741
|
+
),
|
|
742
|
+
},
|
|
743
|
+
],
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (name === 'byan_import_project') {
|
|
748
|
+
if (!BYAN_API_TOKEN) {
|
|
749
|
+
throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
750
|
+
}
|
|
751
|
+
const body = await apiRequest('/api/import/project', {
|
|
752
|
+
method: 'POST',
|
|
753
|
+
body: JSON.stringify({
|
|
754
|
+
path: args.path,
|
|
755
|
+
...(args.name ? { name: args.name } : {}),
|
|
756
|
+
...(args.type ? { type: args.type } : {}),
|
|
757
|
+
}),
|
|
758
|
+
});
|
|
759
|
+
return {
|
|
760
|
+
content: [{ type: 'text', text: JSON.stringify(body.data || body, null, 2) }],
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (name === 'byan_dispatch') {
|
|
765
|
+
const result = dispatch(args);
|
|
766
|
+
return {
|
|
767
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (name === 'byan_soul_read') {
|
|
772
|
+
const result = readSoul({ which: args.which || 'all' });
|
|
773
|
+
return {
|
|
774
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (name === 'byan_soul_memory_append') {
|
|
779
|
+
const result = appendSoulMemory({
|
|
780
|
+
entry: args.entry,
|
|
781
|
+
validated: args.validated === true,
|
|
782
|
+
});
|
|
783
|
+
return {
|
|
784
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (name === 'byan_elo_summary') {
|
|
789
|
+
const result = await eloSummary();
|
|
790
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (name === 'byan_elo_context') {
|
|
794
|
+
const result = await eloContext({ domain: args.domain });
|
|
795
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (name === 'byan_elo_record') {
|
|
799
|
+
const result = await eloRecord({
|
|
800
|
+
domain: args.domain,
|
|
801
|
+
result: args.result,
|
|
802
|
+
reason: args.reason,
|
|
803
|
+
});
|
|
804
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if (name === 'byan_fc_check') {
|
|
808
|
+
const result = await fcCheck({ text: args.text });
|
|
809
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (name === 'byan_fc_parse') {
|
|
813
|
+
const result = await fcParse({ text: args.text });
|
|
814
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (name === 'byan_copilot_sessions') {
|
|
818
|
+
const result = listSessions({
|
|
819
|
+
limit: args.limit,
|
|
820
|
+
sinceIso: args.sinceIso,
|
|
821
|
+
cwdFilter: args.cwdFilter,
|
|
822
|
+
});
|
|
823
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (name === 'byan_copilot_session_events') {
|
|
827
|
+
const result = readSessionEvents({
|
|
828
|
+
sessionId: args.sessionId,
|
|
829
|
+
types: args.types,
|
|
830
|
+
limit: args.limit,
|
|
831
|
+
});
|
|
832
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (name === 'byan_copilot_search') {
|
|
836
|
+
const result = searchSessions({
|
|
837
|
+
query: args.query,
|
|
838
|
+
types: args.types,
|
|
839
|
+
limit: args.limit,
|
|
840
|
+
});
|
|
841
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
if (name === 'byan_fd_start') {
|
|
845
|
+
const state = fdStart({ featureName: args.featureName, force: args.force });
|
|
846
|
+
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (name === 'byan_fd_status') {
|
|
850
|
+
const state = fdStatus();
|
|
851
|
+
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if (name === 'byan_fd_advance') {
|
|
855
|
+
const state = fdAdvance({ to: args.to, note: args.note });
|
|
856
|
+
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (name === 'byan_fd_update') {
|
|
860
|
+
const state = fdUpdate({ patch: args.patch });
|
|
861
|
+
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (name === 'byan_fd_abort') {
|
|
865
|
+
const state = fdAbort({ reason: args.reason });
|
|
866
|
+
return { content: [{ type: 'text', text: JSON.stringify(state, null, 2) }] };
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (name === 'byan_review_request') {
|
|
870
|
+
const r = requestReview({
|
|
871
|
+
task_id: args.task_id,
|
|
872
|
+
author: args.author,
|
|
873
|
+
artifact_paths: args.artifact_paths,
|
|
874
|
+
description: args.description,
|
|
875
|
+
});
|
|
876
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if (name === 'byan_review_verdict') {
|
|
880
|
+
const r = recordVerdict({
|
|
881
|
+
task_id: args.task_id,
|
|
882
|
+
reviewer: args.reviewer,
|
|
883
|
+
verdict: args.verdict,
|
|
884
|
+
comments: args.comments,
|
|
885
|
+
must_fix: args.must_fix,
|
|
886
|
+
});
|
|
887
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (name === 'byan_review_get') {
|
|
891
|
+
const r = getReview({ task_id: args.task_id });
|
|
892
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (name === 'byan_review_pending') {
|
|
896
|
+
const r = listPending();
|
|
897
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
if (name === 'byan_review_pick_reviewer') {
|
|
901
|
+
const r = pickReviewer({
|
|
902
|
+
author: args.author,
|
|
903
|
+
preferredDomain: args.preferredDomain,
|
|
904
|
+
});
|
|
905
|
+
return {
|
|
906
|
+
content: [{ type: 'text', text: JSON.stringify({ reviewer: r }, null, 2) }],
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (name === 'byan_kanban_create') {
|
|
911
|
+
const r = createBoard({ sessionId: args.sessionId });
|
|
912
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
913
|
+
}
|
|
914
|
+
if (name === 'byan_kanban_add') {
|
|
915
|
+
const r = addCard({ sessionId: args.sessionId, card: args.card });
|
|
916
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
917
|
+
}
|
|
918
|
+
if (name === 'byan_kanban_move') {
|
|
919
|
+
const r = moveCard({
|
|
920
|
+
sessionId: args.sessionId,
|
|
921
|
+
cardId: args.cardId,
|
|
922
|
+
toColumn: args.toColumn,
|
|
923
|
+
blocker_reason: args.blocker_reason,
|
|
924
|
+
});
|
|
925
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
926
|
+
}
|
|
927
|
+
if (name === 'byan_kanban_assign') {
|
|
928
|
+
const r = assignCard({
|
|
929
|
+
sessionId: args.sessionId,
|
|
930
|
+
cardId: args.cardId,
|
|
931
|
+
assignee: args.assignee,
|
|
932
|
+
});
|
|
933
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
934
|
+
}
|
|
935
|
+
if (name === 'byan_kanban_get') {
|
|
936
|
+
const r = getBoard({ sessionId: args.sessionId });
|
|
937
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
938
|
+
}
|
|
939
|
+
if (name === 'byan_standup_post') {
|
|
940
|
+
const r = postStandup({
|
|
941
|
+
sessionId: args.sessionId,
|
|
942
|
+
agent: args.agent,
|
|
943
|
+
did: args.did,
|
|
944
|
+
blockers: args.blockers,
|
|
945
|
+
next: args.next,
|
|
946
|
+
});
|
|
947
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
948
|
+
}
|
|
949
|
+
if (name === 'byan_standup_read') {
|
|
950
|
+
const r = readStandups({ sessionId: args.sessionId, limit: args.limit });
|
|
951
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
952
|
+
}
|
|
953
|
+
if (name === 'byan_standup_blocked') {
|
|
954
|
+
const r = detectBlockedStreaks({
|
|
955
|
+
sessionId: args.sessionId,
|
|
956
|
+
minStreak: args.minStreak,
|
|
957
|
+
});
|
|
958
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (name === 'byan_workflow_script_list') {
|
|
962
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
963
|
+
const r = await listScripts({ apiRequest, nodeId: args.nodeId });
|
|
964
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
965
|
+
}
|
|
966
|
+
if (name === 'byan_workflow_script_get') {
|
|
967
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
968
|
+
const r = await getScript({ apiRequest, id: args.id });
|
|
969
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
970
|
+
}
|
|
971
|
+
if (name === 'byan_workflow_script_create') {
|
|
972
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
973
|
+
const r = await createScript({
|
|
974
|
+
apiRequest,
|
|
975
|
+
nodeId: args.nodeId,
|
|
976
|
+
name: args.name,
|
|
977
|
+
language: args.language,
|
|
978
|
+
content: args.content,
|
|
979
|
+
execution_mode: args.execution_mode,
|
|
980
|
+
order_idx: args.order_idx,
|
|
981
|
+
bypassValidation: args.bypassValidation,
|
|
982
|
+
});
|
|
983
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
984
|
+
}
|
|
985
|
+
if (name === 'byan_workflow_script_update') {
|
|
986
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
987
|
+
const r = await updateScript({
|
|
988
|
+
apiRequest,
|
|
989
|
+
id: args.id,
|
|
990
|
+
expected_version: args.expected_version,
|
|
991
|
+
name: args.name,
|
|
992
|
+
language: args.language,
|
|
993
|
+
content: args.content,
|
|
994
|
+
execution_mode: args.execution_mode,
|
|
995
|
+
order_idx: args.order_idx,
|
|
996
|
+
bypassValidation: args.bypassValidation,
|
|
997
|
+
});
|
|
998
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
999
|
+
}
|
|
1000
|
+
if (name === 'byan_workflow_script_delete') {
|
|
1001
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
1002
|
+
const r = await deleteScript({ apiRequest, id: args.id });
|
|
1003
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
1004
|
+
}
|
|
1005
|
+
if (name === 'byan_workflow_script_history') {
|
|
1006
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
1007
|
+
const r = await getScriptHistory({ apiRequest, id: args.id });
|
|
1008
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
1009
|
+
}
|
|
1010
|
+
if (name === 'byan_workflow_script_rollback') {
|
|
1011
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
1012
|
+
const r = await rollbackScript({ apiRequest, id: args.id, version: args.version });
|
|
1013
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
1014
|
+
}
|
|
1015
|
+
if (name === 'byan_workflow_script_import') {
|
|
1016
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
1017
|
+
const r = await importScript({
|
|
1018
|
+
apiRequest,
|
|
1019
|
+
nodeId: args.nodeId,
|
|
1020
|
+
url: args.url,
|
|
1021
|
+
name: args.name,
|
|
1022
|
+
language: args.language,
|
|
1023
|
+
execution_mode: args.execution_mode,
|
|
1024
|
+
});
|
|
1025
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
1026
|
+
}
|
|
1027
|
+
if (name === 'byan_workflow_script_validate') {
|
|
1028
|
+
if (!BYAN_API_TOKEN) throw new Error('BYAN_API_TOKEN env var is required for this tool.');
|
|
1029
|
+
const r = await validateScriptSyntax({
|
|
1030
|
+
apiRequest,
|
|
1031
|
+
language: args.language,
|
|
1032
|
+
content: args.content,
|
|
1033
|
+
});
|
|
1034
|
+
return { content: [{ type: 'text', text: JSON.stringify(r, null, 2) }] };
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
1038
|
+
} catch (err) {
|
|
1039
|
+
return {
|
|
1040
|
+
isError: true,
|
|
1041
|
+
content: [{ type: 'text', text: `Error: ${err.message}` }],
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
const transport = new StdioServerTransport();
|
|
1047
|
+
await server.connect(transport);
|