@integrity-labs/agt-cli 0.10.1 → 0.10.3
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/bin/agt.js +237 -3
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-N7TRKQMT.js → chunk-6YGOQRAR.js} +658 -25
- package/dist/chunk-6YGOQRAR.js.map +1 -0
- package/dist/lib/manager-worker.js +406 -100
- package/dist/lib/manager-worker.js.map +1 -1
- package/mcp/direct-chat-channel.js +13985 -0
- package/mcp/index.js +181 -0
- package/mcp/slack-channel.js +30 -3
- package/package.json +2 -2
- package/dist/chunk-N7TRKQMT.js.map +0 -1
package/mcp/index.js
CHANGED
|
@@ -21624,6 +21624,187 @@ server.tool(
|
|
|
21624
21624
|
};
|
|
21625
21625
|
}
|
|
21626
21626
|
);
|
|
21627
|
+
server.tool(
|
|
21628
|
+
"schedule.update",
|
|
21629
|
+
// Lead with user phrasings the agent should match against, then explain
|
|
21630
|
+
// the two modes. Order matters for tool selection.
|
|
21631
|
+
'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". Two modes: (1) DIRECT FIELD UPDATES \u2014 set cron_expression/interval/timezone/channel/enabled/name/prompt to change those values directly. (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.',
|
|
21632
|
+
{
|
|
21633
|
+
task_id: external_exports.string().describe("The task ID to update (from schedule.list)"),
|
|
21634
|
+
// Direct-field mode
|
|
21635
|
+
name: external_exports.string().optional().describe("New task display name"),
|
|
21636
|
+
schedule_kind: external_exports.enum(["cron", "every", "at"]).optional().describe(
|
|
21637
|
+
"Schedule type. If changing, must also provide the matching expression field."
|
|
21638
|
+
),
|
|
21639
|
+
schedule_expr: external_exports.string().optional().describe(
|
|
21640
|
+
'Cron expression (e.g. "0 9 * * 1-5") when schedule_kind is cron'
|
|
21641
|
+
),
|
|
21642
|
+
schedule_every: external_exports.string().optional().describe(
|
|
21643
|
+
'Interval string (e.g. "30m", "2h") when schedule_kind is every'
|
|
21644
|
+
),
|
|
21645
|
+
schedule_at: external_exports.string().optional().describe(
|
|
21646
|
+
"ISO 8601 timestamp when schedule_kind is at (one-off task)"
|
|
21647
|
+
),
|
|
21648
|
+
timezone: external_exports.string().optional().describe('IANA timezone (e.g. "America/Los_Angeles")'),
|
|
21649
|
+
prompt: external_exports.string().optional().describe(
|
|
21650
|
+
"Raw new prompt text. Use description_feedback instead for LLM-assisted rewrites."
|
|
21651
|
+
),
|
|
21652
|
+
delivery_channel: external_exports.string().optional().describe(
|
|
21653
|
+
'Where results are delivered (e.g. "slack", "telegram", "email")'
|
|
21654
|
+
),
|
|
21655
|
+
delivery_to: external_exports.string().optional().describe(
|
|
21656
|
+
"Channel/chat/email identifier for delivery"
|
|
21657
|
+
),
|
|
21658
|
+
enabled: external_exports.boolean().optional().describe(
|
|
21659
|
+
"Set to false to pause the schedule without deleting it"
|
|
21660
|
+
),
|
|
21661
|
+
// LLM rewrite mode
|
|
21662
|
+
description_feedback: external_exports.string().optional().describe(
|
|
21663
|
+
'Natural-language feedback about how to rewrite the task prompt. Examples: "make this more concise", "add a section covering the team backlog", "focus on blockers instead of progress". Triggers an LLM rewrite \u2014 mutually exclusive with direct prompt updates.'
|
|
21664
|
+
),
|
|
21665
|
+
auto_apply: external_exports.boolean().optional().describe(
|
|
21666
|
+
"For description_feedback only. Default false (preview the rewrite, then call again with auto_apply: true to commit)."
|
|
21667
|
+
)
|
|
21668
|
+
},
|
|
21669
|
+
async (params) => {
|
|
21670
|
+
const data = await apiPost("/host/schedules/update", {
|
|
21671
|
+
agent_id: AGT_AGENT_ID,
|
|
21672
|
+
...params
|
|
21673
|
+
});
|
|
21674
|
+
if (params.description_feedback) {
|
|
21675
|
+
const lines = [];
|
|
21676
|
+
lines.push(data.applied ? "\u2705 Applied schedule prompt rewrite" : "\u{1F4CB} Proposed schedule prompt rewrite (preview)");
|
|
21677
|
+
lines.push("");
|
|
21678
|
+
if (data.proposed) {
|
|
21679
|
+
lines.push(`Rationale: ${data.proposed.rationale}`);
|
|
21680
|
+
lines.push("");
|
|
21681
|
+
lines.push("## Before");
|
|
21682
|
+
lines.push("```");
|
|
21683
|
+
lines.push(data.current?.prompt ?? "(empty)");
|
|
21684
|
+
lines.push("```");
|
|
21685
|
+
lines.push("## After");
|
|
21686
|
+
lines.push("```");
|
|
21687
|
+
lines.push(data.proposed.new_prompt);
|
|
21688
|
+
lines.push("```");
|
|
21689
|
+
}
|
|
21690
|
+
if (!data.applied) {
|
|
21691
|
+
lines.push("");
|
|
21692
|
+
lines.push("---");
|
|
21693
|
+
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.");
|
|
21694
|
+
}
|
|
21695
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
21696
|
+
}
|
|
21697
|
+
const updatedFields = [];
|
|
21698
|
+
for (const key of ["name", "schedule_kind", "schedule_expr", "schedule_every", "schedule_at", "timezone", "prompt", "delivery_channel", "delivery_to", "enabled"]) {
|
|
21699
|
+
if (params[key] !== void 0) updatedFields.push(key);
|
|
21700
|
+
}
|
|
21701
|
+
const summary = `Updated scheduled task ${params.task_id} (${updatedFields.join(", ") || "no changes"})`;
|
|
21702
|
+
return { content: [{ type: "text", text: summary }] };
|
|
21703
|
+
}
|
|
21704
|
+
);
|
|
21705
|
+
server.tool(
|
|
21706
|
+
"plugin.list",
|
|
21707
|
+
`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.`,
|
|
21708
|
+
{},
|
|
21709
|
+
async () => {
|
|
21710
|
+
const data = await apiPost("/host/list-plugins", {
|
|
21711
|
+
agent_id: AGT_AGENT_ID
|
|
21712
|
+
});
|
|
21713
|
+
if (!data.plugins.length) {
|
|
21714
|
+
return { content: [{ type: "text", text: "No plugins installed on this agent." }] };
|
|
21715
|
+
}
|
|
21716
|
+
const lines = [];
|
|
21717
|
+
lines.push(`## Installed Plugins (${data.plugins.length})
|
|
21718
|
+
`);
|
|
21719
|
+
for (const p of data.plugins) {
|
|
21720
|
+
lines.push(`### ${p.plugin_name} \`${p.plugin_slug}\` (v${p.version})`);
|
|
21721
|
+
if (p.description) lines.push(p.description);
|
|
21722
|
+
lines.push(`- Skills: ${p.skill_count}`);
|
|
21723
|
+
if (p.has_schema && p.context_field_count > 0) {
|
|
21724
|
+
lines.push(`- Context values:`);
|
|
21725
|
+
for (const [key, val] of Object.entries(p.current_values)) {
|
|
21726
|
+
lines.push(` - \`${key}\`: ${JSON.stringify(val)}`);
|
|
21727
|
+
}
|
|
21728
|
+
} else if (p.has_schema) {
|
|
21729
|
+
lines.push(`- Context: schema declared but no values set (all defaults)`);
|
|
21730
|
+
} else {
|
|
21731
|
+
lines.push(`- Context: no typed schema (freeform overrides only)`);
|
|
21732
|
+
}
|
|
21733
|
+
if (p.has_overrides) {
|
|
21734
|
+
lines.push(`- Freeform overrides (preview):`);
|
|
21735
|
+
lines.push(` > ${p.overrides_preview.replace(/\n/g, "\n > ")}`);
|
|
21736
|
+
}
|
|
21737
|
+
lines.push("");
|
|
21738
|
+
}
|
|
21739
|
+
lines.push("To update any plugin's behavior, use the `plugin.improve` tool with the user's feedback.");
|
|
21740
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
21741
|
+
}
|
|
21742
|
+
);
|
|
21743
|
+
server.tool(
|
|
21744
|
+
"plugin.improve",
|
|
21745
|
+
// Description leads with the user phrasings the agent should match against,
|
|
21746
|
+
// then explains the safety rule. Order matters — Claude\'s tool selection
|
|
21747
|
+
// weights the first line of a description heavily.
|
|
21748
|
+
`Update, edit, or add a rule to an installed plugin (e.g. the Coding plugin, the Knowledge Base plugin, the Slack plugin). USE THIS TOOL when the user says any of: "update the X plugin", "add a rule to plugin Y", "tell the X plugin not to do Z", "change the X plugin so it does Y", "the Coding plugin should always/never...", "remember this for the X plugin". This is the ONLY correct way to modify a plugin's behavior. NEVER edit SKILL.md files under .claude/skills/plugin-* directly \u2014 those files are derived from the platform database and your edits will be silently overwritten on the next manager refresh. The platform calls an LLM to translate the user's request into a structured update of the plugin's typed context fields and/or freeform overrides text, then returns a diff for you to show the user. Default flow is preview-then-apply: call once to get the proposed diff, show it to the user, then call again with auto_apply=true if they confirm. Only works for plugins that are actually installed on this agent.`,
|
|
21749
|
+
{
|
|
21750
|
+
plugin_slug: external_exports.string().optional().describe('Plugin slug to improve (e.g. "claude-code-github"). Either this or plugin_id is required.'),
|
|
21751
|
+
plugin_id: external_exports.string().optional().describe("Plugin UUID. Either this or plugin_slug is required."),
|
|
21752
|
+
feedback: external_exports.string().min(1).describe("The user's feedback in natural language. What should the plugin do differently?"),
|
|
21753
|
+
transcript_snippet: external_exports.string().optional().describe("Optional short transcript snippet showing the behavior the user flagged. Helps the LLM understand context. Max 2000 chars."),
|
|
21754
|
+
auto_apply: external_exports.boolean().optional().describe("If true, apply the proposed update immediately without preview. Default false (preview-then-apply). Only set to true after the user has confirmed the proposed diff.")
|
|
21755
|
+
},
|
|
21756
|
+
async (params) => {
|
|
21757
|
+
if (!params.plugin_slug && !params.plugin_id) {
|
|
21758
|
+
return {
|
|
21759
|
+
content: [{ type: "text", text: "Error: either plugin_slug or plugin_id is required." }]
|
|
21760
|
+
};
|
|
21761
|
+
}
|
|
21762
|
+
const data = await apiPost("/host/improve-plugin", {
|
|
21763
|
+
agent_id: AGT_AGENT_ID,
|
|
21764
|
+
plugin_slug: params.plugin_slug,
|
|
21765
|
+
plugin_id: params.plugin_id,
|
|
21766
|
+
feedback: params.feedback,
|
|
21767
|
+
transcript_snippet: params.transcript_snippet,
|
|
21768
|
+
auto_apply: params.auto_apply ?? false
|
|
21769
|
+
});
|
|
21770
|
+
const lines = [];
|
|
21771
|
+
lines.push(data.applied ? "\u2705 Applied plugin context update" : "\u{1F4CB} Proposed plugin context update (preview)");
|
|
21772
|
+
lines.push("");
|
|
21773
|
+
lines.push(`Rationale: ${data.proposed.rationale}`);
|
|
21774
|
+
if (data.proposed.changed_fields.length > 0) {
|
|
21775
|
+
lines.push("");
|
|
21776
|
+
lines.push("## Typed field changes");
|
|
21777
|
+
for (const field of data.proposed.changed_fields) {
|
|
21778
|
+
const before = JSON.stringify(data.current.values[field] ?? null);
|
|
21779
|
+
const after = JSON.stringify(data.proposed.values[field] ?? null);
|
|
21780
|
+
lines.push(`- \`${field}\`: ${before} \u2192 ${after}`);
|
|
21781
|
+
}
|
|
21782
|
+
}
|
|
21783
|
+
if (data.proposed.appended_to_overrides) {
|
|
21784
|
+
lines.push("");
|
|
21785
|
+
lines.push("## Overrides change");
|
|
21786
|
+
const before = data.current.overrides || "(empty)";
|
|
21787
|
+
const after = data.proposed.overrides || "(empty)";
|
|
21788
|
+
lines.push("Before:");
|
|
21789
|
+
lines.push("```");
|
|
21790
|
+
lines.push(before);
|
|
21791
|
+
lines.push("```");
|
|
21792
|
+
lines.push("After:");
|
|
21793
|
+
lines.push("```");
|
|
21794
|
+
lines.push(after);
|
|
21795
|
+
lines.push("```");
|
|
21796
|
+
}
|
|
21797
|
+
if (!data.applied) {
|
|
21798
|
+
lines.push("");
|
|
21799
|
+
lines.push("---");
|
|
21800
|
+
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.");
|
|
21801
|
+
} else {
|
|
21802
|
+
lines.push("");
|
|
21803
|
+
lines.push("Update applied. The manager will re-render the plugin's SKILL.md files on the next refresh cycle.");
|
|
21804
|
+
}
|
|
21805
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
21806
|
+
}
|
|
21807
|
+
);
|
|
21627
21808
|
function groupByStatus(items) {
|
|
21628
21809
|
const groups = {};
|
|
21629
21810
|
for (const item of items) {
|
package/mcp/slack-channel.js
CHANGED
|
@@ -13867,6 +13867,8 @@ var APP_TOKEN = process.env.SLACK_APP_TOKEN;
|
|
|
13867
13867
|
var ALLOWED_USERS = new Set(
|
|
13868
13868
|
(process.env.SLACK_ALLOWED_USERS ?? "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
13869
13869
|
);
|
|
13870
|
+
var THREAD_AUTO_FOLLOW = process.env.SLACK_THREAD_AUTO_FOLLOW ?? "off";
|
|
13871
|
+
var trackedThreads = /* @__PURE__ */ new Map();
|
|
13870
13872
|
if (!BOT_TOKEN || !APP_TOKEN) {
|
|
13871
13873
|
console.error(
|
|
13872
13874
|
"slack-channel: Missing SLACK_BOT_TOKEN or SLACK_APP_TOKEN. Cannot start."
|
|
@@ -13885,7 +13887,10 @@ var mcp = new Server(
|
|
|
13885
13887
|
"Reply using the slack.reply tool, passing channel and thread_ts from the tag.",
|
|
13886
13888
|
"For threaded replies, always include thread_ts so the response appears in the same thread.",
|
|
13887
13889
|
"When someone @mentions you in a channel, respond helpfully in that thread.",
|
|
13888
|
-
"For DMs, respond directly."
|
|
13890
|
+
"For DMs, respond directly.",
|
|
13891
|
+
"Messages with auto_followed=true are from threads you previously participated in.",
|
|
13892
|
+
"For auto-followed messages, use relevance judgment: only reply if you have something useful to add.",
|
|
13893
|
+
"Do NOT reply to every auto-followed message \u2014 skip if the conversation has moved on, the message is directed at someone else, or your input would not add value."
|
|
13889
13894
|
].join(" ")
|
|
13890
13895
|
}
|
|
13891
13896
|
);
|
|
@@ -13949,6 +13954,14 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
13949
13954
|
isError: true
|
|
13950
13955
|
};
|
|
13951
13956
|
}
|
|
13957
|
+
if (THREAD_AUTO_FOLLOW !== "off") {
|
|
13958
|
+
const trackKey = thread_ts ?? data.ts ?? "";
|
|
13959
|
+
if (trackKey) {
|
|
13960
|
+
if (!trackedThreads.has(trackKey)) {
|
|
13961
|
+
trackedThreads.set(trackKey, thread_ts ? "mentioned" : "started");
|
|
13962
|
+
}
|
|
13963
|
+
}
|
|
13964
|
+
}
|
|
13952
13965
|
return { content: [{ type: "text", text: "sent" }] };
|
|
13953
13966
|
} catch (err) {
|
|
13954
13967
|
return {
|
|
@@ -14024,7 +14037,19 @@ async function connectSocketMode() {
|
|
|
14024
14037
|
const evt = msg.payload.event;
|
|
14025
14038
|
if (evt.user === botUserId) return;
|
|
14026
14039
|
if (evt.type !== "app_mention" && evt.type !== "message") return;
|
|
14027
|
-
|
|
14040
|
+
const isDirectMessage = evt.channel?.startsWith("D");
|
|
14041
|
+
const isThreadReply = !!evt.thread_ts && evt.thread_ts !== evt.ts;
|
|
14042
|
+
const threadKey = evt.thread_ts ?? evt.ts ?? "";
|
|
14043
|
+
if (evt.type === "app_mention" && threadKey) {
|
|
14044
|
+
trackedThreads.set(threadKey, trackedThreads.get(threadKey) ?? "mentioned");
|
|
14045
|
+
}
|
|
14046
|
+
if (evt.type === "message" && evt.channel && !isDirectMessage) {
|
|
14047
|
+
if (THREAD_AUTO_FOLLOW === "off") return;
|
|
14048
|
+
if (!isThreadReply) return;
|
|
14049
|
+
const threadInvolvement = trackedThreads.get(threadKey);
|
|
14050
|
+
if (!threadInvolvement) return;
|
|
14051
|
+
if (THREAD_AUTO_FOLLOW === "started" && threadInvolvement !== "started") return;
|
|
14052
|
+
}
|
|
14028
14053
|
if (ALLOWED_USERS.size > 0 && evt.user && !ALLOWED_USERS.has(evt.user)) return;
|
|
14029
14054
|
const text = evt.text ?? "";
|
|
14030
14055
|
const channel = evt.channel ?? "";
|
|
@@ -14042,6 +14067,7 @@ async function connectSocketMode() {
|
|
|
14042
14067
|
}).catch(() => {
|
|
14043
14068
|
});
|
|
14044
14069
|
}
|
|
14070
|
+
const isAutoFollowed = evt.type === "message" && isThreadReply && trackedThreads.has(threadKey);
|
|
14045
14071
|
await mcp.notification({
|
|
14046
14072
|
method: "notifications/claude/channel",
|
|
14047
14073
|
params: {
|
|
@@ -14050,7 +14076,8 @@ async function connectSocketMode() {
|
|
|
14050
14076
|
user,
|
|
14051
14077
|
channel,
|
|
14052
14078
|
thread_ts: threadTs,
|
|
14053
|
-
event_type: evt.type
|
|
14079
|
+
event_type: evt.type,
|
|
14080
|
+
...isAutoFollowed ? { auto_followed: true } : {}
|
|
14054
14081
|
}
|
|
14055
14082
|
}
|
|
14056
14083
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integrity-labs/agt-cli",
|
|
3
|
-
"version": "0.10.
|
|
4
|
-
"description": "Augmented CLI — agent provisioning and management",
|
|
3
|
+
"version": "0.10.3",
|
|
4
|
+
"description": "Augmented Team CLI — agent provisioning and management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"agt": "./dist/bin/agt.js"
|