@chapterai/mcp 0.1.0 → 0.1.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 +490 -391
- package/package.json +12 -11
package/dist/index.js
CHANGED
|
@@ -22352,30 +22352,30 @@ function getClient() {
|
|
|
22352
22352
|
return client;
|
|
22353
22353
|
}
|
|
22354
22354
|
var api = {
|
|
22355
|
-
|
|
22355
|
+
workspaces: {
|
|
22356
22356
|
list(input) {
|
|
22357
|
-
return getClient().
|
|
22357
|
+
return getClient().workspaces.list.query(input);
|
|
22358
22358
|
},
|
|
22359
22359
|
getById(input) {
|
|
22360
|
-
return getClient().
|
|
22360
|
+
return getClient().workspaces.getById.query(input);
|
|
22361
22361
|
},
|
|
22362
22362
|
getReadme(input) {
|
|
22363
|
-
return getClient().
|
|
22363
|
+
return getClient().workspaces.getReadme.query(input);
|
|
22364
22364
|
},
|
|
22365
22365
|
listFiles(input) {
|
|
22366
|
-
return getClient().
|
|
22366
|
+
return getClient().workspaces.listFiles.query(input);
|
|
22367
22367
|
},
|
|
22368
22368
|
listCommits(input) {
|
|
22369
|
-
return getClient().
|
|
22369
|
+
return getClient().workspaces.listCommits.query(input);
|
|
22370
22370
|
},
|
|
22371
22371
|
readFile(input) {
|
|
22372
|
-
return getClient().
|
|
22372
|
+
return getClient().workspaces.readFile.query(input);
|
|
22373
22373
|
},
|
|
22374
22374
|
listChangedFiles(input) {
|
|
22375
|
-
return getClient().
|
|
22375
|
+
return getClient().workspaces.listChangedFiles.query(input);
|
|
22376
22376
|
},
|
|
22377
22377
|
getFileDiff(input) {
|
|
22378
|
-
return getClient().
|
|
22378
|
+
return getClient().workspaces.getFileDiff.query(input);
|
|
22379
22379
|
}
|
|
22380
22380
|
},
|
|
22381
22381
|
changeRequests: {
|
|
@@ -22414,26 +22414,29 @@ var api = {
|
|
|
22414
22414
|
return getClient().search.semantic.query(input);
|
|
22415
22415
|
}
|
|
22416
22416
|
},
|
|
22417
|
-
|
|
22418
|
-
|
|
22419
|
-
return getClient().
|
|
22417
|
+
tasks: {
|
|
22418
|
+
list(input) {
|
|
22419
|
+
return getClient().tasks.list.query(input);
|
|
22420
22420
|
},
|
|
22421
|
-
|
|
22422
|
-
return getClient().
|
|
22421
|
+
getByNumber(input) {
|
|
22422
|
+
return getClient().tasks.getByNumber.query(input);
|
|
22423
22423
|
},
|
|
22424
|
-
|
|
22425
|
-
return getClient().
|
|
22424
|
+
create(input) {
|
|
22425
|
+
return getClient().tasks.create.mutate(input);
|
|
22426
22426
|
},
|
|
22427
|
-
|
|
22428
|
-
return getClient().
|
|
22427
|
+
update(input) {
|
|
22428
|
+
return getClient().tasks.update.mutate(input);
|
|
22429
|
+
}
|
|
22430
|
+
},
|
|
22431
|
+
activity: {
|
|
22432
|
+
feed(input) {
|
|
22433
|
+
return getClient().workspaces.getActivity.query(input);
|
|
22429
22434
|
},
|
|
22430
|
-
|
|
22431
|
-
return getClient().
|
|
22432
|
-
input
|
|
22433
|
-
);
|
|
22435
|
+
fileHistory(input) {
|
|
22436
|
+
return getClient().workspaces.getFileHistory.query(input);
|
|
22434
22437
|
},
|
|
22435
|
-
|
|
22436
|
-
return getClient().
|
|
22438
|
+
stats(input) {
|
|
22439
|
+
return getClient().workspaces.getWorkspaceStats.query(input);
|
|
22437
22440
|
}
|
|
22438
22441
|
},
|
|
22439
22442
|
sessions: {
|
|
@@ -22446,46 +22449,54 @@ var api = {
|
|
|
22446
22449
|
}
|
|
22447
22450
|
};
|
|
22448
22451
|
|
|
22449
|
-
// src/lib/
|
|
22452
|
+
// src/lib/workspace-context.ts
|
|
22450
22453
|
import fs2 from "fs";
|
|
22451
22454
|
import path2 from "path";
|
|
22452
|
-
var
|
|
22453
|
-
|
|
22455
|
+
var LINK_PATH = path2.join(".chapter", "workspace.json");
|
|
22456
|
+
var LEGACY_LINK_FILENAME = ".chapter.json";
|
|
22457
|
+
function readLinkFile(filePath) {
|
|
22458
|
+
try {
|
|
22459
|
+
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
22460
|
+
const data = JSON.parse(raw);
|
|
22461
|
+
const id = data.workspaceId ?? data.projectId;
|
|
22462
|
+
const name = data.workspaceName ?? data.projectName;
|
|
22463
|
+
if (!id || !name) return null;
|
|
22464
|
+
return { workspaceId: id, workspaceName: name };
|
|
22465
|
+
} catch {
|
|
22466
|
+
return null;
|
|
22467
|
+
}
|
|
22468
|
+
}
|
|
22469
|
+
function findWorkspaceLink() {
|
|
22454
22470
|
let dir = process.cwd();
|
|
22455
22471
|
while (true) {
|
|
22456
|
-
const
|
|
22457
|
-
if (fs2.existsSync(
|
|
22458
|
-
|
|
22459
|
-
|
|
22460
|
-
return JSON.parse(raw);
|
|
22461
|
-
} catch {
|
|
22462
|
-
return null;
|
|
22463
|
-
}
|
|
22464
|
-
}
|
|
22472
|
+
const newPath = path2.join(dir, LINK_PATH);
|
|
22473
|
+
if (fs2.existsSync(newPath)) return readLinkFile(newPath);
|
|
22474
|
+
const legacyPath = path2.join(dir, LEGACY_LINK_FILENAME);
|
|
22475
|
+
if (fs2.existsSync(legacyPath)) return readLinkFile(legacyPath);
|
|
22465
22476
|
const parent = path2.dirname(dir);
|
|
22466
22477
|
if (parent === dir) break;
|
|
22467
22478
|
dir = parent;
|
|
22468
22479
|
}
|
|
22469
22480
|
return null;
|
|
22470
22481
|
}
|
|
22471
|
-
async function
|
|
22472
|
-
if (
|
|
22473
|
-
if (
|
|
22474
|
-
const
|
|
22475
|
-
const match =
|
|
22476
|
-
(p) => p.name.toLowerCase() ===
|
|
22482
|
+
async function resolveWorkspaceId(workspaceId, workspaceName) {
|
|
22483
|
+
if (workspaceId) return workspaceId;
|
|
22484
|
+
if (workspaceName) {
|
|
22485
|
+
const workspaces = await api.workspaces.list();
|
|
22486
|
+
const match = workspaces.find(
|
|
22487
|
+
(p) => p.name.toLowerCase() === workspaceName.toLowerCase()
|
|
22477
22488
|
);
|
|
22478
22489
|
if (!match) {
|
|
22479
22490
|
throw new Error(
|
|
22480
|
-
`Project "${
|
|
22491
|
+
`Project "${workspaceName}" not found. Use list_workspaces to see available projects.`
|
|
22481
22492
|
);
|
|
22482
22493
|
}
|
|
22483
22494
|
return match.id;
|
|
22484
22495
|
}
|
|
22485
|
-
const link =
|
|
22486
|
-
if (link) return link.
|
|
22496
|
+
const link = findWorkspaceLink();
|
|
22497
|
+
if (link) return link.workspaceId;
|
|
22487
22498
|
throw new Error(
|
|
22488
|
-
"No project specified. Provide
|
|
22499
|
+
"No project specified. Provide workspaceId, workspaceName, or run from a directory linked to a Chapter workspace."
|
|
22489
22500
|
);
|
|
22490
22501
|
}
|
|
22491
22502
|
|
|
@@ -22515,24 +22526,24 @@ function success(text) {
|
|
|
22515
22526
|
return { content: [{ type: "text", text }] };
|
|
22516
22527
|
}
|
|
22517
22528
|
|
|
22518
|
-
// src/tools/
|
|
22519
|
-
function
|
|
22529
|
+
// src/tools/workspaces.ts
|
|
22530
|
+
function registerWorkspaceTools(server2) {
|
|
22520
22531
|
server2.tool(
|
|
22521
|
-
"
|
|
22522
|
-
"List all accessible Chapter
|
|
22532
|
+
"list_workspaces",
|
|
22533
|
+
"List all accessible Chapter workspaces",
|
|
22523
22534
|
{ orgId: external_exports.string().uuid().optional().describe("Filter by organization ID") },
|
|
22524
22535
|
async ({ orgId }) => {
|
|
22525
22536
|
try {
|
|
22526
|
-
const
|
|
22537
|
+
const workspaces = await api.workspaces.list(
|
|
22527
22538
|
orgId ? { orgId } : void 0
|
|
22528
22539
|
);
|
|
22529
|
-
const lines =
|
|
22540
|
+
const lines = workspaces.map(
|
|
22530
22541
|
(p) => `- ${p.name} (id: ${p.id}, backend: ${p.backend})${p.description ? ` \u2014 ${p.description}` : ""}`
|
|
22531
22542
|
);
|
|
22532
22543
|
return success(
|
|
22533
22544
|
lines.length > 0 ? `Found ${lines.length} project(s):
|
|
22534
22545
|
|
|
22535
|
-
${lines.join("\n")}` : "No
|
|
22546
|
+
${lines.join("\n")}` : "No workspaces found."
|
|
22536
22547
|
);
|
|
22537
22548
|
} catch (error2) {
|
|
22538
22549
|
return formatError2(error2);
|
|
@@ -22543,23 +22554,23 @@ ${lines.join("\n")}` : "No projects found."
|
|
|
22543
22554
|
"get_project",
|
|
22544
22555
|
"Get project details including README content",
|
|
22545
22556
|
{
|
|
22546
|
-
|
|
22547
|
-
|
|
22557
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22558
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)")
|
|
22548
22559
|
},
|
|
22549
|
-
async ({
|
|
22560
|
+
async ({ workspaceId, workspaceName }) => {
|
|
22550
22561
|
try {
|
|
22551
|
-
const id = await
|
|
22552
|
-
const [
|
|
22553
|
-
api.
|
|
22554
|
-
api.
|
|
22562
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22563
|
+
const [workspace, readme] = await Promise.all([
|
|
22564
|
+
api.workspaces.getById({ id }),
|
|
22565
|
+
api.workspaces.getReadme({ workspaceId: id })
|
|
22555
22566
|
]);
|
|
22556
22567
|
const parts = [
|
|
22557
|
-
`# ${
|
|
22558
|
-
|
|
22559
|
-
${
|
|
22568
|
+
`# ${workspace.name}`,
|
|
22569
|
+
workspace.description ? `
|
|
22570
|
+
${workspace.description}` : "",
|
|
22560
22571
|
`
|
|
22561
|
-
Backend: ${
|
|
22562
|
-
`Created: ${
|
|
22572
|
+
Backend: ${workspace.backend}`,
|
|
22573
|
+
`Created: ${workspace.createdAt}`,
|
|
22563
22574
|
readme.content ? `
|
|
22564
22575
|
## README
|
|
22565
22576
|
|
|
@@ -22572,34 +22583,72 @@ ${readme.content}` : ""
|
|
|
22572
22583
|
}
|
|
22573
22584
|
);
|
|
22574
22585
|
server2.tool(
|
|
22575
|
-
"
|
|
22576
|
-
"Get complete
|
|
22586
|
+
"get_workspace_overview",
|
|
22587
|
+
"Get complete workspace context in one call: README, file tree, recent commits, active tasks, and open changes. This is the best tool to start with when working on a workspace \u2014 it gives you full situational awareness.",
|
|
22577
22588
|
{
|
|
22578
|
-
|
|
22579
|
-
|
|
22589
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22590
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)")
|
|
22580
22591
|
},
|
|
22581
|
-
async ({
|
|
22592
|
+
async ({ workspaceId, workspaceName }) => {
|
|
22582
22593
|
try {
|
|
22583
|
-
const id = await
|
|
22584
|
-
const [
|
|
22585
|
-
api.
|
|
22586
|
-
api.
|
|
22587
|
-
api.
|
|
22588
|
-
api.
|
|
22594
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22595
|
+
const [workspace, readme, files, commits, openCRs, appliedCRs, activeTasks, todoTasks, recentSessions] = await Promise.all([
|
|
22596
|
+
api.workspaces.getById({ id }),
|
|
22597
|
+
api.workspaces.getReadme({ workspaceId: id }),
|
|
22598
|
+
api.workspaces.listFiles({ workspaceId: id, path: "" }),
|
|
22599
|
+
api.workspaces.listCommits({ workspaceId: id, limit: 10 }),
|
|
22589
22600
|
api.changeRequests.list({
|
|
22590
|
-
|
|
22601
|
+
workspaceId: id,
|
|
22591
22602
|
status: "open",
|
|
22592
|
-
limit:
|
|
22593
|
-
})
|
|
22603
|
+
limit: 5
|
|
22604
|
+
}),
|
|
22605
|
+
api.changeRequests.list({
|
|
22606
|
+
workspaceId: id,
|
|
22607
|
+
status: "applied",
|
|
22608
|
+
limit: 5
|
|
22609
|
+
}),
|
|
22610
|
+
api.tasks.list({ workspaceId: id, status: "in_progress" }),
|
|
22611
|
+
api.tasks.list({ workspaceId: id, status: "todo" }),
|
|
22612
|
+
api.sessions.list({ workspaceId: id, status: "completed", limit: 5 })
|
|
22594
22613
|
]);
|
|
22595
22614
|
const parts = [];
|
|
22596
|
-
parts.push(`# ${
|
|
22597
|
-
if (
|
|
22598
|
-
parts.push(`Backend: ${
|
|
22615
|
+
parts.push(`# ${workspace.name}`);
|
|
22616
|
+
if (workspace.description) parts.push(workspace.description);
|
|
22617
|
+
parts.push(`Backend: ${workspace.backend}`);
|
|
22599
22618
|
if (readme.content) {
|
|
22600
22619
|
parts.push("\n## README\n");
|
|
22601
22620
|
parts.push(readme.content);
|
|
22602
22621
|
}
|
|
22622
|
+
const allActiveTasks = [...activeTasks, ...todoTasks];
|
|
22623
|
+
if (allActiveTasks.length > 0) {
|
|
22624
|
+
parts.push("\n## Active Tasks\n");
|
|
22625
|
+
parts.push(
|
|
22626
|
+
allActiveTasks.map((t) => {
|
|
22627
|
+
const priority = t.priority !== "none" ? ` (${t.priority})` : "";
|
|
22628
|
+
const status = t.status === "in_progress" ? " [IN PROGRESS]" : "";
|
|
22629
|
+
return `- #${t.number}: ${t.title}${status}${priority}${t.description ? `
|
|
22630
|
+
${t.description.slice(0, 200)}` : ""}`;
|
|
22631
|
+
}).join("\n")
|
|
22632
|
+
);
|
|
22633
|
+
}
|
|
22634
|
+
const sessionsWithSummaries = recentSessions.filter((s) => s.summary);
|
|
22635
|
+
if (sessionsWithSummaries.length > 0) {
|
|
22636
|
+
parts.push("\n## Recent Sessions (what's been done)\n");
|
|
22637
|
+
parts.push(
|
|
22638
|
+
sessionsWithSummaries.map((s) => {
|
|
22639
|
+
try {
|
|
22640
|
+
const parsed = JSON.parse(s.summary);
|
|
22641
|
+
const lines = [`- **${s.title ?? "(untitled)"}** (${new Date(s.createdAt).toLocaleDateString()})`];
|
|
22642
|
+
lines.push(` Asked: ${parsed.whatWasAsked}`);
|
|
22643
|
+
lines.push(` Done: ${parsed.whatWasDone}`);
|
|
22644
|
+
if (parsed.whatToWatch) lines.push(` Watch: ${parsed.whatToWatch}`);
|
|
22645
|
+
return lines.join("\n");
|
|
22646
|
+
} catch {
|
|
22647
|
+
return `- ${s.title ?? "(untitled)"} (${new Date(s.createdAt).toLocaleDateString()})`;
|
|
22648
|
+
}
|
|
22649
|
+
}).join("\n")
|
|
22650
|
+
);
|
|
22651
|
+
}
|
|
22603
22652
|
parts.push("\n## File Tree (root)\n");
|
|
22604
22653
|
if (files.length > 0) {
|
|
22605
22654
|
parts.push(
|
|
@@ -22608,7 +22657,7 @@ ${readme.content}` : ""
|
|
|
22608
22657
|
} else {
|
|
22609
22658
|
parts.push("(empty)");
|
|
22610
22659
|
}
|
|
22611
|
-
parts.push("\n## Recent
|
|
22660
|
+
parts.push("\n## Recent Commits\n");
|
|
22612
22661
|
if (commits.length > 0) {
|
|
22613
22662
|
parts.push(
|
|
22614
22663
|
commits.map(
|
|
@@ -22618,15 +22667,23 @@ ${readme.content}` : ""
|
|
|
22618
22667
|
} else {
|
|
22619
22668
|
parts.push("No commits yet.");
|
|
22620
22669
|
}
|
|
22621
|
-
|
|
22622
|
-
|
|
22670
|
+
if (appliedCRs.length > 0) {
|
|
22671
|
+
parts.push("\n## Recently Shipped Changes\n");
|
|
22672
|
+
parts.push(
|
|
22673
|
+
appliedCRs.map((cr) => {
|
|
22674
|
+
const summary = cr.aiSummary ? `
|
|
22675
|
+
${cr.aiSummary}` : "";
|
|
22676
|
+
return `- #${cr.number}: ${cr.title} (${cr.filesChanged} files, +${cr.additions}/-${cr.deletions})${summary}`;
|
|
22677
|
+
}).join("\n")
|
|
22678
|
+
);
|
|
22679
|
+
}
|
|
22680
|
+
if (openCRs.length > 0) {
|
|
22681
|
+
parts.push("\n## Open Changes (pending review)\n");
|
|
22623
22682
|
parts.push(
|
|
22624
|
-
|
|
22683
|
+
openCRs.map(
|
|
22625
22684
|
(cr) => `- #${cr.number}: ${cr.title} (${cr.filesChanged} files, +${cr.additions}/-${cr.deletions})`
|
|
22626
22685
|
).join("\n")
|
|
22627
22686
|
);
|
|
22628
|
-
} else {
|
|
22629
|
-
parts.push("No open change requests.");
|
|
22630
22687
|
}
|
|
22631
22688
|
return success(parts.join("\n"));
|
|
22632
22689
|
} catch (error2) {
|
|
@@ -22640,18 +22697,18 @@ ${readme.content}` : ""
|
|
|
22640
22697
|
function registerFileTools(server2) {
|
|
22641
22698
|
server2.tool(
|
|
22642
22699
|
"list_files",
|
|
22643
|
-
"Browse files and directories at a path in a
|
|
22700
|
+
"Browse files and directories at a path in a workspace",
|
|
22644
22701
|
{
|
|
22645
|
-
|
|
22646
|
-
|
|
22702
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22703
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22647
22704
|
path: external_exports.string().default("").describe("Directory path to list (empty string for root)"),
|
|
22648
22705
|
ref: external_exports.string().optional().describe("Git ref (branch, tag, or commit SHA)")
|
|
22649
22706
|
},
|
|
22650
|
-
async ({
|
|
22707
|
+
async ({ workspaceId, workspaceName, path: path3, ref }) => {
|
|
22651
22708
|
try {
|
|
22652
|
-
const id = await
|
|
22653
|
-
const files = await api.
|
|
22654
|
-
|
|
22709
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22710
|
+
const files = await api.workspaces.listFiles({
|
|
22711
|
+
workspaceId: id,
|
|
22655
22712
|
path: path3,
|
|
22656
22713
|
ref
|
|
22657
22714
|
});
|
|
@@ -22669,18 +22726,18 @@ function registerFileTools(server2) {
|
|
|
22669
22726
|
);
|
|
22670
22727
|
server2.tool(
|
|
22671
22728
|
"read_file",
|
|
22672
|
-
"Read the content of a file in a
|
|
22729
|
+
"Read the content of a file in a workspace",
|
|
22673
22730
|
{
|
|
22674
|
-
|
|
22675
|
-
|
|
22731
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22732
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22676
22733
|
path: external_exports.string().describe("File path to read"),
|
|
22677
22734
|
ref: external_exports.string().optional().describe("Git ref (branch, tag, or commit SHA)")
|
|
22678
22735
|
},
|
|
22679
|
-
async ({
|
|
22736
|
+
async ({ workspaceId, workspaceName, path: path3, ref }) => {
|
|
22680
22737
|
try {
|
|
22681
|
-
const id = await
|
|
22682
|
-
const result = await api.
|
|
22683
|
-
|
|
22738
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22739
|
+
const result = await api.workspaces.readFile({
|
|
22740
|
+
workspaceId: id,
|
|
22684
22741
|
path: path3,
|
|
22685
22742
|
ref
|
|
22686
22743
|
});
|
|
@@ -22692,24 +22749,24 @@ function registerFileTools(server2) {
|
|
|
22692
22749
|
);
|
|
22693
22750
|
server2.tool(
|
|
22694
22751
|
"search_files",
|
|
22695
|
-
"Find files by name pattern in a
|
|
22752
|
+
"Find files by name pattern in a workspace (recursive, client-side filtering)",
|
|
22696
22753
|
{
|
|
22697
|
-
|
|
22698
|
-
|
|
22754
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22755
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22699
22756
|
pattern: external_exports.string().describe("Pattern to match against file names (case-insensitive substring match)"),
|
|
22700
22757
|
path: external_exports.string().default("").describe("Directory path to search from")
|
|
22701
22758
|
},
|
|
22702
|
-
async ({
|
|
22759
|
+
async ({ workspaceId, workspaceName, pattern, path: path3 }) => {
|
|
22703
22760
|
try {
|
|
22704
|
-
const id = await
|
|
22761
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22705
22762
|
const matches = [];
|
|
22706
22763
|
const lowerPattern = pattern.toLowerCase();
|
|
22707
22764
|
const maxResults = 50;
|
|
22708
22765
|
const maxDepth = 5;
|
|
22709
22766
|
async function searchDir(dirPath, depth) {
|
|
22710
22767
|
if (depth > maxDepth || matches.length >= maxResults) return;
|
|
22711
|
-
const files = await api.
|
|
22712
|
-
|
|
22768
|
+
const files = await api.workspaces.listFiles({
|
|
22769
|
+
workspaceId: id,
|
|
22713
22770
|
path: dirPath
|
|
22714
22771
|
});
|
|
22715
22772
|
for (const f of files) {
|
|
@@ -22741,30 +22798,30 @@ function registerFileTools(server2) {
|
|
|
22741
22798
|
function registerChangeRequestTools(server2) {
|
|
22742
22799
|
server2.tool(
|
|
22743
22800
|
"list_change_requests",
|
|
22744
|
-
"List
|
|
22801
|
+
"List changes for a workspace, optionally filtered by status",
|
|
22745
22802
|
{
|
|
22746
|
-
|
|
22747
|
-
|
|
22803
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22804
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22748
22805
|
status: external_exports.enum(["draft", "open", "applied", "dismissed"]).optional().describe("Filter by status"),
|
|
22749
|
-
limit: external_exports.number().min(1).max(100).default(20).describe("Max results to return")
|
|
22806
|
+
limit: external_exports.coerce.number().min(1).max(100).default(20).describe("Max results to return")
|
|
22750
22807
|
},
|
|
22751
|
-
async ({
|
|
22808
|
+
async ({ workspaceId, workspaceName, status, limit }) => {
|
|
22752
22809
|
try {
|
|
22753
|
-
const id = await
|
|
22810
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22754
22811
|
const crs = await api.changeRequests.list({
|
|
22755
|
-
|
|
22812
|
+
workspaceId: id,
|
|
22756
22813
|
status,
|
|
22757
22814
|
limit
|
|
22758
22815
|
});
|
|
22759
22816
|
if (crs.length === 0) {
|
|
22760
22817
|
return success(
|
|
22761
|
-
status ? `No ${status}
|
|
22818
|
+
status ? `No ${status} changes found.` : "No changes found."
|
|
22762
22819
|
);
|
|
22763
22820
|
}
|
|
22764
22821
|
const lines = crs.map(
|
|
22765
22822
|
(cr) => `- #${cr.number}: ${cr.title} [${cr.status}] (${cr.filesChanged} files, +${cr.additions}/-${cr.deletions})${cr.author ? ` by ${cr.author.name}` : ""}`
|
|
22766
22823
|
);
|
|
22767
|
-
return success(`Found ${crs.length} change
|
|
22824
|
+
return success(`Found ${crs.length} change(s):
|
|
22768
22825
|
|
|
22769
22826
|
${lines.join("\n")}`);
|
|
22770
22827
|
} catch (error2) {
|
|
@@ -22774,21 +22831,21 @@ ${lines.join("\n")}`);
|
|
|
22774
22831
|
);
|
|
22775
22832
|
server2.tool(
|
|
22776
22833
|
"get_change_request",
|
|
22777
|
-
"Get details of a specific change
|
|
22834
|
+
"Get details of a specific change including changed files and AI summary",
|
|
22778
22835
|
{
|
|
22779
|
-
|
|
22780
|
-
|
|
22781
|
-
number: external_exports.number().describe("Change
|
|
22836
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22837
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22838
|
+
number: external_exports.coerce.number().describe("Change number")
|
|
22782
22839
|
},
|
|
22783
|
-
async ({
|
|
22840
|
+
async ({ workspaceId, workspaceName, number: number3 }) => {
|
|
22784
22841
|
try {
|
|
22785
|
-
const id = await
|
|
22842
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22786
22843
|
const cr = await api.changeRequests.getByNumber({
|
|
22787
|
-
|
|
22844
|
+
workspaceId: id,
|
|
22788
22845
|
number: number3
|
|
22789
22846
|
});
|
|
22790
22847
|
const changedFiles = await api.changeRequests.listChangedFiles({
|
|
22791
|
-
|
|
22848
|
+
workspaceId: id,
|
|
22792
22849
|
changeRequestId: cr.id
|
|
22793
22850
|
});
|
|
22794
22851
|
const parts = [
|
|
@@ -22823,15 +22880,15 @@ ${cr.aiSummary}`);
|
|
|
22823
22880
|
);
|
|
22824
22881
|
server2.tool(
|
|
22825
22882
|
"list_branches",
|
|
22826
|
-
"List branches available for creating
|
|
22883
|
+
"List branches available for creating changes. Shows branches ahead of main with linked session info.",
|
|
22827
22884
|
{
|
|
22828
|
-
|
|
22829
|
-
|
|
22885
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22886
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)")
|
|
22830
22887
|
},
|
|
22831
|
-
async ({
|
|
22888
|
+
async ({ workspaceId, workspaceName }) => {
|
|
22832
22889
|
try {
|
|
22833
|
-
const id = await
|
|
22834
|
-
const branches = await api.changeRequests.listBranches({
|
|
22890
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22891
|
+
const branches = await api.changeRequests.listBranches({ workspaceId: id });
|
|
22835
22892
|
if (branches.length === 0) {
|
|
22836
22893
|
return success("No draft branches found. Start a coding session to create one.");
|
|
22837
22894
|
}
|
|
@@ -22849,25 +22906,25 @@ ${lines.join("\n")}`);
|
|
|
22849
22906
|
);
|
|
22850
22907
|
server2.tool(
|
|
22851
22908
|
"create_change_request",
|
|
22852
|
-
"Create a new change
|
|
22909
|
+
"Create a new change from a source branch",
|
|
22853
22910
|
{
|
|
22854
|
-
|
|
22855
|
-
|
|
22856
|
-
title: external_exports.string().min(1).max(500).describe("Title for the change
|
|
22911
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22912
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22913
|
+
title: external_exports.string().min(1).max(500).describe("Title for the change"),
|
|
22857
22914
|
description: external_exports.string().max(5e3).optional().describe("Description of the changes"),
|
|
22858
22915
|
sourceBranch: external_exports.string().min(1).describe("Source branch name \u2014 all commits ahead of main form the CR")
|
|
22859
22916
|
},
|
|
22860
|
-
async ({
|
|
22917
|
+
async ({ workspaceId, workspaceName, title, description, sourceBranch }) => {
|
|
22861
22918
|
try {
|
|
22862
|
-
const id = await
|
|
22919
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22863
22920
|
const cr = await api.changeRequests.create({
|
|
22864
|
-
|
|
22921
|
+
workspaceId: id,
|
|
22865
22922
|
title,
|
|
22866
22923
|
description,
|
|
22867
22924
|
sourceBranch
|
|
22868
22925
|
});
|
|
22869
22926
|
return success(
|
|
22870
|
-
`Created change
|
|
22927
|
+
`Created change #${cr.number}: "${cr.title}" (id: ${cr.id})`
|
|
22871
22928
|
);
|
|
22872
22929
|
} catch (error2) {
|
|
22873
22930
|
return formatError2(error2);
|
|
@@ -22876,24 +22933,24 @@ ${lines.join("\n")}`);
|
|
|
22876
22933
|
);
|
|
22877
22934
|
server2.tool(
|
|
22878
22935
|
"apply_change_request",
|
|
22879
|
-
"Apply (merge) a change
|
|
22936
|
+
"Apply (merge) a change",
|
|
22880
22937
|
{
|
|
22881
|
-
|
|
22882
|
-
|
|
22883
|
-
number: external_exports.number().describe("Change
|
|
22938
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22939
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22940
|
+
number: external_exports.coerce.number().describe("Change number")
|
|
22884
22941
|
},
|
|
22885
|
-
async ({
|
|
22942
|
+
async ({ workspaceId, workspaceName, number: number3 }) => {
|
|
22886
22943
|
try {
|
|
22887
|
-
const id = await
|
|
22944
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22888
22945
|
const cr = await api.changeRequests.getByNumber({
|
|
22889
|
-
|
|
22946
|
+
workspaceId: id,
|
|
22890
22947
|
number: number3
|
|
22891
22948
|
});
|
|
22892
22949
|
await api.changeRequests.applyChanges({
|
|
22893
|
-
|
|
22950
|
+
workspaceId: id,
|
|
22894
22951
|
changeRequestId: cr.id
|
|
22895
22952
|
});
|
|
22896
|
-
return success(`Change
|
|
22953
|
+
return success(`Change #${number3} has been applied.`);
|
|
22897
22954
|
} catch (error2) {
|
|
22898
22955
|
return formatError2(error2);
|
|
22899
22956
|
}
|
|
@@ -22901,24 +22958,24 @@ ${lines.join("\n")}`);
|
|
|
22901
22958
|
);
|
|
22902
22959
|
server2.tool(
|
|
22903
22960
|
"dismiss_change_request",
|
|
22904
|
-
"Dismiss (close without applying) a change
|
|
22961
|
+
"Dismiss (close without applying) a change",
|
|
22905
22962
|
{
|
|
22906
|
-
|
|
22907
|
-
|
|
22908
|
-
number: external_exports.number().describe("Change
|
|
22963
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
22964
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22965
|
+
number: external_exports.coerce.number().describe("Change number")
|
|
22909
22966
|
},
|
|
22910
|
-
async ({
|
|
22967
|
+
async ({ workspaceId, workspaceName, number: number3 }) => {
|
|
22911
22968
|
try {
|
|
22912
|
-
const id = await
|
|
22969
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
22913
22970
|
const cr = await api.changeRequests.getByNumber({
|
|
22914
|
-
|
|
22971
|
+
workspaceId: id,
|
|
22915
22972
|
number: number3
|
|
22916
22973
|
});
|
|
22917
22974
|
await api.changeRequests.dismiss({
|
|
22918
|
-
|
|
22975
|
+
workspaceId: id,
|
|
22919
22976
|
changeRequestId: cr.id
|
|
22920
22977
|
});
|
|
22921
|
-
return success(`Change
|
|
22978
|
+
return success(`Change #${number3} has been dismissed.`);
|
|
22922
22979
|
} catch (error2) {
|
|
22923
22980
|
return formatError2(error2);
|
|
22924
22981
|
}
|
|
@@ -22926,12 +22983,12 @@ ${lines.join("\n")}`);
|
|
|
22926
22983
|
);
|
|
22927
22984
|
server2.tool(
|
|
22928
22985
|
"add_comment",
|
|
22929
|
-
"Add a comment to a change
|
|
22986
|
+
"Add a comment to a change. Can be a general comment or an inline code comment (provide path, line, and side for inline).",
|
|
22930
22987
|
{
|
|
22931
|
-
changeRequestId: external_exports.string().uuid().describe("Change
|
|
22988
|
+
changeRequestId: external_exports.string().uuid().describe("Change ID"),
|
|
22932
22989
|
body: external_exports.string().min(1).max(1e4).describe("Comment text"),
|
|
22933
22990
|
path: external_exports.string().optional().describe("File path (for inline code comments)"),
|
|
22934
|
-
line: external_exports.number().int().positive().optional().describe("Line number (for inline code comments)"),
|
|
22991
|
+
line: external_exports.coerce.number().int().positive().optional().describe("Line number (for inline code comments)"),
|
|
22935
22992
|
side: external_exports.enum(["LEFT", "RIGHT"]).optional().describe("Diff side (for inline code comments)")
|
|
22936
22993
|
},
|
|
22937
22994
|
async ({ changeRequestId, body, path: path3, line, side }) => {
|
|
@@ -22965,18 +23022,18 @@ ${h.lines.join("\n")}`
|
|
|
22965
23022
|
function registerCommitTools(server2) {
|
|
22966
23023
|
server2.tool(
|
|
22967
23024
|
"list_commits",
|
|
22968
|
-
"List recent commit history for a
|
|
23025
|
+
"List recent commit history for a workspace",
|
|
22969
23026
|
{
|
|
22970
|
-
|
|
22971
|
-
|
|
23027
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23028
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
22972
23029
|
ref: external_exports.string().optional().describe("Git ref (branch, tag, or commit SHA)"),
|
|
22973
|
-
limit: external_exports.number().min(1).max(200).default(20).describe("Max commits to return")
|
|
23030
|
+
limit: external_exports.coerce.number().min(1).max(200).default(20).describe("Max commits to return")
|
|
22974
23031
|
},
|
|
22975
|
-
async ({
|
|
23032
|
+
async ({ workspaceId, workspaceName, ref, limit }) => {
|
|
22976
23033
|
try {
|
|
22977
|
-
const id = await
|
|
22978
|
-
const commits = await api.
|
|
22979
|
-
|
|
23034
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23035
|
+
const commits = await api.workspaces.listCommits({
|
|
23036
|
+
workspaceId: id,
|
|
22980
23037
|
ref,
|
|
22981
23038
|
limit
|
|
22982
23039
|
});
|
|
@@ -22996,29 +23053,29 @@ ${lines.join("\n")}`);
|
|
|
22996
23053
|
);
|
|
22997
23054
|
server2.tool(
|
|
22998
23055
|
"get_diff",
|
|
22999
|
-
"Get the diff for a change
|
|
23056
|
+
"Get the diff for a change or a specific commit. Provide either changeRequestNumber or commitOid.",
|
|
23000
23057
|
{
|
|
23001
|
-
|
|
23002
|
-
|
|
23003
|
-
changeRequestNumber: external_exports.number().optional().describe("Change
|
|
23058
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23059
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23060
|
+
changeRequestNumber: external_exports.coerce.number().optional().describe("Change number (to get the full diff)"),
|
|
23004
23061
|
commitOid: external_exports.string().optional().describe("Commit OID (to get a single commit diff)")
|
|
23005
23062
|
},
|
|
23006
|
-
async ({
|
|
23063
|
+
async ({ workspaceId, workspaceName, changeRequestNumber, commitOid }) => {
|
|
23007
23064
|
try {
|
|
23008
23065
|
if (!changeRequestNumber && !commitOid) {
|
|
23009
23066
|
return formatError2(
|
|
23010
23067
|
new Error("Provide either changeRequestNumber or commitOid.")
|
|
23011
23068
|
);
|
|
23012
23069
|
}
|
|
23013
|
-
const id = await
|
|
23070
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23014
23071
|
const maxFiles = 10;
|
|
23015
23072
|
if (changeRequestNumber) {
|
|
23016
23073
|
const cr = await api.changeRequests.getByNumber({
|
|
23017
|
-
|
|
23074
|
+
workspaceId: id,
|
|
23018
23075
|
number: changeRequestNumber
|
|
23019
23076
|
});
|
|
23020
23077
|
const changedFiles2 = await api.changeRequests.listChangedFiles({
|
|
23021
|
-
|
|
23078
|
+
workspaceId: id,
|
|
23022
23079
|
changeRequestId: cr.id
|
|
23023
23080
|
});
|
|
23024
23081
|
const filesToShow2 = changedFiles2.slice(0, maxFiles);
|
|
@@ -23029,7 +23086,7 @@ ${lines.join("\n")}`);
|
|
|
23029
23086
|
];
|
|
23030
23087
|
for (const file of filesToShow2) {
|
|
23031
23088
|
const diff = await api.changeRequests.getFileDiff({
|
|
23032
|
-
|
|
23089
|
+
workspaceId: id,
|
|
23033
23090
|
changeRequestId: cr.id,
|
|
23034
23091
|
filePath: file.path
|
|
23035
23092
|
});
|
|
@@ -23045,8 +23102,8 @@ ${lines.join("\n")}`);
|
|
|
23045
23102
|
}
|
|
23046
23103
|
return success(parts2.join("\n"));
|
|
23047
23104
|
}
|
|
23048
|
-
const changedFiles = await api.
|
|
23049
|
-
|
|
23105
|
+
const changedFiles = await api.workspaces.listChangedFiles({
|
|
23106
|
+
workspaceId: id,
|
|
23050
23107
|
commitOid
|
|
23051
23108
|
});
|
|
23052
23109
|
const filesToShow = changedFiles.slice(0, maxFiles);
|
|
@@ -23056,8 +23113,8 @@ ${lines.join("\n")}`);
|
|
|
23056
23113
|
`
|
|
23057
23114
|
];
|
|
23058
23115
|
for (const file of filesToShow) {
|
|
23059
|
-
const diff = await api.
|
|
23060
|
-
|
|
23116
|
+
const diff = await api.workspaces.getFileDiff({
|
|
23117
|
+
workspaceId: id,
|
|
23061
23118
|
commitOid,
|
|
23062
23119
|
filePath: file.path
|
|
23063
23120
|
});
|
|
@@ -23083,24 +23140,34 @@ ${lines.join("\n")}`);
|
|
|
23083
23140
|
function registerSessionTools(server2) {
|
|
23084
23141
|
server2.tool(
|
|
23085
23142
|
"list_sessions",
|
|
23086
|
-
"List AI coding sessions
|
|
23143
|
+
"List AI coding sessions in a workspace with summaries of what was done. Use this to understand previous work before starting a new session.",
|
|
23087
23144
|
{
|
|
23088
|
-
|
|
23089
|
-
|
|
23145
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23146
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23090
23147
|
status: external_exports.enum(["active", "completed", "archived"]).optional().describe("Filter by status"),
|
|
23091
|
-
limit: external_exports.number().min(1).max(100).default(20).describe("Max results to return")
|
|
23148
|
+
limit: external_exports.coerce.number().min(1).max(100).default(20).describe("Max results to return")
|
|
23092
23149
|
},
|
|
23093
|
-
async ({
|
|
23150
|
+
async ({ workspaceId, workspaceName, status, limit }) => {
|
|
23094
23151
|
try {
|
|
23095
|
-
const id = await
|
|
23152
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23096
23153
|
const sessions = await api.sessions.list({
|
|
23097
|
-
|
|
23154
|
+
workspaceId: id,
|
|
23098
23155
|
status,
|
|
23099
23156
|
limit
|
|
23100
23157
|
});
|
|
23101
|
-
const lines = sessions.map(
|
|
23102
|
-
|
|
23103
|
-
|
|
23158
|
+
const lines = sessions.map((s) => {
|
|
23159
|
+
const parts = [
|
|
23160
|
+
`- ${s.title ?? "(untitled)"} (id: ${s.id}, by ${s.userName ?? "unknown"}, ${s.messageCount} messages, ${new Date(s.createdAt).toLocaleDateString()})`
|
|
23161
|
+
];
|
|
23162
|
+
if (s.summary) {
|
|
23163
|
+
try {
|
|
23164
|
+
const parsed = JSON.parse(s.summary);
|
|
23165
|
+
parts.push(` \u2192 ${parsed.whatWasDone}`);
|
|
23166
|
+
} catch {
|
|
23167
|
+
}
|
|
23168
|
+
}
|
|
23169
|
+
return parts.join("\n");
|
|
23170
|
+
});
|
|
23104
23171
|
return success(
|
|
23105
23172
|
lines.length > 0 ? `Found ${lines.length} session(s):
|
|
23106
23173
|
|
|
@@ -23115,25 +23182,41 @@ ${lines.join("\n")}` : "No sessions found."
|
|
|
23115
23182
|
"get_session",
|
|
23116
23183
|
"Get a session with its full chat history",
|
|
23117
23184
|
{
|
|
23118
|
-
|
|
23119
|
-
|
|
23185
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23186
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23120
23187
|
sessionId: external_exports.string().uuid().describe("Session ID")
|
|
23121
23188
|
},
|
|
23122
|
-
async ({
|
|
23189
|
+
async ({ workspaceId, workspaceName, sessionId }) => {
|
|
23123
23190
|
try {
|
|
23124
|
-
const id = await
|
|
23191
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23125
23192
|
const session = await api.sessions.getById({
|
|
23126
|
-
|
|
23193
|
+
workspaceId: id,
|
|
23127
23194
|
sessionId
|
|
23128
23195
|
});
|
|
23129
23196
|
const parts = [];
|
|
23130
23197
|
parts.push(`# ${session.title ?? "(untitled)"}`);
|
|
23131
|
-
if (session.
|
|
23198
|
+
if (session.client) parts.push(`Client: ${session.client}`);
|
|
23132
23199
|
parts.push(`Status: ${session.status}`);
|
|
23133
23200
|
if (session.branch) parts.push(`Branch: ${session.branch}`);
|
|
23134
23201
|
if (session.changeRequestNumber != null)
|
|
23135
|
-
parts.push(`Change
|
|
23202
|
+
parts.push(`Change: #${session.changeRequestNumber}`);
|
|
23203
|
+
if (session.task)
|
|
23204
|
+
parts.push(`Task: #${session.task.number} ${session.task.title} [${session.task.status}]`);
|
|
23136
23205
|
parts.push(`Created: ${session.createdAt}`);
|
|
23206
|
+
if (session.summary) {
|
|
23207
|
+
try {
|
|
23208
|
+
const s = JSON.parse(session.summary);
|
|
23209
|
+
parts.push("\n## Summary\n");
|
|
23210
|
+
parts.push(`**Asked:** ${s.whatWasAsked}`);
|
|
23211
|
+
parts.push(`**Done:** ${s.whatWasDone}`);
|
|
23212
|
+
if (s.whatToTest.length > 0) {
|
|
23213
|
+
parts.push("**To verify:**");
|
|
23214
|
+
s.whatToTest.forEach((item) => parts.push(`- ${item}`));
|
|
23215
|
+
}
|
|
23216
|
+
if (s.whatToWatch) parts.push(`**Watch out:** ${s.whatToWatch}`);
|
|
23217
|
+
} catch {
|
|
23218
|
+
}
|
|
23219
|
+
}
|
|
23137
23220
|
parts.push(`
|
|
23138
23221
|
## Conversation (${session.messages.length} messages)
|
|
23139
23222
|
`);
|
|
@@ -23157,23 +23240,23 @@ ${lines.join("\n")}` : "No sessions found."
|
|
|
23157
23240
|
function registerSearchTools(server2) {
|
|
23158
23241
|
server2.tool(
|
|
23159
23242
|
"search_project",
|
|
23160
|
-
|
|
23243
|
+
`Search the workspace's session and change history using natural language. This is the PRIMARY way to answer questions about why something was done, when a feature was added or removed, or what happened in past work. Always try this BEFORE falling back to git log or file diffs. Examples: "why did we remove the code tab?", "when did we add the serif font?", "who fixed the auth bug?"`,
|
|
23161
23244
|
{
|
|
23162
|
-
|
|
23163
|
-
"Project ID (auto-resolved from
|
|
23245
|
+
workspaceId: external_exports.string().uuid().optional().describe(
|
|
23246
|
+
"Project ID (auto-resolved from workspace link if omitted)"
|
|
23164
23247
|
),
|
|
23165
|
-
|
|
23248
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23166
23249
|
query: external_exports.string().min(1).describe("Natural language search query"),
|
|
23167
23250
|
entityTypes: external_exports.array(external_exports.enum(["session", "change_request"])).optional().describe(
|
|
23168
|
-
"Filter by entity type. Omit to search both sessions and
|
|
23251
|
+
"Filter by entity type. Omit to search both sessions and changes."
|
|
23169
23252
|
),
|
|
23170
23253
|
limit: external_exports.number().min(1).max(50).default(10).describe("Max results to return")
|
|
23171
23254
|
},
|
|
23172
|
-
async ({
|
|
23255
|
+
async ({ workspaceId, workspaceName, query, entityTypes, limit }) => {
|
|
23173
23256
|
try {
|
|
23174
|
-
const id = await
|
|
23257
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23175
23258
|
const results = await api.search.semantic({
|
|
23176
|
-
|
|
23259
|
+
workspaceId: id,
|
|
23177
23260
|
query,
|
|
23178
23261
|
entityTypes,
|
|
23179
23262
|
limit
|
|
@@ -23184,7 +23267,7 @@ function registerSearchTools(server2) {
|
|
|
23184
23267
|
);
|
|
23185
23268
|
}
|
|
23186
23269
|
const lines = results.map((r, i) => {
|
|
23187
|
-
const type = r.entityType === "session" ? "Session" : "Change
|
|
23270
|
+
const type = r.entityType === "session" ? "Session" : "Change";
|
|
23188
23271
|
return `${i + 1}. [${type}] ${r.snippet} (id: ${r.entityId}, relevance: ${r.similarity.toFixed(2)})`;
|
|
23189
23272
|
});
|
|
23190
23273
|
return success(
|
|
@@ -23199,243 +23282,258 @@ ${lines.join("\n")}`
|
|
|
23199
23282
|
);
|
|
23200
23283
|
}
|
|
23201
23284
|
|
|
23202
|
-
// src/tools/
|
|
23203
|
-
|
|
23285
|
+
// src/tools/tasks.ts
|
|
23286
|
+
var STATUS_LABELS = {
|
|
23287
|
+
backlog: "Backlog",
|
|
23288
|
+
todo: "To Do",
|
|
23289
|
+
in_progress: "In Progress",
|
|
23290
|
+
done: "Done"
|
|
23291
|
+
};
|
|
23292
|
+
var PRIORITY_LABELS = {
|
|
23293
|
+
none: "None",
|
|
23294
|
+
urgent: "Urgent",
|
|
23295
|
+
high: "High",
|
|
23296
|
+
medium: "Medium",
|
|
23297
|
+
low: "Low"
|
|
23298
|
+
};
|
|
23299
|
+
function registerTaskTools(server2) {
|
|
23204
23300
|
server2.tool(
|
|
23205
|
-
"
|
|
23206
|
-
|
|
23301
|
+
"list_tasks",
|
|
23302
|
+
'List tasks in the workspace backlog. Use this at the START of your work to see what needs to be done. If you are working on a specific task, update its status to "in_progress" using update_task before you begin.',
|
|
23207
23303
|
{
|
|
23208
|
-
|
|
23209
|
-
|
|
23304
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23305
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23306
|
+
status: external_exports.enum(["backlog", "todo", "in_progress", "done"]).optional().describe("Filter by status"),
|
|
23307
|
+
priority: external_exports.enum(["none", "urgent", "high", "medium", "low"]).optional().describe("Filter by priority")
|
|
23210
23308
|
},
|
|
23211
|
-
async ({
|
|
23309
|
+
async ({ workspaceId, workspaceName, status, priority }) => {
|
|
23212
23310
|
try {
|
|
23213
|
-
const id = await
|
|
23214
|
-
const
|
|
23215
|
-
|
|
23311
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23312
|
+
const tasks = await api.tasks.list({ workspaceId: id, status, priority });
|
|
23313
|
+
if (tasks.length === 0) {
|
|
23314
|
+
return success("No tasks found.");
|
|
23315
|
+
}
|
|
23316
|
+
const lines = tasks.map((t) => {
|
|
23317
|
+
const parts = [`- #${t.number}: ${t.title}`];
|
|
23318
|
+
parts.push(`[${STATUS_LABELS[t.status] ?? t.status}]`);
|
|
23319
|
+
if (t.priority !== "none") parts.push(`(${PRIORITY_LABELS[t.priority] ?? t.priority})`);
|
|
23320
|
+
if (t.assignee) parts.push(`assigned to ${t.assignee.name}`);
|
|
23321
|
+
if (t.sessionCount > 0) parts.push(`(${t.sessionCount} session${t.sessionCount > 1 ? "s" : ""})`);
|
|
23322
|
+
return parts.join(" ");
|
|
23216
23323
|
});
|
|
23217
|
-
|
|
23218
|
-
|
|
23219
|
-
|
|
23220
|
-
);
|
|
23221
|
-
}
|
|
23222
|
-
const lines = ["# Project Code Structure\n"];
|
|
23223
|
-
for (const bucket of buckets) {
|
|
23224
|
-
const lang = bucket.primaryLanguage ?? "mixed";
|
|
23225
|
-
lines.push(
|
|
23226
|
-
`## ${bucket.path}/ (${bucket.fileCount} files \xB7 ${lang} \xB7 ${bucket.exportCount} exports)`
|
|
23227
|
-
);
|
|
23228
|
-
if (bucket.subdirectories.length > 0) {
|
|
23229
|
-
const subdirs = bucket.subdirectories.map((s) => `${s.name}/ (${s.fileCount})`).join(" ");
|
|
23230
|
-
lines.push(` ${subdirs}`);
|
|
23231
|
-
}
|
|
23232
|
-
lines.push("");
|
|
23233
|
-
}
|
|
23234
|
-
const totalFiles = buckets.reduce((n, b) => n + b.fileCount, 0);
|
|
23235
|
-
const totalSymbols = buckets.reduce((n, b) => n + b.symbolCount, 0);
|
|
23236
|
-
lines.push(
|
|
23237
|
-
`---
|
|
23238
|
-
Total: ${totalFiles} files, ${totalSymbols} symbols across ${buckets.length} directories`
|
|
23239
|
-
);
|
|
23240
|
-
return success(lines.join("\n"));
|
|
23324
|
+
return success(`Found ${tasks.length} task(s):
|
|
23325
|
+
|
|
23326
|
+
${lines.join("\n")}`);
|
|
23241
23327
|
} catch (error2) {
|
|
23242
23328
|
return formatError2(error2);
|
|
23243
23329
|
}
|
|
23244
23330
|
}
|
|
23245
23331
|
);
|
|
23246
23332
|
server2.tool(
|
|
23247
|
-
"
|
|
23248
|
-
"Get
|
|
23333
|
+
"get_task",
|
|
23334
|
+
"Get full details of a task including its description, linked sessions, and history. Use this to understand requirements before starting work on a task.",
|
|
23249
23335
|
{
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
23336
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23337
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23338
|
+
number: external_exports.coerce.number().describe("Task number (e.g. 1, 2, 3)")
|
|
23253
23339
|
},
|
|
23254
|
-
async ({
|
|
23340
|
+
async ({ workspaceId, workspaceName, number: number3 }) => {
|
|
23255
23341
|
try {
|
|
23256
|
-
const id = await
|
|
23257
|
-
const
|
|
23258
|
-
|
|
23259
|
-
|
|
23260
|
-
});
|
|
23261
|
-
|
|
23262
|
-
|
|
23263
|
-
|
|
23264
|
-
|
|
23265
|
-
|
|
23266
|
-
|
|
23267
|
-
|
|
23268
|
-
|
|
23269
|
-
|
|
23270
|
-
|
|
23271
|
-
|
|
23272
|
-
|
|
23342
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23343
|
+
const task = await api.tasks.getByNumber({ workspaceId: id, number: number3 });
|
|
23344
|
+
const parts = [];
|
|
23345
|
+
parts.push(`# Task #${task.number}: ${task.title}`);
|
|
23346
|
+
parts.push(`Status: ${STATUS_LABELS[task.status] ?? task.status}`);
|
|
23347
|
+
parts.push(`Priority: ${PRIORITY_LABELS[task.priority] ?? task.priority}`);
|
|
23348
|
+
if (task.assignee) parts.push(`Assigned to: ${task.assignee.name}`);
|
|
23349
|
+
if (task.description) parts.push(`
|
|
23350
|
+
## Description
|
|
23351
|
+
|
|
23352
|
+
${task.description}`);
|
|
23353
|
+
if (task.sessions.length > 0) {
|
|
23354
|
+
parts.push(`
|
|
23355
|
+
## Linked Sessions (${task.sessions.length})
|
|
23356
|
+
`);
|
|
23357
|
+
for (const s of task.sessions) {
|
|
23358
|
+
const crInfo = s.changeRequestNumber != null ? ` (CR #${s.changeRequestNumber})` : "";
|
|
23359
|
+
parts.push(`- ${s.title ?? "(untitled)"} \u2014 ${s.status}${crInfo}`);
|
|
23360
|
+
if (s.summary) {
|
|
23361
|
+
try {
|
|
23362
|
+
const parsed = JSON.parse(s.summary);
|
|
23363
|
+
parts.push(` Done: ${parsed.whatWasDone}`);
|
|
23364
|
+
if (parsed.whatToWatch) parts.push(` Watch: ${parsed.whatToWatch}`);
|
|
23365
|
+
} catch {
|
|
23366
|
+
}
|
|
23367
|
+
}
|
|
23368
|
+
}
|
|
23273
23369
|
}
|
|
23274
|
-
return success(
|
|
23370
|
+
return success(parts.join("\n"));
|
|
23275
23371
|
} catch (error2) {
|
|
23276
23372
|
return formatError2(error2);
|
|
23277
23373
|
}
|
|
23278
23374
|
}
|
|
23279
23375
|
);
|
|
23280
23376
|
server2.tool(
|
|
23281
|
-
"
|
|
23282
|
-
"
|
|
23377
|
+
"create_task",
|
|
23378
|
+
"Create a new task in the workspace backlog. Use this to add work items that need to be built. If you discover bugs or follow-up work while coding, create tasks for them rather than leaving TODOs in code.",
|
|
23283
23379
|
{
|
|
23284
|
-
|
|
23285
|
-
|
|
23286
|
-
|
|
23380
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23381
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23382
|
+
title: external_exports.string().min(1).max(500).describe("Task title \u2014 a plain-language description of what to build"),
|
|
23383
|
+
description: external_exports.string().max(5e3).optional().describe("Optional longer description with details or acceptance criteria"),
|
|
23384
|
+
status: external_exports.enum(["backlog", "todo", "in_progress", "done"]).optional().describe("Initial status (defaults to backlog)"),
|
|
23385
|
+
priority: external_exports.enum(["none", "urgent", "high", "medium", "low"]).optional().describe("Priority level")
|
|
23287
23386
|
},
|
|
23288
|
-
async ({
|
|
23387
|
+
async ({ workspaceId, workspaceName, title, description, status, priority }) => {
|
|
23289
23388
|
try {
|
|
23290
|
-
const id = await
|
|
23291
|
-
const
|
|
23292
|
-
|
|
23293
|
-
|
|
23389
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23390
|
+
const task = await api.tasks.create({
|
|
23391
|
+
workspaceId: id,
|
|
23392
|
+
title,
|
|
23393
|
+
description,
|
|
23394
|
+
status,
|
|
23395
|
+
priority
|
|
23294
23396
|
});
|
|
23295
|
-
|
|
23296
|
-
`
|
|
23297
|
-
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
} else {
|
|
23301
|
-
for (const d of deps.imports) {
|
|
23302
|
-
const specs = d.importSpecifiers?.join(", ") ?? "*";
|
|
23303
|
-
lines.push(`- ${d.targetFilePath} \u2192 {${specs}}`);
|
|
23304
|
-
}
|
|
23305
|
-
}
|
|
23306
|
-
lines.push("");
|
|
23307
|
-
lines.push(`## Imported By (${deps.importedBy.length})`);
|
|
23308
|
-
if (deps.importedBy.length === 0) {
|
|
23309
|
-
lines.push("No files import this file.");
|
|
23310
|
-
} else {
|
|
23311
|
-
for (const d of deps.importedBy) {
|
|
23312
|
-
const specs = d.importSpecifiers?.join(", ") ?? "*";
|
|
23313
|
-
lines.push(`- ${d.sourceFilePath} \u2192 {${specs}}`);
|
|
23314
|
-
}
|
|
23315
|
-
}
|
|
23316
|
-
return success(lines.join("\n"));
|
|
23397
|
+
return success(
|
|
23398
|
+
`Created task #${task.number}: ${task.title}
|
|
23399
|
+
Status: ${STATUS_LABELS[task.status] ?? task.status}` + (task.priority !== "none" ? `
|
|
23400
|
+
Priority: ${PRIORITY_LABELS[task.priority] ?? task.priority}` : "")
|
|
23401
|
+
);
|
|
23317
23402
|
} catch (error2) {
|
|
23318
23403
|
return formatError2(error2);
|
|
23319
23404
|
}
|
|
23320
23405
|
}
|
|
23321
23406
|
);
|
|
23322
23407
|
server2.tool(
|
|
23323
|
-
"
|
|
23324
|
-
|
|
23408
|
+
"update_task",
|
|
23409
|
+
`Update a task's status, title, description, or priority. IMPORTANT: You MUST use this tool to keep task status current as you work. Set status to "in_progress" when you start working on a task, and "done" when you finish. This is not optional \u2014 task tracking is how the team stays in sync.`,
|
|
23325
23410
|
{
|
|
23326
|
-
|
|
23327
|
-
|
|
23328
|
-
|
|
23329
|
-
|
|
23411
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23412
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23413
|
+
number: external_exports.coerce.number().describe("Task number to update"),
|
|
23414
|
+
title: external_exports.string().min(1).max(500).optional().describe("New title"),
|
|
23415
|
+
description: external_exports.string().max(5e3).nullable().optional().describe("New description (null to clear)"),
|
|
23416
|
+
status: external_exports.enum(["backlog", "todo", "in_progress", "done"]).optional().describe('New status \u2014 set to "done" when the task is complete'),
|
|
23417
|
+
priority: external_exports.enum(["none", "urgent", "high", "medium", "low"]).optional().describe("New priority")
|
|
23330
23418
|
},
|
|
23331
|
-
async ({
|
|
23419
|
+
async ({ workspaceId, workspaceName, number: number3, title, description, status, priority }) => {
|
|
23332
23420
|
try {
|
|
23333
|
-
|
|
23334
|
-
|
|
23335
|
-
|
|
23336
|
-
|
|
23337
|
-
|
|
23338
|
-
|
|
23339
|
-
|
|
23340
|
-
|
|
23341
|
-
};
|
|
23342
|
-
var renderNode = renderNode2;
|
|
23343
|
-
const id = await resolveProjectId(projectId, projectName);
|
|
23344
|
-
const tree = await api.codeIntelligence.getImpactAnalysis({
|
|
23345
|
-
projectId: id,
|
|
23346
|
-
filePath,
|
|
23347
|
-
depth
|
|
23421
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23422
|
+
const existing = await api.tasks.getByNumber({ workspaceId: id, number: number3 });
|
|
23423
|
+
const task = await api.tasks.update({
|
|
23424
|
+
taskId: existing.id,
|
|
23425
|
+
title,
|
|
23426
|
+
description,
|
|
23427
|
+
status,
|
|
23428
|
+
priority
|
|
23348
23429
|
});
|
|
23349
|
-
|
|
23350
|
-
`
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
|
|
23354
|
-
lines.push(
|
|
23355
|
-
`${tree.dependents.length} file(s) directly depend on this file:
|
|
23356
|
-
`
|
|
23357
|
-
);
|
|
23358
|
-
renderNode2(tree, 0);
|
|
23359
|
-
}
|
|
23360
|
-
return success(lines.join("\n"));
|
|
23430
|
+
return success(
|
|
23431
|
+
`Updated task #${task.number}: ${task.title}
|
|
23432
|
+
Status: ${STATUS_LABELS[task.status] ?? task.status}` + (task.priority !== "none" ? `
|
|
23433
|
+
Priority: ${PRIORITY_LABELS[task.priority] ?? task.priority}` : "")
|
|
23434
|
+
);
|
|
23361
23435
|
} catch (error2) {
|
|
23362
23436
|
return formatError2(error2);
|
|
23363
23437
|
}
|
|
23364
23438
|
}
|
|
23365
23439
|
);
|
|
23440
|
+
}
|
|
23441
|
+
|
|
23442
|
+
// src/tools/activity.ts
|
|
23443
|
+
function registerActivityTools(server2) {
|
|
23366
23444
|
server2.tool(
|
|
23367
|
-
"
|
|
23368
|
-
"
|
|
23445
|
+
"get_activity",
|
|
23446
|
+
"Get a timeline of recent activity in a workspace \u2014 sessions, changes, tasks, and commits. Use this to understand what has been happening recently.",
|
|
23369
23447
|
{
|
|
23370
|
-
|
|
23371
|
-
|
|
23372
|
-
|
|
23373
|
-
|
|
23374
|
-
"function",
|
|
23375
|
-
"class",
|
|
23376
|
-
"interface",
|
|
23377
|
-
"type",
|
|
23378
|
-
"variable",
|
|
23379
|
-
"method",
|
|
23380
|
-
"export"
|
|
23381
|
-
]).optional().describe("Filter by symbol type")
|
|
23448
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23449
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23450
|
+
limit: external_exports.coerce.number().min(1).max(100).default(20).describe("Max events to return"),
|
|
23451
|
+
since: external_exports.string().optional().describe("ISO date \u2014 only show events after this date (default: 7 days ago)")
|
|
23382
23452
|
},
|
|
23383
|
-
async ({
|
|
23453
|
+
async ({ workspaceId, workspaceName, limit, since }) => {
|
|
23384
23454
|
try {
|
|
23385
|
-
const id = await
|
|
23386
|
-
const
|
|
23387
|
-
|
|
23388
|
-
|
|
23389
|
-
|
|
23455
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23456
|
+
const events = await api.activity.feed({
|
|
23457
|
+
workspaceId: id,
|
|
23458
|
+
limit,
|
|
23459
|
+
since
|
|
23390
23460
|
});
|
|
23391
|
-
|
|
23392
|
-
|
|
23393
|
-
|
|
23394
|
-
|
|
23395
|
-
|
|
23396
|
-
|
|
23397
|
-
`)
|
|
23398
|
-
|
|
23399
|
-
|
|
23400
|
-
|
|
23401
|
-
lines.push(
|
|
23402
|
-
`- **${sym.symbolType}** \`${sym.name}\`${parent}${exported} \u2014 ${sym.filePath}:${sym.startLine}`
|
|
23403
|
-
);
|
|
23404
|
-
}
|
|
23405
|
-
return success(lines.join("\n"));
|
|
23461
|
+
const lines = events.map((e) => {
|
|
23462
|
+
const date3 = new Date(e.timestamp).toLocaleString();
|
|
23463
|
+
const author = e.author ? ` by ${e.author}` : "";
|
|
23464
|
+
return `- [${e.type}] ${e.description}${author} (${date3})`;
|
|
23465
|
+
});
|
|
23466
|
+
return success(
|
|
23467
|
+
lines.length > 0 ? `Recent activity (${lines.length} events):
|
|
23468
|
+
|
|
23469
|
+
${lines.join("\n")}` : "No recent activity found."
|
|
23470
|
+
);
|
|
23406
23471
|
} catch (error2) {
|
|
23407
23472
|
return formatError2(error2);
|
|
23408
23473
|
}
|
|
23409
23474
|
}
|
|
23410
23475
|
);
|
|
23411
23476
|
server2.tool(
|
|
23412
|
-
"
|
|
23413
|
-
"
|
|
23477
|
+
"get_file_history",
|
|
23478
|
+
"Get the commit history for a specific file, including which AI sessions produced each change. Use this to understand how a file has evolved.",
|
|
23414
23479
|
{
|
|
23415
|
-
|
|
23416
|
-
|
|
23480
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23481
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)"),
|
|
23482
|
+
filePath: external_exports.string().describe('Path to the file (e.g. "src/index.ts")'),
|
|
23483
|
+
limit: external_exports.coerce.number().min(1).max(100).default(10).describe("Max commits to return")
|
|
23417
23484
|
},
|
|
23418
|
-
async ({
|
|
23485
|
+
async ({ workspaceId, workspaceName, filePath, limit }) => {
|
|
23419
23486
|
try {
|
|
23420
|
-
const id = await
|
|
23421
|
-
const
|
|
23422
|
-
|
|
23423
|
-
|
|
23424
|
-
|
|
23425
|
-
|
|
23426
|
-
|
|
23427
|
-
|
|
23428
|
-
|
|
23429
|
-
|
|
23430
|
-
|
|
23431
|
-
|
|
23432
|
-
|
|
23433
|
-
|
|
23487
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23488
|
+
const history = await api.activity.fileHistory({
|
|
23489
|
+
workspaceId: id,
|
|
23490
|
+
filePath,
|
|
23491
|
+
limit
|
|
23492
|
+
});
|
|
23493
|
+
const lines = history.map((entry) => {
|
|
23494
|
+
const date3 = new Date(entry.timestamp).toLocaleString();
|
|
23495
|
+
const parts = [
|
|
23496
|
+
`- ${entry.commitOid.slice(0, 7)} ${entry.message} (${entry.author}, ${date3})`
|
|
23497
|
+
];
|
|
23498
|
+
if (entry.session) {
|
|
23499
|
+
parts.push(
|
|
23500
|
+
` Session: ${entry.session.title ?? "(untitled)"} (id: ${entry.session.id})`
|
|
23501
|
+
);
|
|
23502
|
+
}
|
|
23503
|
+
return parts.join("\n");
|
|
23504
|
+
});
|
|
23434
23505
|
return success(
|
|
23435
|
-
|
|
23506
|
+
lines.length > 0 ? `File history for ${filePath} (${lines.length} commits):
|
|
23507
|
+
|
|
23508
|
+
${lines.join("\n")}` : `No commit history found for ${filePath}.`
|
|
23436
23509
|
);
|
|
23437
|
-
} catch (
|
|
23438
|
-
return formatError2(
|
|
23510
|
+
} catch (error2) {
|
|
23511
|
+
return formatError2(error2);
|
|
23512
|
+
}
|
|
23513
|
+
}
|
|
23514
|
+
);
|
|
23515
|
+
server2.tool(
|
|
23516
|
+
"get_workspace_stats",
|
|
23517
|
+
"Get high-level project statistics \u2014 sessions this week, total changes, active tasks, and total commits.",
|
|
23518
|
+
{
|
|
23519
|
+
workspaceId: external_exports.string().uuid().optional().describe("Project ID (auto-resolved from workspace link if omitted)"),
|
|
23520
|
+
workspaceName: external_exports.string().optional().describe("Project name (alternative to workspaceId)")
|
|
23521
|
+
},
|
|
23522
|
+
async ({ workspaceId, workspaceName }) => {
|
|
23523
|
+
try {
|
|
23524
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23525
|
+
const stats = await api.activity.stats({ workspaceId: id });
|
|
23526
|
+
const lines = [
|
|
23527
|
+
`Sessions this week: ${stats.sessionsThisWeek}`,
|
|
23528
|
+
`Total change requests: ${stats.totalChangeRequests}`,
|
|
23529
|
+
`Active tasks (in progress): ${stats.activeTasks}`,
|
|
23530
|
+
`Total commits: ${stats.totalCommits}`
|
|
23531
|
+
];
|
|
23532
|
+
return success(`Project stats:
|
|
23533
|
+
|
|
23534
|
+
${lines.join("\n")}`);
|
|
23535
|
+
} catch (error2) {
|
|
23536
|
+
return formatError2(error2);
|
|
23439
23537
|
}
|
|
23440
23538
|
}
|
|
23441
23539
|
);
|
|
@@ -23443,13 +23541,14 @@ Total: ${totalFiles} files, ${totalSymbols} symbols across ${buckets.length} dir
|
|
|
23443
23541
|
|
|
23444
23542
|
// src/tools/index.ts
|
|
23445
23543
|
function registerAllTools(server2) {
|
|
23446
|
-
|
|
23544
|
+
registerWorkspaceTools(server2);
|
|
23447
23545
|
registerFileTools(server2);
|
|
23448
23546
|
registerChangeRequestTools(server2);
|
|
23449
23547
|
registerCommitTools(server2);
|
|
23450
23548
|
registerSessionTools(server2);
|
|
23451
23549
|
registerSearchTools(server2);
|
|
23452
|
-
|
|
23550
|
+
registerTaskTools(server2);
|
|
23551
|
+
registerActivityTools(server2);
|
|
23453
23552
|
}
|
|
23454
23553
|
|
|
23455
23554
|
// src/index.ts
|