@integrity-labs/agt-cli 0.27.8-test.9 → 0.27.9-test.11
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/assets/impersonate-statusline.sh +7 -2
- package/dist/bin/agt.js +798 -98
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-HT6EETEL.js → chunk-45I2X4M7.js} +361 -26
- package/dist/chunk-45I2X4M7.js.map +1 -0
- package/dist/{chunk-NFBRJGNU.js → chunk-N2EBL4PZ.js} +915 -239
- package/dist/chunk-N2EBL4PZ.js.map +1 -0
- package/dist/{chunk-F4NG4EXD.js → chunk-SJPAXXTW.js} +512 -80
- package/dist/chunk-SJPAXXTW.js.map +1 -0
- package/dist/{claude-pair-runtime-OBAJZDXK.js → claude-pair-runtime-OUGV74LY.js} +2 -2
- package/dist/lib/manager-worker.js +2058 -508
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +143 -67
- package/dist/mcp/slack-channel.js +1059 -297
- package/dist/mcp/teams-channel.js +16018 -0
- package/dist/mcp/telegram-channel.js +999 -140
- package/dist/{persistent-session-SBSOZG74.js → persistent-session-G3MR7JVI.js} +5 -3
- package/dist/responsiveness-probe-UHSBETBR.js +74 -0
- package/dist/responsiveness-probe-UHSBETBR.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-F4NG4EXD.js.map +0 -1
- package/dist/chunk-HT6EETEL.js.map +0 -1
- package/dist/chunk-NFBRJGNU.js.map +0 -1
- package/dist/responsiveness-probe-DU4IJ2RZ.js +0 -33
- package/dist/responsiveness-probe-DU4IJ2RZ.js.map +0 -1
- /package/dist/{claude-pair-runtime-OBAJZDXK.js.map → claude-pair-runtime-OUGV74LY.js.map} +0 -0
- /package/dist/{persistent-session-SBSOZG74.js.map → persistent-session-G3MR7JVI.js.map} +0 -0
package/dist/mcp/index.js
CHANGED
|
@@ -21061,8 +21061,11 @@ var DeliveryTargetSchema = external_exports.union([
|
|
|
21061
21061
|
channel_id: external_exports.string().optional(),
|
|
21062
21062
|
chat_id: external_exports.string().optional(),
|
|
21063
21063
|
conversation_id: external_exports.string().optional(),
|
|
21064
|
-
service_url: external_exports.string().optional()
|
|
21065
|
-
|
|
21064
|
+
service_url: external_exports.string().optional(),
|
|
21065
|
+
thread_ts: external_exports.string().nullable().optional().describe(
|
|
21066
|
+
`Slack only (ENG-6038). The originating thread's thread_ts when the user asked for the result back in the thread the request came from ("report back here" inside a thread) \u2014 take it from the inbound message's <channel> envelope. Pass null to mean 'top-level on purpose' (e.g. the user said "post it to the channel" \u2014 null also suppresses server-side thread auto-injection on one-time tasks). Omit only when the request didn't come from a thread.`
|
|
21067
|
+
)
|
|
21068
|
+
}).describe("Post to a Slack channel, Telegram chat, or Microsoft Teams conversation. Provide channel_id for Slack, chat_id for Telegram, or conversation_id + service_url for Teams. For Slack, thread_ts optionally threads the delivery under the originating conversation."),
|
|
21066
21069
|
external_exports.object({
|
|
21067
21070
|
kind: external_exports.literal("dm"),
|
|
21068
21071
|
person_id: external_exports.string().uuid(),
|
|
@@ -21076,6 +21079,7 @@ var DeliveryTargetSchema = external_exports.union([
|
|
|
21076
21079
|
]);
|
|
21077
21080
|
var AGT_HOST = process.env.AGT_HOST;
|
|
21078
21081
|
var AGT_API_KEY = process.env.AGT_API_KEY;
|
|
21082
|
+
var AGT_AGENT_SESSION_TOKEN = process.env.AGT_AGENT_SESSION_TOKEN;
|
|
21079
21083
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID;
|
|
21080
21084
|
var AGT_AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME;
|
|
21081
21085
|
var AGT_APP_URL = (process.env.AGT_APP_URL?.trim() || "https://app.augmented.team").replace(/\/+$/, "");
|
|
@@ -21086,9 +21090,9 @@ function readRunId() {
|
|
|
21086
21090
|
}
|
|
21087
21091
|
var AGT_RUN_ID = readRunId();
|
|
21088
21092
|
var AGT_TOKEN = process.env.AGT_TOKEN ?? "";
|
|
21089
|
-
if (!AGT_HOST || !AGT_AGENT_ID || !AGT_TOKEN && !AGT_API_KEY) {
|
|
21093
|
+
if (!AGT_HOST || !AGT_AGENT_ID || !AGT_TOKEN && !AGT_API_KEY && !AGT_AGENT_SESSION_TOKEN) {
|
|
21090
21094
|
console.error(
|
|
21091
|
-
"augmented-mcp: Missing required env vars. Need AGT_HOST, AGT_AGENT_ID, and AGT_TOKEN or AGT_API_KEY"
|
|
21095
|
+
"augmented-mcp: Missing required env vars. Need AGT_HOST, AGT_AGENT_ID, and one of AGT_AGENT_SESSION_TOKEN, AGT_TOKEN, or AGT_API_KEY"
|
|
21092
21096
|
);
|
|
21093
21097
|
process.exit(1);
|
|
21094
21098
|
}
|
|
@@ -21110,6 +21114,9 @@ async function refreshToken() {
|
|
|
21110
21114
|
return AGT_TOKEN;
|
|
21111
21115
|
}
|
|
21112
21116
|
async function getToken() {
|
|
21117
|
+
if (AGT_AGENT_SESSION_TOKEN) {
|
|
21118
|
+
return AGT_AGENT_SESSION_TOKEN;
|
|
21119
|
+
}
|
|
21113
21120
|
if (AGT_API_KEY && (!AGT_TOKEN || Date.now() > tokenExpiresAt - 5 * 6e4)) {
|
|
21114
21121
|
if (!exchangeInFlight) {
|
|
21115
21122
|
exchangeInFlight = refreshToken().finally(() => {
|
|
@@ -21141,13 +21148,18 @@ async function apiPost(path, body, retried = false, timeoutMs = 15e3) {
|
|
|
21141
21148
|
body: JSON.stringify(body),
|
|
21142
21149
|
signal: controller.signal
|
|
21143
21150
|
});
|
|
21144
|
-
if (res.status === 401 && AGT_API_KEY && !retried) {
|
|
21151
|
+
if (res.status === 401 && AGT_API_KEY && !AGT_AGENT_SESSION_TOKEN && !retried) {
|
|
21145
21152
|
clearTimeout(timeout);
|
|
21146
21153
|
tokenExpiresAt = 0;
|
|
21147
21154
|
return apiPost(path, body, true, timeoutMs);
|
|
21148
21155
|
}
|
|
21149
21156
|
if (!res.ok) {
|
|
21150
21157
|
const text = await res.text().catch(() => res.statusText);
|
|
21158
|
+
if (res.status === 401 && AGT_AGENT_SESSION_TOKEN) {
|
|
21159
|
+
throw new Error(
|
|
21160
|
+
`API ${path} returned 401: agent-session rejected (expired or revoked). Re-run \`agt impersonate connect\` to mint a fresh session. (${text})`
|
|
21161
|
+
);
|
|
21162
|
+
}
|
|
21151
21163
|
throw new Error(`API ${path} returned ${res.status}: ${text}`);
|
|
21152
21164
|
}
|
|
21153
21165
|
return await res.json();
|
|
@@ -21177,7 +21189,7 @@ server.tool(
|
|
|
21177
21189
|
}
|
|
21178
21190
|
const grouped = groupByStatus(data.items);
|
|
21179
21191
|
const lines = [];
|
|
21180
|
-
for (const status of ["in_progress", "todo", "backlog", "done"]) {
|
|
21192
|
+
for (const status of ["in_progress", "todo", "backlog", "done", "failed"]) {
|
|
21181
21193
|
const items = grouped[status];
|
|
21182
21194
|
if (!items?.length) continue;
|
|
21183
21195
|
lines.push(`
|
|
@@ -21236,11 +21248,11 @@ server.tool(
|
|
|
21236
21248
|
);
|
|
21237
21249
|
server.tool(
|
|
21238
21250
|
"kanban_move",
|
|
21239
|
-
|
|
21251
|
+
'Move a kanban item to a different status column. Use status="failed" to mark a task that was attempted but could not complete (matches the hosted kanban_move enum).',
|
|
21240
21252
|
{
|
|
21241
21253
|
id: external_exports.string().optional().describe("Item UUID (preferred)"),
|
|
21242
21254
|
title: external_exports.string().optional().describe("Item title for fuzzy match (if no id)"),
|
|
21243
|
-
status: external_exports.enum(["backlog", "todo", "in_progress", "done"]).describe(
|
|
21255
|
+
status: external_exports.enum(["backlog", "todo", "in_progress", "done", "failed"]).describe('Target status. "failed" closes the row as a failed attempt; there is no "cancelled" status \u2014 close no-longer-needed work via kanban_done with an explanatory result.'),
|
|
21244
21256
|
notes: external_exports.string().optional().describe("Progress notes")
|
|
21245
21257
|
},
|
|
21246
21258
|
async (params) => {
|
|
@@ -21728,7 +21740,7 @@ server.tool(
|
|
|
21728
21740
|
prompt: external_exports.string().describe("What to do when the task fires"),
|
|
21729
21741
|
delivery_channel: external_exports.string().optional().describe('Channel platform to deliver results to (e.g. "slack", "telegram"). Default: "slack" if available.'),
|
|
21730
21742
|
delivery_to: DeliveryTargetSchema.optional().describe(
|
|
21731
|
-
"Where the task output should be delivered. Structured object: either { kind: 'channel', provider, channel_id? | chat_id? } to post to a Slack channel / Telegram chat, or { kind: 'dm', person_id, follow_reports_to, medium } to DM a person. For 'reply to the channel this request came from', pass the incoming message's channel_id. For 'DM my manager', use follow_reports_to=true with the agent's current reports_to person_id. Legacy string forms ('channel:<id>', 'chat:<id>', 'slack_user:<id>') are rejected server-side \u2014 use the structured form."
|
|
21743
|
+
"Where the task output should be delivered. Structured object: either { kind: 'channel', provider, channel_id? | chat_id? } to post to a Slack channel / Telegram chat, or { kind: 'dm', person_id, follow_reports_to, medium } to DM a person. For 'reply to the channel this request came from', pass the incoming message's channel_id. For 'report back HERE' said inside a Slack thread, also pass thread_ts from the inbound envelope so the result lands in that thread; if the user wants the channel top-level despite asking from a thread, pass thread_ts: null. For 'DM my manager', use follow_reports_to=true with the agent's current reports_to person_id. Legacy string forms ('channel:<id>', 'chat:<id>', 'slack_user:<id>') are rejected server-side \u2014 use the structured form."
|
|
21732
21744
|
),
|
|
21733
21745
|
delivery_mode: external_exports.enum(["announce", "none"]).optional().describe('Delivery mode: "announce" sends output to delivery_channel, "none" suppresses. Default: "announce".')
|
|
21734
21746
|
},
|
|
@@ -21801,7 +21813,7 @@ server.tool(
|
|
|
21801
21813
|
'Where results are delivered (e.g. "slack", "telegram", "email")'
|
|
21802
21814
|
),
|
|
21803
21815
|
delivery_to: DeliveryTargetSchema.optional().describe(
|
|
21804
|
-
"Structured delivery target (see schedule_create description for shape). Pass null-equivalent by omitting the field; pass a new structured target to change routing."
|
|
21816
|
+
"Structured delivery target (see schedule_create description for shape). Pass null-equivalent by omitting the field; pass a new structured target to change routing. delivery_to is replaced wholesale: to STOP a task threading into a Slack conversation ('post it to the channel instead'), pass the channel target again WITHOUT thread_ts; to start threading, include thread_ts."
|
|
21805
21817
|
),
|
|
21806
21818
|
enabled: external_exports.boolean().optional().describe(
|
|
21807
21819
|
"Set to false to pause the schedule without deleting it"
|
|
@@ -22243,7 +22255,8 @@ function statusLabel(status) {
|
|
|
22243
22255
|
backlog: "Backlog",
|
|
22244
22256
|
todo: "To Do",
|
|
22245
22257
|
in_progress: "In Progress",
|
|
22246
|
-
done: "Done"
|
|
22258
|
+
done: "Done",
|
|
22259
|
+
failed: "Failed"
|
|
22247
22260
|
};
|
|
22248
22261
|
return labels[status] ?? status;
|
|
22249
22262
|
}
|
|
@@ -22317,9 +22330,13 @@ var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
22317
22330
|
"dashboards_request_refresh",
|
|
22318
22331
|
"dashboards_pending_refreshes",
|
|
22319
22332
|
"dashboards_persist_widget",
|
|
22333
|
+
"artefacts_list",
|
|
22334
|
+
"artefacts_get",
|
|
22335
|
+
"artefacts_get_source_chunk",
|
|
22336
|
+
// ADR-0017 Projects container (the reclaimed projects_* namespace — read-only
|
|
22337
|
+
// in v1; no projects_get_source_chunk, a project is a container not a document).
|
|
22320
22338
|
"projects_list",
|
|
22321
|
-
"projects_get"
|
|
22322
|
-
"projects_get_source_chunk"
|
|
22339
|
+
"projects_get"
|
|
22323
22340
|
]);
|
|
22324
22341
|
async function registerForwardedApiTools() {
|
|
22325
22342
|
const apiTools = await discoverApiTools();
|
|
@@ -22353,76 +22370,135 @@ async function registerForwardedApiTools() {
|
|
|
22353
22370
|
}
|
|
22354
22371
|
return { registered, skipped };
|
|
22355
22372
|
}
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
|
|
22359
|
-
|
|
22360
|
-
publisher: external_exports.string().optional().describe('Filter by publisher (e.g. "here-now")'),
|
|
22361
|
-
kind: external_exports.enum(["mockup", "deck", "site", "app", "other"]).optional().describe("Filter by artefact kind"),
|
|
22362
|
-
limit: external_exports.number().int().min(1).max(100).optional().describe("Maximum projects to return (default 50, max 100)")
|
|
22363
|
-
},
|
|
22364
|
-
async (params) => {
|
|
22365
|
-
const data = await apiPost("/host/my-published-projects", {
|
|
22373
|
+
async function listPublishedArtefactsText(params) {
|
|
22374
|
+
const data = await apiPost(
|
|
22375
|
+
"/host/my-published-artefacts",
|
|
22376
|
+
{
|
|
22366
22377
|
agent_id: AGT_AGENT_ID,
|
|
22367
22378
|
publisher: params.publisher,
|
|
22368
22379
|
kind: params.kind,
|
|
22369
22380
|
limit: params.limit
|
|
22370
|
-
});
|
|
22371
|
-
if (!data.projects.length) {
|
|
22372
|
-
return { content: [{ type: "text", text: "No published projects yet." }] };
|
|
22373
22381
|
}
|
|
22374
|
-
|
|
22375
|
-
|
|
22376
|
-
|
|
22377
|
-
|
|
22378
|
-
|
|
22379
|
-
|
|
22380
|
-
|
|
22382
|
+
);
|
|
22383
|
+
if (!data.artefacts.length) {
|
|
22384
|
+
return "No published artefacts yet.";
|
|
22385
|
+
}
|
|
22386
|
+
return data.artefacts.map((p) => {
|
|
22387
|
+
const title = p.title ?? "(untitled)";
|
|
22388
|
+
const expires = p.expires_at ? ` expires ${p.expires_at}` : "";
|
|
22389
|
+
return `- [${p.kind}] ${title} \u2014 ${p.live_url} (id: ${p.id}, ${p.mode}, published ${p.published_at}${expires})`;
|
|
22390
|
+
}).join("\n");
|
|
22391
|
+
}
|
|
22392
|
+
async function getPublishedArtefactText(artefactId) {
|
|
22393
|
+
const data = await apiPost(`/host/published-artefact/${encodeURIComponent(artefactId)}`, {
|
|
22394
|
+
agent_id: AGT_AGENT_ID
|
|
22395
|
+
});
|
|
22396
|
+
const p = data.artefact;
|
|
22397
|
+
return [
|
|
22398
|
+
`Artefact: ${p.title ?? "(untitled)"} [${p.kind}]`,
|
|
22399
|
+
`Publisher: ${p.publisher} (${p.mode})`,
|
|
22400
|
+
`Live URL: ${p.live_url}`,
|
|
22401
|
+
p.claim_url ? `Claim URL: ${p.claim_url}` : null,
|
|
22402
|
+
`Published: ${p.published_at}`,
|
|
22403
|
+
p.expires_at ? `Expires: ${p.expires_at}` : null,
|
|
22404
|
+
`Last modified: ${p.last_modified_at}`,
|
|
22405
|
+
p.has_source_html ? `Source HTML: ${p.source_html_length} bytes (call artefacts_get_source_chunk to fetch)` : "(source HTML not preserved for this artefact)"
|
|
22406
|
+
].filter((s) => s !== null).join("\n");
|
|
22407
|
+
}
|
|
22408
|
+
async function getPublishedArtefactSourceChunkText(artefactId, offset, limit) {
|
|
22409
|
+
const data = await apiPost(`/host/published-artefact/${encodeURIComponent(artefactId)}/source-chunk`, {
|
|
22410
|
+
agent_id: AGT_AGENT_ID,
|
|
22411
|
+
offset,
|
|
22412
|
+
limit
|
|
22413
|
+
});
|
|
22414
|
+
const trailer = data.end_of_content ? "\n\n---\n(end of source)" : `
|
|
22415
|
+
|
|
22416
|
+
---
|
|
22417
|
+
(more \u2014 next offset: ${data.offset + data.length}, total: ${data.total_length} bytes)`;
|
|
22418
|
+
return data.chunk + trailer;
|
|
22419
|
+
}
|
|
22420
|
+
var artefactListSchema = {
|
|
22421
|
+
publisher: external_exports.string().optional().describe('Filter by publisher (e.g. "here-now")'),
|
|
22422
|
+
kind: external_exports.enum(["mockup", "deck", "site", "app", "other"]).optional().describe("Filter by artefact kind"),
|
|
22423
|
+
limit: external_exports.number().int().min(1).max(100).optional().describe("Maximum artefacts to return (default 50, max 100)")
|
|
22424
|
+
};
|
|
22425
|
+
server.tool(
|
|
22426
|
+
"artefacts_list",
|
|
22427
|
+
"List artefacts (websites, slide decks, mockups) this agent has previously published. Call this BEFORE re-publishing to find and modify existing work instead of creating duplicates.",
|
|
22428
|
+
artefactListSchema,
|
|
22429
|
+
async (params) => ({
|
|
22430
|
+
content: [{ type: "text", text: await listPublishedArtefactsText(params) }]
|
|
22431
|
+
})
|
|
22381
22432
|
);
|
|
22382
22433
|
server.tool(
|
|
22383
|
-
"
|
|
22384
|
-
"Fetch metadata for a single published
|
|
22434
|
+
"artefacts_get",
|
|
22435
|
+
"Fetch metadata for a single published artefact. Returns the artefact record without the source HTML \u2014 call artefacts_get_source_chunk to retrieve the HTML in chunks when you need to modify it.",
|
|
22385
22436
|
{
|
|
22386
|
-
|
|
22437
|
+
artefact_id: external_exports.string().uuid().describe("The artefact id returned by artefacts_list")
|
|
22387
22438
|
},
|
|
22388
|
-
async (params) => {
|
|
22389
|
-
|
|
22390
|
-
|
|
22391
|
-
});
|
|
22392
|
-
const p = data.project;
|
|
22393
|
-
const header = [
|
|
22394
|
-
`Project: ${p.title ?? "(untitled)"} [${p.kind}]`,
|
|
22395
|
-
`Publisher: ${p.publisher} (${p.mode})`,
|
|
22396
|
-
`Live URL: ${p.live_url}`,
|
|
22397
|
-
p.claim_url ? `Claim URL: ${p.claim_url}` : null,
|
|
22398
|
-
`Published: ${p.published_at}`,
|
|
22399
|
-
p.expires_at ? `Expires: ${p.expires_at}` : null,
|
|
22400
|
-
`Last modified: ${p.last_modified_at}`,
|
|
22401
|
-
p.has_source_html ? `Source HTML: ${p.source_html_length} bytes (call projects_get_source_chunk to fetch)` : "(source HTML not preserved for this project)"
|
|
22402
|
-
].filter((s) => s !== null).join("\n");
|
|
22403
|
-
return { content: [{ type: "text", text: header }] };
|
|
22404
|
-
}
|
|
22439
|
+
async (params) => ({
|
|
22440
|
+
content: [{ type: "text", text: await getPublishedArtefactText(params.artefact_id) }]
|
|
22441
|
+
})
|
|
22405
22442
|
);
|
|
22406
22443
|
server.tool(
|
|
22407
|
-
"
|
|
22408
|
-
"Fetch a chunk of source HTML for a published
|
|
22444
|
+
"artefacts_get_source_chunk",
|
|
22445
|
+
"Fetch a chunk of source HTML for a published artefact. Use this to assemble the HTML for modification when artefacts_get reports a non-zero source_html_length.",
|
|
22409
22446
|
{
|
|
22410
|
-
|
|
22447
|
+
artefact_id: external_exports.string().uuid().describe("The artefact id returned by artefacts_list"),
|
|
22411
22448
|
offset: external_exports.number().int().min(0).describe("Byte offset into the source HTML to start from"),
|
|
22412
22449
|
limit: external_exports.number().int().min(1).max(65536).optional().describe("Max bytes to return (default 32KB, max 64KB)")
|
|
22413
22450
|
},
|
|
22414
|
-
async (params) => {
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
|
|
22418
|
-
|
|
22419
|
-
|
|
22420
|
-
|
|
22421
|
-
|
|
22422
|
-
|
|
22423
|
-
|
|
22424
|
-
|
|
22451
|
+
async (params) => ({
|
|
22452
|
+
content: [
|
|
22453
|
+
{ type: "text", text: await getPublishedArtefactSourceChunkText(params.artefact_id, params.offset, params.limit) }
|
|
22454
|
+
]
|
|
22455
|
+
})
|
|
22456
|
+
);
|
|
22457
|
+
async function listProjectsText(params) {
|
|
22458
|
+
const data = await apiPost("/host/my-projects", {
|
|
22459
|
+
agent_id: AGT_AGENT_ID,
|
|
22460
|
+
status: params.status,
|
|
22461
|
+
limit: params.limit
|
|
22462
|
+
});
|
|
22463
|
+
if (!data.projects.length) {
|
|
22464
|
+
return "No projects yet. Projects are created by a human in the console; ask one to create a project to group your work under.";
|
|
22425
22465
|
}
|
|
22466
|
+
return data.projects.map((p) => `- ${p.name} [${p.status}] (id: ${p.id}, created ${p.created_at})`).join("\n");
|
|
22467
|
+
}
|
|
22468
|
+
async function getProjectText(projectId) {
|
|
22469
|
+
const data = await apiPost(
|
|
22470
|
+
`/host/project/${encodeURIComponent(projectId)}`,
|
|
22471
|
+
{ agent_id: AGT_AGENT_ID }
|
|
22472
|
+
);
|
|
22473
|
+
const p = data.project;
|
|
22474
|
+
return [
|
|
22475
|
+
`Project: ${p.name} [${p.status}]`,
|
|
22476
|
+
`Id: ${p.id}`,
|
|
22477
|
+
p.linear_project_id ? `Linear project: ${p.linear_project_id}` : null,
|
|
22478
|
+
`Created: ${p.created_at}`,
|
|
22479
|
+
`Last updated: ${p.updated_at}`
|
|
22480
|
+
].filter((s) => s !== null).join("\n");
|
|
22481
|
+
}
|
|
22482
|
+
server.tool(
|
|
22483
|
+
"projects_list",
|
|
22484
|
+
"List the projects belonging to this agent's team. A project is a container that groups related tasks and published artefacts across agents under one unit of work. Read-only: projects are created by humans in the console.",
|
|
22485
|
+
{
|
|
22486
|
+
status: external_exports.enum(["active", "archived"]).optional().describe("Filter by project status"),
|
|
22487
|
+
limit: external_exports.number().int().min(1).max(100).optional().describe("Maximum projects to return (default 50, max 100)")
|
|
22488
|
+
},
|
|
22489
|
+
async (params) => ({
|
|
22490
|
+
content: [{ type: "text", text: await listProjectsText(params) }]
|
|
22491
|
+
})
|
|
22492
|
+
);
|
|
22493
|
+
server.tool(
|
|
22494
|
+
"projects_get",
|
|
22495
|
+
"Fetch a single project (a team-scoped container) by id, including its name, status, and optional Linear link.",
|
|
22496
|
+
{
|
|
22497
|
+
project_id: external_exports.string().uuid().describe("The project id returned by projects_list")
|
|
22498
|
+
},
|
|
22499
|
+
async (params) => ({
|
|
22500
|
+
content: [{ type: "text", text: await getProjectText(params.project_id) }]
|
|
22501
|
+
})
|
|
22426
22502
|
);
|
|
22427
22503
|
async function main() {
|
|
22428
22504
|
try {
|