@integrity-labs/agt-cli 0.27.8 → 0.27.9-test.12
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 +946 -129
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-YSBGIXJG.js → chunk-I2OTQJH3.js} +361 -26
- package/dist/chunk-I2OTQJH3.js.map +1 -0
- package/dist/{chunk-GN4XPQWJ.js → chunk-MQJ5DMPT.js} +535 -94
- package/dist/chunk-MQJ5DMPT.js.map +1 -0
- package/dist/{chunk-IB655E5U.js → chunk-SXBZDUKN.js} +1086 -285
- package/dist/chunk-SXBZDUKN.js.map +1 -0
- package/dist/{claude-pair-runtime-ZBQKBBMT.js → claude-pair-runtime-F6USL3EW.js} +2 -2
- package/dist/lib/manager-worker.js +2071 -517
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +49 -455
- package/dist/mcp/index.js +232 -137
- package/dist/mcp/slack-channel.js +1379 -856
- package/dist/mcp/teams-channel.js +16018 -0
- package/dist/mcp/telegram-channel.js +1264 -618
- package/dist/{persistent-session-ICYFLUAM.js → persistent-session-OL5EDYB4.js} +5 -3
- package/dist/responsiveness-probe-B6LJJRUD.js +74 -0
- package/dist/responsiveness-probe-B6LJJRUD.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-GN4XPQWJ.js.map +0 -1
- package/dist/chunk-IB655E5U.js.map +0 -1
- package/dist/chunk-YSBGIXJG.js.map +0 -1
- package/dist/responsiveness-probe-WZNQ2762.js +0 -33
- package/dist/responsiveness-probe-WZNQ2762.js.map +0 -1
- /package/dist/{claude-pair-runtime-ZBQKBBMT.js.map → claude-pair-runtime-F6USL3EW.js.map} +0 -0
- /package/dist/{persistent-session-ICYFLUAM.js.map → persistent-session-OL5EDYB4.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();
|
|
@@ -21165,7 +21177,7 @@ var server = new McpServer({
|
|
|
21165
21177
|
version: "0.1.0"
|
|
21166
21178
|
});
|
|
21167
21179
|
server.tool(
|
|
21168
|
-
"
|
|
21180
|
+
"kanban_list",
|
|
21169
21181
|
"List kanban board items for this agent. Returns active items and recently completed items (last 7 days).",
|
|
21170
21182
|
{},
|
|
21171
21183
|
async () => {
|
|
@@ -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(`
|
|
@@ -21194,7 +21206,7 @@ server.tool(
|
|
|
21194
21206
|
}
|
|
21195
21207
|
);
|
|
21196
21208
|
server.tool(
|
|
21197
|
-
"
|
|
21209
|
+
"kanban_add",
|
|
21198
21210
|
"Add a new item to the kanban board.",
|
|
21199
21211
|
{
|
|
21200
21212
|
title: external_exports.string().describe("Item title (max 200 chars)"),
|
|
@@ -21235,12 +21247,12 @@ server.tool(
|
|
|
21235
21247
|
}
|
|
21236
21248
|
);
|
|
21237
21249
|
server.tool(
|
|
21238
|
-
"
|
|
21239
|
-
|
|
21250
|
+
"kanban_move",
|
|
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) => {
|
|
@@ -21273,7 +21285,7 @@ server.tool(
|
|
|
21273
21285
|
}
|
|
21274
21286
|
);
|
|
21275
21287
|
server.tool(
|
|
21276
|
-
"
|
|
21288
|
+
"kanban_update",
|
|
21277
21289
|
"Update notes or result on a kanban item without changing its status.",
|
|
21278
21290
|
{
|
|
21279
21291
|
id: external_exports.string().optional().describe("Item UUID (preferred)"),
|
|
@@ -21324,7 +21336,7 @@ server.tool(
|
|
|
21324
21336
|
}
|
|
21325
21337
|
);
|
|
21326
21338
|
server.tool(
|
|
21327
|
-
"
|
|
21339
|
+
"kanban_progress",
|
|
21328
21340
|
"Report what you're doing RIGHT NOW on a kanban item. Overwrites a single live status line (the Step row on the Slack progress card the requester is watching) \u2014 not a log. Call it at the start of each phase of a long task (ideally ~every minute) so the requester can watch the work move. Each call also renews the task heartbeat. Pass an empty step to clear it.",
|
|
21329
21341
|
{
|
|
21330
21342
|
id: external_exports.string().optional().describe("Item UUID (preferred)"),
|
|
@@ -21362,7 +21374,7 @@ server.tool(
|
|
|
21362
21374
|
}
|
|
21363
21375
|
);
|
|
21364
21376
|
server.tool(
|
|
21365
|
-
"
|
|
21377
|
+
"kanban_done",
|
|
21366
21378
|
"Mark a kanban item as done with an optional result.",
|
|
21367
21379
|
{
|
|
21368
21380
|
id: external_exports.string().optional().describe("Item UUID (preferred)"),
|
|
@@ -21401,7 +21413,7 @@ server.tool(
|
|
|
21401
21413
|
}
|
|
21402
21414
|
);
|
|
21403
21415
|
server.tool(
|
|
21404
|
-
"
|
|
21416
|
+
"status_standup",
|
|
21405
21417
|
"Submit a daily standup update with yesterday, today, and blockers.",
|
|
21406
21418
|
{
|
|
21407
21419
|
yesterday: external_exports.string().describe("What was accomplished yesterday/last session"),
|
|
@@ -21434,7 +21446,7 @@ server.tool(
|
|
|
21434
21446
|
}
|
|
21435
21447
|
);
|
|
21436
21448
|
server.tool(
|
|
21437
|
-
"
|
|
21449
|
+
"status_update",
|
|
21438
21450
|
"Report current task progress or status update.",
|
|
21439
21451
|
{
|
|
21440
21452
|
current_tasks: external_exports.string().describe("Summary of what you are currently working on")
|
|
@@ -21461,7 +21473,7 @@ server.tool(
|
|
|
21461
21473
|
}
|
|
21462
21474
|
);
|
|
21463
21475
|
server.tool(
|
|
21464
|
-
"
|
|
21476
|
+
"drift_report",
|
|
21465
21477
|
"Report configuration drift detected in local agent files (CHARTER.md, TOOLS.md, etc.). Compares local file hashes against API-side versions and reports any differences.",
|
|
21466
21478
|
{
|
|
21467
21479
|
drifted_files: external_exports.array(external_exports.string()).describe('List of filenames that have drifted from provisioned state (e.g. ["CHARTER.md", "TOOLS.md"])'),
|
|
@@ -21484,7 +21496,7 @@ server.tool(
|
|
|
21484
21496
|
}
|
|
21485
21497
|
);
|
|
21486
21498
|
server.tool(
|
|
21487
|
-
"
|
|
21499
|
+
"token_refresh",
|
|
21488
21500
|
"Get a working OAuth access token for an integration. Returns the current cached token when it is still valid (the server-side cron rotates tokens every ~15 minutes) and forces a refresh only when the cached token is expiring or missing. Pass `integration_id` to force-refresh a specific integration after a 401/TokenExpired from the provider.",
|
|
21489
21501
|
{
|
|
21490
21502
|
integration_id: external_exports.string().optional().describe("Specific integration UUID to force-refresh (use after a 401 from the provider). If omitted, returns current tokens for all OAuth integrations, refreshing any that are within ~10 minutes of expiry.")
|
|
@@ -21578,7 +21590,7 @@ async function runAcpxCommand(args, cwd) {
|
|
|
21578
21590
|
});
|
|
21579
21591
|
}
|
|
21580
21592
|
server.tool(
|
|
21581
|
-
"
|
|
21593
|
+
"acpx_prompt",
|
|
21582
21594
|
"Send a prompt to a coding agent (claude, codex, openclaw) via ACP. Uses persistent sessions scoped to the working directory.",
|
|
21583
21595
|
{
|
|
21584
21596
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent to use"),
|
|
@@ -21603,7 +21615,7 @@ server.tool(
|
|
|
21603
21615
|
}
|
|
21604
21616
|
);
|
|
21605
21617
|
server.tool(
|
|
21606
|
-
"
|
|
21618
|
+
"acpx_exec",
|
|
21607
21619
|
"Run a one-shot task on a coding agent. Does not reuse sessions \u2014 fire and forget.",
|
|
21608
21620
|
{
|
|
21609
21621
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent to use"),
|
|
@@ -21622,7 +21634,7 @@ server.tool(
|
|
|
21622
21634
|
}
|
|
21623
21635
|
);
|
|
21624
21636
|
server.tool(
|
|
21625
|
-
"
|
|
21637
|
+
"acpx_spawn",
|
|
21626
21638
|
"Ensure an ACP session exists for a coding agent. Creates one if needed, reuses existing.",
|
|
21627
21639
|
{
|
|
21628
21640
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent to use"),
|
|
@@ -21642,7 +21654,7 @@ server.tool(
|
|
|
21642
21654
|
}
|
|
21643
21655
|
);
|
|
21644
21656
|
server.tool(
|
|
21645
|
-
"
|
|
21657
|
+
"acpx_cancel",
|
|
21646
21658
|
"Send a cooperative cancel to the running ACP session. Does not destroy state.",
|
|
21647
21659
|
{
|
|
21648
21660
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent to cancel"),
|
|
@@ -21662,7 +21674,7 @@ server.tool(
|
|
|
21662
21674
|
}
|
|
21663
21675
|
);
|
|
21664
21676
|
server.tool(
|
|
21665
|
-
"
|
|
21677
|
+
"acpx_status",
|
|
21666
21678
|
"Check the status of the current ACP session (running, idle, dead).",
|
|
21667
21679
|
{
|
|
21668
21680
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent to check"),
|
|
@@ -21676,7 +21688,7 @@ server.tool(
|
|
|
21676
21688
|
}
|
|
21677
21689
|
);
|
|
21678
21690
|
server.tool(
|
|
21679
|
-
"
|
|
21691
|
+
"acpx_close",
|
|
21680
21692
|
"Soft-close an ACP session. Terminates the process but preserves history.",
|
|
21681
21693
|
{
|
|
21682
21694
|
agent: external_exports.enum(["claude", "codex", "openclaw"]).describe("Coding agent session to close"),
|
|
@@ -21696,7 +21708,7 @@ server.tool(
|
|
|
21696
21708
|
}
|
|
21697
21709
|
);
|
|
21698
21710
|
server.tool(
|
|
21699
|
-
"
|
|
21711
|
+
"schedule_list",
|
|
21700
21712
|
"List your scheduled tasks (cron jobs, reminders, recurring work).",
|
|
21701
21713
|
{},
|
|
21702
21714
|
async () => {
|
|
@@ -21716,7 +21728,7 @@ server.tool(
|
|
|
21716
21728
|
}
|
|
21717
21729
|
);
|
|
21718
21730
|
server.tool(
|
|
21719
|
-
"
|
|
21731
|
+
"schedule_create",
|
|
21720
21732
|
"Create a new scheduled task. Supports cron expressions, intervals (every), and one-time reminders (at).",
|
|
21721
21733
|
{
|
|
21722
21734
|
name: external_exports.string().describe('Display name for the task (e.g. "Daily standup", "Check emails")'),
|
|
@@ -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
|
},
|
|
@@ -21752,10 +21764,10 @@ server.tool(
|
|
|
21752
21764
|
}
|
|
21753
21765
|
);
|
|
21754
21766
|
server.tool(
|
|
21755
|
-
"
|
|
21767
|
+
"schedule_delete",
|
|
21756
21768
|
"Delete a scheduled task by ID.",
|
|
21757
21769
|
{
|
|
21758
|
-
task_id: external_exports.string().describe("The task ID to delete (from
|
|
21770
|
+
task_id: external_exports.string().describe("The task ID to delete (from schedule_list)")
|
|
21759
21771
|
},
|
|
21760
21772
|
async (params) => {
|
|
21761
21773
|
await apiPost("/host/schedules/delete", {
|
|
@@ -21768,12 +21780,17 @@ server.tool(
|
|
|
21768
21780
|
}
|
|
21769
21781
|
);
|
|
21770
21782
|
server.tool(
|
|
21771
|
-
"
|
|
21783
|
+
"schedule_update",
|
|
21772
21784
|
// Lead with user phrasings the agent should match against, then explain
|
|
21773
21785
|
// the two modes. Order matters for tool selection.
|
|
21774
|
-
|
|
21786
|
+
// CR PR #1601: field names + delivery_to shape brought into line with the
|
|
21787
|
+
// actual zod schema below. The prior copy referenced `cron_expression` /
|
|
21788
|
+
// `interval` (which the schema doesn't accept) and described
|
|
21789
|
+
// `delivery_to` as a raw channel ID (it's a structured DeliveryTargetSchema
|
|
21790
|
+
// object). Agents reading the old wording were producing invalid calls.
|
|
21791
|
+
'Update an existing scheduled task. USE THIS TOOL when the user says: "change the schedule for X", "run the daily report at 10am instead of 9am", "pause the standup schedule", "move the weekly digest to Mondays", "make this report more concise", "add a section about X to the daily summary", "tell the Y schedule to also cover Z", "post these to the Customer Success channel from now on". Two modes: (1) DIRECT FIELD UPDATES \u2014 set schedule_expr/schedule_every/schedule_at/timezone/delivery_channel/delivery_to/enabled/name/prompt to change those values directly (pair the expression field with the matching schedule_kind: cron/every/at). (2) LLM DESCRIPTION REWRITE \u2014 pass description_feedback to have the platform rewrite the task prompt based on natural-language feedback (e.g. "make this more concise" or "add a section about the team backlog"). Default for LLM rewrites is preview-then-apply: call once to get the proposed rewrite, show the diff to the user, call again with auto_apply=true on confirmation. Direct field updates apply immediately. The two modes are mutually exclusive \u2014 one request is EITHER a field update OR a description rewrite.\n\nIMPORTANT \u2014 `delivery_to` is a structured target object, not a human channel name. If the user references a Slack channel by name ("the Customer Success channel"), call `mcp__slack__slack.list_channels` first with `query: "customer success"` to get the matching `id`, then pass `delivery_to: { kind: "channel", provider: "slack", channel_id: "<id>" }`. Do not guess channel ids.',
|
|
21775
21792
|
{
|
|
21776
|
-
task_id: external_exports.string().describe("The task ID to update (from
|
|
21793
|
+
task_id: external_exports.string().describe("The task ID to update (from schedule_list)"),
|
|
21777
21794
|
// Direct-field mode
|
|
21778
21795
|
name: external_exports.string().optional().describe("New task display name"),
|
|
21779
21796
|
schedule_kind: external_exports.enum(["cron", "every", "at"]).optional().describe(
|
|
@@ -21796,7 +21813,7 @@ server.tool(
|
|
|
21796
21813
|
'Where results are delivered (e.g. "slack", "telegram", "email")'
|
|
21797
21814
|
),
|
|
21798
21815
|
delivery_to: DeliveryTargetSchema.optional().describe(
|
|
21799
|
-
"Structured delivery target (see
|
|
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."
|
|
21800
21817
|
),
|
|
21801
21818
|
enabled: external_exports.boolean().optional().describe(
|
|
21802
21819
|
"Set to false to pause the schedule without deleting it"
|
|
@@ -21833,7 +21850,7 @@ server.tool(
|
|
|
21833
21850
|
if (!data.applied) {
|
|
21834
21851
|
lines.push("");
|
|
21835
21852
|
lines.push("---");
|
|
21836
|
-
lines.push("Show this diff to the user. If they confirm, call `
|
|
21853
|
+
lines.push("Show this diff to the user. If they confirm, call `schedule_update` again with the same `task_id` and `description_feedback` plus `auto_apply: true` to commit the change.");
|
|
21837
21854
|
}
|
|
21838
21855
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
21839
21856
|
}
|
|
@@ -21846,8 +21863,8 @@ server.tool(
|
|
|
21846
21863
|
}
|
|
21847
21864
|
);
|
|
21848
21865
|
server.tool(
|
|
21849
|
-
"
|
|
21850
|
-
"List team knowledge entries (ids, titles, source types). Use before
|
|
21866
|
+
"knowledge_list",
|
|
21867
|
+
"List team knowledge entries (ids, titles, source types). Use before knowledge_add to check if a fact is already saved, or before knowledge_update/delete to find the target id. Returns metadata only \u2014 fetch the full content via the webapp if you need to read an entry back.",
|
|
21851
21868
|
{},
|
|
21852
21869
|
async () => {
|
|
21853
21870
|
const data = await apiPost("/host/my-knowledge", {
|
|
@@ -21864,8 +21881,8 @@ server.tool(
|
|
|
21864
21881
|
}
|
|
21865
21882
|
);
|
|
21866
21883
|
server.tool(
|
|
21867
|
-
"
|
|
21868
|
-
"Save a new durable fact or learning to the team knowledge base. Use when the user explicitly asks you to save/remember something, or when you discover information that will be useful on future runs (e.g. a tenant id, an API key name, a company policy). Do NOT use for tasks (use
|
|
21884
|
+
"knowledge_add",
|
|
21885
|
+
"Save a new durable fact or learning to the team knowledge base. Use when the user explicitly asks you to save/remember something, or when you discover information that will be useful on future runs (e.g. a tenant id, an API key name, a company policy). Do NOT use for tasks (use kanban_add) or trivial one-off answers. Returns the new entry id so you can target it with knowledge_update / knowledge_delete.",
|
|
21869
21886
|
{
|
|
21870
21887
|
title: external_exports.string().describe("Short title summarising the entry (max 200 chars)"),
|
|
21871
21888
|
content: external_exports.string().describe("The knowledge content \u2014 the actual fact, learning, or reference material"),
|
|
@@ -21903,10 +21920,10 @@ server.tool(
|
|
|
21903
21920
|
}
|
|
21904
21921
|
);
|
|
21905
21922
|
server.tool(
|
|
21906
|
-
"
|
|
21907
|
-
"Edit an existing knowledge entry by id. Use to correct a saved fact or refine its wording. Only the fields you pass are changed; others are left alone. Call
|
|
21923
|
+
"knowledge_update",
|
|
21924
|
+
"Edit an existing knowledge entry by id. Use to correct a saved fact or refine its wording. Only the fields you pass are changed; others are left alone. Call knowledge_list first if you need to find the target id.",
|
|
21908
21925
|
{
|
|
21909
|
-
id: external_exports.string().describe("Knowledge entry id (uuid) \u2014 from
|
|
21926
|
+
id: external_exports.string().describe("Knowledge entry id (uuid) \u2014 from knowledge_list or knowledge_add"),
|
|
21910
21927
|
title: external_exports.string().optional().describe("New title (max 200 chars). Regenerates the slug."),
|
|
21911
21928
|
content: external_exports.string().optional().describe("Replacement content for the entry"),
|
|
21912
21929
|
is_active: external_exports.boolean().optional().describe("Set false to soft-disable without deleting")
|
|
@@ -21914,7 +21931,7 @@ server.tool(
|
|
|
21914
21931
|
async (params) => {
|
|
21915
21932
|
if (params.title === void 0 && params.content === void 0 && params.is_active === void 0) {
|
|
21916
21933
|
return {
|
|
21917
|
-
content: [{ type: "text", text: "Error:
|
|
21934
|
+
content: [{ type: "text", text: "Error: knowledge_update needs at least one of title, content, or is_active." }],
|
|
21918
21935
|
isError: true
|
|
21919
21936
|
};
|
|
21920
21937
|
}
|
|
@@ -21940,8 +21957,8 @@ server.tool(
|
|
|
21940
21957
|
}
|
|
21941
21958
|
);
|
|
21942
21959
|
server.tool(
|
|
21943
|
-
"
|
|
21944
|
-
"Remove a knowledge entry permanently. Prefer
|
|
21960
|
+
"knowledge_delete",
|
|
21961
|
+
"Remove a knowledge entry permanently. Prefer knowledge_update with is_active=false for temporary hides; use delete only when the fact was wrong or no longer applies.",
|
|
21945
21962
|
{
|
|
21946
21963
|
id: external_exports.string().describe("Knowledge entry id (uuid) to delete")
|
|
21947
21964
|
},
|
|
@@ -21961,8 +21978,8 @@ server.tool(
|
|
|
21961
21978
|
}
|
|
21962
21979
|
);
|
|
21963
21980
|
server.tool(
|
|
21964
|
-
"
|
|
21965
|
-
`List the plugins currently installed on this agent, with their current typed context values and a preview of any freeform overrides. Use this when the user asks "what plugins do I have?", "show me the plugins", "what is the Coding plugin configured with?", or before calling
|
|
21981
|
+
"plugin_list",
|
|
21982
|
+
`List the plugins currently installed on this agent, with their current typed context values and a preview of any freeform overrides. Use this when the user asks "what plugins do I have?", "show me the plugins", "what is the Coding plugin configured with?", or before calling plugin_improve to see what fields exist and what they're set to.`,
|
|
21966
21983
|
{},
|
|
21967
21984
|
async () => {
|
|
21968
21985
|
const data = await apiPost("/host/list-plugins", {
|
|
@@ -21994,12 +22011,12 @@ server.tool(
|
|
|
21994
22011
|
}
|
|
21995
22012
|
lines.push("");
|
|
21996
22013
|
}
|
|
21997
|
-
lines.push("To update any plugin's behavior, use the `
|
|
22014
|
+
lines.push("To update any plugin's behavior, use the `plugin_improve` tool with the user's feedback.");
|
|
21998
22015
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
21999
22016
|
}
|
|
22000
22017
|
);
|
|
22001
22018
|
server.tool(
|
|
22002
|
-
"
|
|
22019
|
+
"plugin_improve",
|
|
22003
22020
|
// Description leads with the user phrasings the agent should match against,
|
|
22004
22021
|
// then explains the safety rule. Order matters — Claude\'s tool selection
|
|
22005
22022
|
// weights the first line of a description heavily.
|
|
@@ -22055,7 +22072,7 @@ server.tool(
|
|
|
22055
22072
|
if (!data.applied) {
|
|
22056
22073
|
lines.push("");
|
|
22057
22074
|
lines.push("---");
|
|
22058
|
-
lines.push("Show this diff to the user. If they confirm, call `
|
|
22075
|
+
lines.push("Show this diff to the user. If they confirm, call `plugin_improve` again with `auto_apply: true` and the same arguments to apply.");
|
|
22059
22076
|
} else {
|
|
22060
22077
|
lines.push("");
|
|
22061
22078
|
lines.push("Update applied. The manager will re-render the plugin's SKILL.md files on the next refresh cycle.");
|
|
@@ -22073,7 +22090,7 @@ var WidgetDefSchema = external_exports.object({
|
|
|
22073
22090
|
refresh_cron: external_exports.string().optional().describe('Optional per-widget cron override (e.g. "0 6 * * *" for 6am daily).')
|
|
22074
22091
|
});
|
|
22075
22092
|
server.tool(
|
|
22076
|
-
"
|
|
22093
|
+
"dashboards_list",
|
|
22077
22094
|
'List dashboards visible to your team. Use to answer "what dashboards exist", "show me the dashboards I built", or before authoring a new one to avoid duplicating an existing slug.',
|
|
22078
22095
|
{
|
|
22079
22096
|
status: external_exports.enum(["draft", "active", "archived"]).optional().describe("Filter by status. Defaults to 'active'.")
|
|
@@ -22095,8 +22112,8 @@ ${lines.join("\n")}` }] };
|
|
|
22095
22112
|
}
|
|
22096
22113
|
);
|
|
22097
22114
|
server.tool(
|
|
22098
|
-
"
|
|
22099
|
-
"Get full metadata for one dashboard by slug \u2014 title, description, scope, status, widget list, last refresh per widget. Use when investigating a specific dashboard or before editing it via
|
|
22115
|
+
"dashboards_show",
|
|
22116
|
+
"Get full metadata for one dashboard by slug \u2014 title, description, scope, status, widget list, last refresh per widget. Use when investigating a specific dashboard or before editing it via dashboards_upsert.",
|
|
22100
22117
|
{
|
|
22101
22118
|
slug: external_exports.string().describe("Dashboard slug, e.g. 'finance-overview'.")
|
|
22102
22119
|
},
|
|
@@ -22128,7 +22145,7 @@ URL: ${url}` : "",
|
|
|
22128
22145
|
}
|
|
22129
22146
|
);
|
|
22130
22147
|
server.tool(
|
|
22131
|
-
"
|
|
22148
|
+
"dashboards_upsert",
|
|
22132
22149
|
// The description leads with the user phrasings the agent should match
|
|
22133
22150
|
// against AND the explicit forbidden alternatives. Tool selection weights
|
|
22134
22151
|
// the first sentence heavily, so we burn it on the right behavior.
|
|
@@ -22168,8 +22185,8 @@ URL: ${url}
|
|
|
22168
22185
|
}
|
|
22169
22186
|
);
|
|
22170
22187
|
server.tool(
|
|
22171
|
-
"
|
|
22172
|
-
"Mark widgets on a dashboard as needing refresh. Use this when authoring a new dashboard (to populate the first snapshot) or when you want widgets to update on the next
|
|
22188
|
+
"dashboards_request_refresh",
|
|
22189
|
+
"Mark widgets on a dashboard as needing refresh. Use this when authoring a new dashboard (to populate the first snapshot) or when you want widgets to update on the next dashboards_pending_refreshes call. Pass widget_id to flag just one widget; omit to flag every widget.",
|
|
22173
22190
|
{
|
|
22174
22191
|
slug: external_exports.string(),
|
|
22175
22192
|
widget_id: external_exports.string().optional().describe("Optional. Omit to flag all widgets on the dashboard."),
|
|
@@ -22189,8 +22206,8 @@ server.tool(
|
|
|
22189
22206
|
}
|
|
22190
22207
|
);
|
|
22191
22208
|
server.tool(
|
|
22192
|
-
"
|
|
22193
|
-
"Return widgets that need refresh \u2014 by default ONLY those flagged pending (user clicked \u21BB in the iframe, or someone called request_refresh). Pass slug=<dashboard slug> to instead get every widget on that dashboard so you can proactively refresh after authoring or when the user asks 'update the X dashboard'. Pass include_all=true with no slug to get every flagged-or-not widget across all your dashboards. Each entry: {slug, widget_id, kind, prompt, schema, requested_at}. Loop over them, read the prompt, gather data with your other tools, match the schema, and call
|
|
22209
|
+
"dashboards_pending_refreshes",
|
|
22210
|
+
"Return widgets that need refresh \u2014 by default ONLY those flagged pending (user clicked \u21BB in the iframe, or someone called request_refresh). Pass slug=<dashboard slug> to instead get every widget on that dashboard so you can proactively refresh after authoring or when the user asks 'update the X dashboard'. Pass include_all=true with no slug to get every flagged-or-not widget across all your dashboards. Each entry: {slug, widget_id, kind, prompt, schema, requested_at}. Loop over them, read the prompt, gather data with your other tools, match the schema, and call dashboards_persist_widget for each.",
|
|
22194
22211
|
{
|
|
22195
22212
|
slug: external_exports.string().optional().describe("Restrict to one dashboard by slug. When set, returns every widget on that dashboard \u2014 flagged or not \u2014 so you can refresh the whole thing without calling request_refresh first."),
|
|
22196
22213
|
include_all: external_exports.boolean().optional().describe("When true (and no slug), returns every widget on every dashboard you own \u2014 flagged or not. Use sparingly; one refresh = one LLM call.")
|
|
@@ -22209,7 +22226,7 @@ server.tool(
|
|
|
22209
22226
|
}
|
|
22210
22227
|
);
|
|
22211
22228
|
server.tool(
|
|
22212
|
-
"
|
|
22229
|
+
"dashboards_persist_widget",
|
|
22213
22230
|
"Persist refreshed data for one widget. The platform validates `data` against the widget's stored JSON Schema server-side \u2014 invalid output is rejected. Call this once per widget after gathering data with your tools.",
|
|
22214
22231
|
{
|
|
22215
22232
|
slug: external_exports.string(),
|
|
@@ -22238,7 +22255,8 @@ function statusLabel(status) {
|
|
|
22238
22255
|
backlog: "Backlog",
|
|
22239
22256
|
todo: "To Do",
|
|
22240
22257
|
in_progress: "In Progress",
|
|
22241
|
-
done: "Done"
|
|
22258
|
+
done: "Done",
|
|
22259
|
+
failed: "Failed"
|
|
22242
22260
|
};
|
|
22243
22261
|
return labels[status] ?? status;
|
|
22244
22262
|
}
|
|
@@ -22279,32 +22297,50 @@ async function forwardToolCall(toolName, args) {
|
|
|
22279
22297
|
FORWARD_TOOL_CALL_TIMEOUT_MS
|
|
22280
22298
|
);
|
|
22281
22299
|
}
|
|
22300
|
+
var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
22301
|
+
"kanban_list",
|
|
22302
|
+
"kanban_add",
|
|
22303
|
+
"kanban_move",
|
|
22304
|
+
"kanban_update",
|
|
22305
|
+
"kanban_progress",
|
|
22306
|
+
"kanban_done",
|
|
22307
|
+
"status_standup",
|
|
22308
|
+
"status_update",
|
|
22309
|
+
"drift_report",
|
|
22310
|
+
"token_refresh",
|
|
22311
|
+
"acpx_prompt",
|
|
22312
|
+
"acpx_exec",
|
|
22313
|
+
"acpx_spawn",
|
|
22314
|
+
"acpx_cancel",
|
|
22315
|
+
"acpx_status",
|
|
22316
|
+
"acpx_close",
|
|
22317
|
+
"schedule_list",
|
|
22318
|
+
"schedule_create",
|
|
22319
|
+
"schedule_delete",
|
|
22320
|
+
"schedule_update",
|
|
22321
|
+
"knowledge_list",
|
|
22322
|
+
"knowledge_add",
|
|
22323
|
+
"knowledge_update",
|
|
22324
|
+
"knowledge_delete",
|
|
22325
|
+
"plugin_list",
|
|
22326
|
+
"plugin_improve",
|
|
22327
|
+
"dashboards_list",
|
|
22328
|
+
"dashboards_show",
|
|
22329
|
+
"dashboards_upsert",
|
|
22330
|
+
"dashboards_request_refresh",
|
|
22331
|
+
"dashboards_pending_refreshes",
|
|
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).
|
|
22338
|
+
"projects_list",
|
|
22339
|
+
"projects_get"
|
|
22340
|
+
]);
|
|
22282
22341
|
async function registerForwardedApiTools() {
|
|
22283
22342
|
const apiTools = await discoverApiTools();
|
|
22284
|
-
const localToolNames =
|
|
22285
|
-
"kanban.list",
|
|
22286
|
-
"kanban.add",
|
|
22287
|
-
"kanban.move",
|
|
22288
|
-
"kanban.update",
|
|
22289
|
-
"kanban.progress",
|
|
22290
|
-
"kanban.done",
|
|
22291
|
-
"status.standup",
|
|
22292
|
-
"status.update",
|
|
22293
|
-
"drift.report",
|
|
22294
|
-
"token.refresh",
|
|
22295
|
-
"acpx.prompt",
|
|
22296
|
-
"acpx.exec",
|
|
22297
|
-
"acpx.spawn",
|
|
22298
|
-
"acpx.cancel",
|
|
22299
|
-
"knowledge.list",
|
|
22300
|
-
"knowledge.search",
|
|
22301
|
-
"knowledge.read",
|
|
22302
|
-
"knowledge.add",
|
|
22303
|
-
"knowledge.update",
|
|
22304
|
-
"knowledge.delete",
|
|
22305
|
-
"plugin.list",
|
|
22306
|
-
"plugin.improve"
|
|
22307
|
-
]);
|
|
22343
|
+
const localToolNames = LOCAL_TOOL_NAMES;
|
|
22308
22344
|
let registered = 0;
|
|
22309
22345
|
let skipped = 0;
|
|
22310
22346
|
for (const tool of apiTools) {
|
|
@@ -22334,76 +22370,135 @@ async function registerForwardedApiTools() {
|
|
|
22334
22370
|
}
|
|
22335
22371
|
return { registered, skipped };
|
|
22336
22372
|
}
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
publisher: external_exports.string().optional().describe('Filter by publisher (e.g. "here-now")'),
|
|
22342
|
-
kind: external_exports.enum(["mockup", "deck", "site", "app", "other"]).optional().describe("Filter by artefact kind"),
|
|
22343
|
-
limit: external_exports.number().int().min(1).max(100).optional().describe("Maximum projects to return (default 50, max 100)")
|
|
22344
|
-
},
|
|
22345
|
-
async (params) => {
|
|
22346
|
-
const data = await apiPost("/host/my-published-projects", {
|
|
22373
|
+
async function listPublishedArtefactsText(params) {
|
|
22374
|
+
const data = await apiPost(
|
|
22375
|
+
"/host/my-published-artefacts",
|
|
22376
|
+
{
|
|
22347
22377
|
agent_id: AGT_AGENT_ID,
|
|
22348
22378
|
publisher: params.publisher,
|
|
22349
22379
|
kind: params.kind,
|
|
22350
22380
|
limit: params.limit
|
|
22351
|
-
});
|
|
22352
|
-
if (!data.projects.length) {
|
|
22353
|
-
return { content: [{ type: "text", text: "No published projects yet." }] };
|
|
22354
22381
|
}
|
|
22355
|
-
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
|
|
22359
|
-
|
|
22360
|
-
|
|
22361
|
-
|
|
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. "agt-live")'),
|
|
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
|
+
})
|
|
22362
22432
|
);
|
|
22363
22433
|
server.tool(
|
|
22364
|
-
"
|
|
22365
|
-
"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.",
|
|
22366
22436
|
{
|
|
22367
|
-
|
|
22437
|
+
artefact_id: external_exports.string().uuid().describe("The artefact id returned by artefacts_list")
|
|
22368
22438
|
},
|
|
22369
|
-
async (params) => {
|
|
22370
|
-
|
|
22371
|
-
|
|
22372
|
-
});
|
|
22373
|
-
const p = data.project;
|
|
22374
|
-
const header = [
|
|
22375
|
-
`Project: ${p.title ?? "(untitled)"} [${p.kind}]`,
|
|
22376
|
-
`Publisher: ${p.publisher} (${p.mode})`,
|
|
22377
|
-
`Live URL: ${p.live_url}`,
|
|
22378
|
-
p.claim_url ? `Claim URL: ${p.claim_url}` : null,
|
|
22379
|
-
`Published: ${p.published_at}`,
|
|
22380
|
-
p.expires_at ? `Expires: ${p.expires_at}` : null,
|
|
22381
|
-
`Last modified: ${p.last_modified_at}`,
|
|
22382
|
-
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)"
|
|
22383
|
-
].filter((s) => s !== null).join("\n");
|
|
22384
|
-
return { content: [{ type: "text", text: header }] };
|
|
22385
|
-
}
|
|
22439
|
+
async (params) => ({
|
|
22440
|
+
content: [{ type: "text", text: await getPublishedArtefactText(params.artefact_id) }]
|
|
22441
|
+
})
|
|
22386
22442
|
);
|
|
22387
22443
|
server.tool(
|
|
22388
|
-
"
|
|
22389
|
-
"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.",
|
|
22390
22446
|
{
|
|
22391
|
-
|
|
22447
|
+
artefact_id: external_exports.string().uuid().describe("The artefact id returned by artefacts_list"),
|
|
22392
22448
|
offset: external_exports.number().int().min(0).describe("Byte offset into the source HTML to start from"),
|
|
22393
22449
|
limit: external_exports.number().int().min(1).max(65536).optional().describe("Max bytes to return (default 32KB, max 64KB)")
|
|
22394
22450
|
},
|
|
22395
|
-
async (params) => {
|
|
22396
|
-
|
|
22397
|
-
|
|
22398
|
-
|
|
22399
|
-
|
|
22400
|
-
|
|
22401
|
-
|
|
22402
|
-
|
|
22403
|
-
|
|
22404
|
-
|
|
22405
|
-
|
|
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.";
|
|
22406
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
|
+
})
|
|
22407
22502
|
);
|
|
22408
22503
|
async function main() {
|
|
22409
22504
|
try {
|