@integrity-labs/agt-cli 0.27.7-test.6 → 0.27.8-test.10

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.
@@ -13861,127 +13861,6 @@ var StdioServerTransport = class {
13861
13861
  }
13862
13862
  };
13863
13863
 
13864
- // src/direct-chat-progress.ts
13865
- var MODE_EMOJI = {
13866
- thinking: "\u{1F4AD}",
13867
- working: "\u{1F6E0}\uFE0F",
13868
- waiting: "\u23F3"
13869
- };
13870
- var TERMINAL_EMOJI = {
13871
- completed: "\u2705",
13872
- failed: "\u274C"
13873
- };
13874
- function formatWallClock(ms, timeZone) {
13875
- const fmt = new Intl.DateTimeFormat("en-GB", {
13876
- hour: "2-digit",
13877
- minute: "2-digit",
13878
- second: "2-digit",
13879
- hour12: false,
13880
- timeZone,
13881
- timeZoneName: "short"
13882
- });
13883
- const parts = fmt.formatToParts(new Date(ms));
13884
- const get = (t) => parts.find((p) => p.type === t)?.value ?? "";
13885
- return `${get("hour")}:${get("minute")}:${get("second")} ${get("timeZoneName")}`;
13886
- }
13887
- function renderProgressMarkdown(state) {
13888
- const lines = [];
13889
- if (state.terminal) {
13890
- const banner = state.terminal.kind === "completed" ? "Done" : "Failed";
13891
- lines.push(`${TERMINAL_EMOJI[state.terminal.kind]} **${banner}** \u2014 ${state.initialLabel}`);
13892
- if (state.terminal.message) lines.push(state.terminal.message);
13893
- lines.push(`_completed: ${formatWallClock(state.lastChangeAt)}_`);
13894
- return lines.join("\n");
13895
- }
13896
- lines.push(`${MODE_EMOJI[state.mode]} **Working on:** ${state.initialLabel}`);
13897
- if (state.stepNumber || state.stepLabel) {
13898
- const stepParts = [];
13899
- if (state.stepNumber) {
13900
- if (state.stepNumber.total != null) {
13901
- stepParts.push(`**Step ${state.stepNumber.current} of ${state.stepNumber.total}**`);
13902
- } else {
13903
- stepParts.push(`**Step ${state.stepNumber.current}**`);
13904
- }
13905
- }
13906
- if (state.stepLabel) stepParts.push(state.stepLabel);
13907
- lines.push(stepParts.join(": "));
13908
- }
13909
- if (state.detail) lines.push(`_${state.detail}_`);
13910
- lines.push(`_last update: ${formatWallClock(state.lastChangeAt)}_`);
13911
- return lines.join("\n");
13912
- }
13913
- var DirectChatApiError = class extends Error {
13914
- constructor(endpoint, apiError, status) {
13915
- super(`/host/${endpoint} failed: ${apiError} (status=${status})`);
13916
- this.endpoint = endpoint;
13917
- this.apiError = apiError;
13918
- this.status = status;
13919
- this.name = "DirectChatApiError";
13920
- }
13921
- };
13922
- function createDirectChatProgressFlush(opts) {
13923
- const fetchImpl = opts.fetchImpl ?? fetch;
13924
- const timeoutMs = opts.timeoutMs ?? 5e3;
13925
- let anchorMessageId = null;
13926
- async function apiCall(endpoint, body) {
13927
- const token = await opts.getAuthToken();
13928
- const controller = new AbortController();
13929
- const timer = setTimeout(() => controller.abort(), timeoutMs);
13930
- let response;
13931
- try {
13932
- response = await fetchImpl(`${opts.agtHost}/host/${endpoint}`, {
13933
- method: "POST",
13934
- headers: {
13935
- "Content-Type": "application/json",
13936
- Authorization: `Bearer ${token}`
13937
- },
13938
- body: JSON.stringify(body),
13939
- signal: controller.signal
13940
- });
13941
- } finally {
13942
- clearTimeout(timer);
13943
- }
13944
- const parsed = await response.json().catch(() => ({ ok: false, error: "invalid_json" }));
13945
- if (!response.ok || !parsed.ok) {
13946
- throw new DirectChatApiError(
13947
- endpoint,
13948
- parsed.error ?? `http ${response.status}`,
13949
- response.status
13950
- );
13951
- }
13952
- return parsed;
13953
- }
13954
- return async function flush(state) {
13955
- const content = renderProgressMarkdown(state);
13956
- if (anchorMessageId == null) {
13957
- const res = await apiCall("direct-chat/reply", {
13958
- agent_id: opts.agentId,
13959
- session_id: opts.sessionId,
13960
- content
13961
- });
13962
- if (res.message_id) {
13963
- anchorMessageId = res.message_id;
13964
- opts.onAnchorPosted?.(res.message_id);
13965
- }
13966
- return;
13967
- }
13968
- try {
13969
- await apiCall("direct-chat/update", {
13970
- agent_id: opts.agentId,
13971
- session_id: opts.sessionId,
13972
- message_id: anchorMessageId,
13973
- content
13974
- });
13975
- } catch (err) {
13976
- if (opts.onApiError && err instanceof DirectChatApiError) {
13977
- await opts.onApiError(err);
13978
- return;
13979
- }
13980
- throw err;
13981
- }
13982
- };
13983
- }
13984
-
13985
13864
  // src/inbound-context-client.ts
13986
13865
  var REQUEST_TIMEOUT_MS = 1e4;
13987
13866
  function createInboundContextClient(args) {
@@ -14051,323 +13930,6 @@ function createInboundContextClient(args) {
14051
13930
  };
14052
13931
  }
14053
13932
 
14054
- // src/progress-tools.ts
14055
- import { randomUUID } from "crypto";
14056
-
14057
- // src/progress-handle.ts
14058
- async function startProgressHandle(opts) {
14059
- const now = opts.now ?? (() => Date.now());
14060
- const setTimer = opts.setTimer ?? ((cb, ms) => setTimeout(cb, ms));
14061
- const clearTimer = opts.clearTimer ?? ((id) => clearTimeout(id));
14062
- const debounceMs = opts.debounceMs ?? 1e3;
14063
- const onPostTerminalUpdate = opts.onPostTerminalUpdate ?? defaultPostTerminalWarn;
14064
- const state = {
14065
- initialLabel: opts.initialLabel,
14066
- mode: opts.initialMode ?? "working",
14067
- lastChangeAt: now()
14068
- };
14069
- let lastFlushAt = 0;
14070
- let pendingTimer = null;
14071
- let inFlight = null;
14072
- let terminal = false;
14073
- async function doFlush() {
14074
- while (inFlight) await inFlight;
14075
- if (pendingTimer != null) {
14076
- clearTimer(pendingTimer);
14077
- pendingTimer = null;
14078
- }
14079
- lastFlushAt = now();
14080
- const promise = opts.flush(snapshotState());
14081
- inFlight = promise.then(
14082
- () => {
14083
- inFlight = null;
14084
- },
14085
- (err) => {
14086
- inFlight = null;
14087
- throw err;
14088
- }
14089
- );
14090
- await inFlight;
14091
- }
14092
- function snapshotState() {
14093
- return {
14094
- initialLabel: state.initialLabel,
14095
- mode: state.mode,
14096
- stepLabel: state.stepLabel,
14097
- stepNumber: state.stepNumber ? { ...state.stepNumber } : void 0,
14098
- detail: state.detail,
14099
- lastChangeAt: state.lastChangeAt,
14100
- terminal: state.terminal ? { ...state.terminal } : void 0
14101
- };
14102
- }
14103
- function applyUpdate(next) {
14104
- if (next.mode !== void 0) state.mode = next.mode;
14105
- if (next.stepLabel !== void 0) state.stepLabel = next.stepLabel;
14106
- if (next.stepNumber !== void 0) state.stepNumber = { ...next.stepNumber };
14107
- if (next.detail !== void 0) state.detail = next.detail;
14108
- state.lastChangeAt = now();
14109
- }
14110
- async function scheduleOrFlush() {
14111
- const elapsed = now() - lastFlushAt;
14112
- if (elapsed >= debounceMs) {
14113
- await doFlush();
14114
- return;
14115
- }
14116
- if (pendingTimer != null) return;
14117
- const remaining = debounceMs - elapsed;
14118
- pendingTimer = setTimer(() => {
14119
- pendingTimer = null;
14120
- void doFlush().catch(() => {
14121
- });
14122
- }, remaining);
14123
- }
14124
- lastFlushAt = now();
14125
- await opts.flush(snapshotState());
14126
- return {
14127
- snapshot: snapshotState,
14128
- async update(next) {
14129
- if (terminal) {
14130
- const peeked = snapshotState();
14131
- Object.assign(peeked, {
14132
- mode: next.mode ?? peeked.mode,
14133
- stepLabel: next.stepLabel ?? peeked.stepLabel,
14134
- stepNumber: next.stepNumber ?? peeked.stepNumber,
14135
- detail: next.detail ?? peeked.detail
14136
- });
14137
- try {
14138
- onPostTerminalUpdate(peeked);
14139
- } catch (err) {
14140
- console.warn(
14141
- "[progress-handle] onPostTerminalUpdate threw \u2014 swallowed to keep update() non-throwing:",
14142
- err
14143
- );
14144
- }
14145
- return;
14146
- }
14147
- applyUpdate(next);
14148
- await scheduleOrFlush();
14149
- },
14150
- async complete(summary) {
14151
- if (terminal) return;
14152
- terminal = true;
14153
- state.terminal = { kind: "completed", message: summary };
14154
- state.lastChangeAt = now();
14155
- await doFlush();
14156
- },
14157
- async fail(reason) {
14158
- if (terminal) return;
14159
- terminal = true;
14160
- state.terminal = { kind: "failed", message: reason };
14161
- state.lastChangeAt = now();
14162
- await doFlush();
14163
- },
14164
- isTerminal: () => terminal
14165
- };
14166
- }
14167
- function defaultPostTerminalWarn(state) {
14168
- console.warn(
14169
- `[progress-handle] update() called after terminal transition (${state.terminal?.kind}) \u2014 ignored.`
14170
- );
14171
- }
14172
-
14173
- // src/progress-tools.ts
14174
- var ProgressToolRegistry = class {
14175
- constructor(opts) {
14176
- this.opts = opts;
14177
- this.toolNames = {
14178
- start: `${opts.prefix}_progress_start`,
14179
- update: `${opts.prefix}_progress_update`,
14180
- complete: `${opts.prefix}_progress_complete`,
14181
- fail: `${opts.prefix}_progress_fail`
14182
- };
14183
- }
14184
- handles = /* @__PURE__ */ new Map();
14185
- toolNames;
14186
- /** Tool definitions to splice into the MCP ListToolsRequest response. */
14187
- getDefinitions() {
14188
- const { surfaceDescription, startArgsSchema } = this.opts;
14189
- const debounceMs = this.opts.debounceMs ?? 1e3;
14190
- const debounceText = debounceMs === 1e3 ? "per second" : `every ${debounceMs}ms`;
14191
- return [
14192
- {
14193
- name: this.toolNames.start,
14194
- description: `Post a "still working" anchor to ${surfaceDescription} and return a progress_id. The anchor message updates in place as you call ${this.toolNames.update} \u2014 operators see one message that ticks forward instead of a flood of new ones. Always end with ${this.toolNames.complete} or ${this.toolNames.fail}; otherwise the anchor lingers as "working" until the stale-state sweep flips it. Opt-in \u2014 only call this for tasks that will take more than a few seconds.`,
14195
- inputSchema: {
14196
- type: "object",
14197
- properties: {
14198
- label: {
14199
- type: "string",
14200
- description: 'Short top-line label for the task (e.g. "diagnose vigil"). Stays constant for the lifetime of this progress anchor.'
14201
- },
14202
- initial_mode: {
14203
- type: "string",
14204
- enum: ["thinking", "working", "waiting"],
14205
- description: 'Initial mode emoji \u2014 defaults to "working".'
14206
- },
14207
- ...startArgsSchema.properties
14208
- },
14209
- required: ["label", ...startArgsSchema.required]
14210
- }
14211
- },
14212
- {
14213
- name: this.toolNames.update,
14214
- description: `Update the progress anchor in place. The state machine debounces calls to one ${surfaceDescription} API call ${debounceText}, so spamming this every step is safe \u2014 only the latest pending state will paint. Any subset of fields can be passed; omitted ones retain their previous value.`,
14215
- inputSchema: {
14216
- type: "object",
14217
- properties: {
14218
- progress_id: { type: "string", description: "The progress_id returned from start." },
14219
- step_label: { type: "string", description: 'Short label for the current step (e.g. "Querying CloudWatch logs").' },
14220
- step_current: { type: "number", description: "1-based step counter \u2014 current." },
14221
- step_total: { type: "number", description: "Total steps if known. Omit for open-ended progress." },
14222
- mode: { type: "string", enum: ["thinking", "working", "waiting"] },
14223
- detail: { type: "string", description: "Free-text detail line under the step label." }
14224
- },
14225
- required: ["progress_id"]
14226
- }
14227
- },
14228
- {
14229
- name: this.toolNames.complete,
14230
- description: `Mark the progress anchor as \u2705 completed. Flushes any pending debounced state before painting the terminal banner \u2014 the operator never sees a stale "Step N" beside the \u2705. After this, the handle is dead; further updates are no-ops.`,
14231
- inputSchema: {
14232
- type: "object",
14233
- properties: {
14234
- progress_id: { type: "string" },
14235
- summary: { type: "string", description: "Optional one-line summary of what was achieved." }
14236
- },
14237
- required: ["progress_id"]
14238
- }
14239
- },
14240
- {
14241
- name: this.toolNames.fail,
14242
- description: `Mark the progress anchor as \u274C failed. Always include a one-sentence reason \u2014 the operator can't tell *why* from emoji alone. Same flush-then-paint behaviour as complete.`,
14243
- inputSchema: {
14244
- type: "object",
14245
- properties: {
14246
- progress_id: { type: "string" },
14247
- reason: { type: "string", description: "One-sentence failure reason." }
14248
- },
14249
- required: ["progress_id", "reason"]
14250
- }
14251
- }
14252
- ];
14253
- }
14254
- /**
14255
- * Dispatch a CallToolRequest. Returns `undefined` if the tool name
14256
- * isn't one of ours (so the caller can keep walking its dispatch
14257
- * chain). Returns a tool result otherwise.
14258
- */
14259
- async handle(name, args) {
14260
- if (name === this.toolNames.start) return this.handleStart(args);
14261
- if (name === this.toolNames.update) return this.handleUpdate(args);
14262
- if (name === this.toolNames.complete) return this.handleComplete(args);
14263
- if (name === this.toolNames.fail) return this.handleFail(args);
14264
- return void 0;
14265
- }
14266
- /** Live count of in-flight handles. Exposed for tests + diagnostics. */
14267
- size() {
14268
- return this.handles.size;
14269
- }
14270
- async handleStart(args) {
14271
- const label = typeof args.label === "string" ? args.label : null;
14272
- if (!label) return errResult(`${this.toolNames.start}: 'label' must be a non-empty string`);
14273
- if ("initial_mode" in args && !isMode(args.initial_mode)) {
14274
- return errResult(
14275
- `${this.toolNames.start}: 'initial_mode' must be one of 'thinking', 'working', or 'waiting'`
14276
- );
14277
- }
14278
- for (const k of this.opts.startArgsSchema.required) {
14279
- if (typeof args[k] !== "string" || args[k].length === 0) {
14280
- return errResult(`${this.toolNames.start}: '${k}' must be a non-empty string`);
14281
- }
14282
- }
14283
- const initialMode = isMode(args.initial_mode) ? args.initial_mode : void 0;
14284
- const progressId = randomUUID();
14285
- try {
14286
- const flush = this.opts.createFlush(args);
14287
- const handle = await startProgressHandle({
14288
- initialLabel: label,
14289
- initialMode,
14290
- flush,
14291
- debounceMs: this.opts.debounceMs ?? 1e3
14292
- });
14293
- this.handles.set(progressId, handle);
14294
- return okResult(JSON.stringify({ progress_id: progressId }));
14295
- } catch (err) {
14296
- return errResult(`${this.toolNames.start} failed: ${err.message ?? String(err)}`);
14297
- }
14298
- }
14299
- async handleUpdate(args) {
14300
- const id = typeof args.progress_id === "string" ? args.progress_id : null;
14301
- if (!id) return errResult(`${this.toolNames.update}: 'progress_id' must be a string`);
14302
- const handle = this.handles.get(id);
14303
- if (!handle) return errResult(`${this.toolNames.update}: unknown progress_id (already terminated, or never started)`);
14304
- if ("mode" in args && !isMode(args.mode)) {
14305
- return errResult(
14306
- `${this.toolNames.update}: 'mode' must be one of 'thinking', 'working', or 'waiting'`
14307
- );
14308
- }
14309
- if (typeof args.step_total === "number" && typeof args.step_current !== "number") {
14310
- return errResult(
14311
- `${this.toolNames.update}: 'step_total' requires 'step_current'`
14312
- );
14313
- }
14314
- const next = {};
14315
- if (typeof args.step_label === "string") next.stepLabel = args.step_label;
14316
- if (typeof args.step_current === "number") {
14317
- next.stepNumber = {
14318
- current: args.step_current,
14319
- ...typeof args.step_total === "number" ? { total: args.step_total } : {}
14320
- };
14321
- }
14322
- if (isMode(args.mode)) next.mode = args.mode;
14323
- if (typeof args.detail === "string") next.detail = args.detail;
14324
- try {
14325
- await handle.update(next);
14326
- return okResult("ok");
14327
- } catch (err) {
14328
- return errResult(`${this.toolNames.update} failed: ${err.message ?? String(err)}`);
14329
- }
14330
- }
14331
- async handleComplete(args) {
14332
- const id = typeof args.progress_id === "string" ? args.progress_id : null;
14333
- if (!id) return errResult(`${this.toolNames.complete}: 'progress_id' must be a string`);
14334
- const handle = this.handles.get(id);
14335
- if (!handle) return errResult(`${this.toolNames.complete}: unknown progress_id`);
14336
- const summary = typeof args.summary === "string" ? args.summary : void 0;
14337
- try {
14338
- await handle.complete(summary);
14339
- this.handles.delete(id);
14340
- return okResult("ok");
14341
- } catch (err) {
14342
- return errResult(`${this.toolNames.complete} failed: ${err.message ?? String(err)}`);
14343
- }
14344
- }
14345
- async handleFail(args) {
14346
- const id = typeof args.progress_id === "string" ? args.progress_id : null;
14347
- if (!id) return errResult(`${this.toolNames.fail}: 'progress_id' must be a string`);
14348
- const reason = typeof args.reason === "string" ? args.reason : null;
14349
- if (!reason) return errResult(`${this.toolNames.fail}: 'reason' must be a non-empty string`);
14350
- const handle = this.handles.get(id);
14351
- if (!handle) return errResult(`${this.toolNames.fail}: unknown progress_id`);
14352
- try {
14353
- await handle.fail(reason);
14354
- this.handles.delete(id);
14355
- return okResult("ok");
14356
- } catch (err) {
14357
- return errResult(`${this.toolNames.fail} failed: ${err.message ?? String(err)}`);
14358
- }
14359
- }
14360
- };
14361
- function okResult(text) {
14362
- return { content: [{ type: "text", text }] };
14363
- }
14364
- function errResult(text) {
14365
- return { content: [{ type: "text", text }], isError: true };
14366
- }
14367
- function isMode(value) {
14368
- return value === "thinking" || value === "working" || value === "waiting";
14369
- }
14370
-
14371
13933
  // src/impersonation.ts
14372
13934
  var ENV_VAR = "AGT_ACT_AS_AGENT_ID";
14373
13935
  var OVERRIDE_ENV_VAR = "ENABLE_IMPERSONATION_CHANNELS";
@@ -14552,36 +14114,23 @@ var mcp = new Server(
14552
14114
  tools: {}
14553
14115
  },
14554
14116
  instructions: [
14117
+ // ENG-5845: highest-priority guard first. Without this framing,
14118
+ // Opus 4.8 reads the softer "Reply using…" line as a suggestion and
14119
+ // emits plain text — the reply lives in the local Claude session
14120
+ // but never reaches the operator's session_id through the channel
14121
+ // API. Mirrors the slack-channel CRITICAL line shipped in
14122
+ // ENG-5830. Total instructions string is ~850 / 2048 chars so we
14123
+ // have room to be explicit.
14124
+ "CRITICAL: every response to a direct-chat <channel> tag MUST go through direct_chat.reply (passing the session_id verbatim). Text in your session WITHOUT a direct_chat.reply call never reaches the operator \u2014 the reply dies inside the agent process.",
14555
14125
  'Messages from the webapp Direct Chat arrive as <channel source="direct-chat" session_id="..." user="...">.',
14556
14126
  "Reply using the direct_chat.reply tool, passing the session_id from the tag.",
14557
14127
  "Always reply to every direct chat message \u2014 the user is waiting in the webapp.",
14558
- "Long task (3+ tool calls or >5s)? Use direct_chat_progress_start (session_id), then direct_chat_progress_update between steps, then direct_chat_progress_complete or _fail. One anchor edits in place rather than spawning a new reply each step. Skip for one-shot Q&A.",
14559
14128
  "Keep replies concise and helpful. You have full access to all your MCP tools."
14560
14129
  ].join(" ")
14561
14130
  }
14562
14131
  );
14563
- var progressRegistry = new ProgressToolRegistry({
14564
- prefix: "direct_chat",
14565
- surfaceDescription: "a direct-chat session",
14566
- startArgsSchema: {
14567
- properties: {
14568
- session_id: {
14569
- type: "string",
14570
- description: 'Session id (from the `session_id` attribute on the inbound <channel source="direct-chat"> tag).'
14571
- }
14572
- },
14573
- required: ["session_id"]
14574
- },
14575
- createFlush: (args) => createDirectChatProgressFlush({
14576
- agtHost: AGT_HOST,
14577
- agentId: AGT_AGENT_ID,
14578
- sessionId: args.session_id,
14579
- getAuthToken
14580
- })
14581
- });
14582
14132
  mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
14583
14133
  tools: [
14584
- ...progressRegistry.getDefinitions(),
14585
14134
  {
14586
14135
  name: "channel_request_input",
14587
14136
  description: "Generic Yes/No or multi-choice picker. NOT YET IMPLEMENTED for Direct Chat \u2014 call returns NotImplemented. Follow-up issue tracked alongside ENG-5392 will add the Direct Chat renderer once the inline-button surface lands. Today the tool exists only so agents can register a stable, channel-agnostic signature in their prompt and degrade gracefully.",
@@ -14642,10 +14191,8 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
14642
14191
  mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
14643
14192
  const { name, arguments: args } = req.params;
14644
14193
  if (isImpersonating() && !channelsEnabledOverride() && DIRECT_CHAT_EGRESS_TOOLS.has(name)) {
14645
- return buildImpersonationRefusal(name);
14194
+ return { ...buildImpersonationRefusal(name) };
14646
14195
  }
14647
- const progressResult = await progressRegistry.handle(name, args ?? {});
14648
- if (progressResult !== void 0) return progressResult;
14649
14196
  if (name === "channel_request_input") {
14650
14197
  return {
14651
14198
  content: [
package/dist/mcp/index.js CHANGED
@@ -21771,7 +21771,12 @@ server.tool(
21771
21771
  "schedule_update",
21772
21772
  // Lead with user phrasings the agent should match against, then explain
21773
21773
  // the two modes. Order matters for tool selection.
21774
- '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 cron_expression/interval/timezone/delivery_channel/delivery_to/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.\n\nIMPORTANT \u2014 `delivery_to` requires a Slack channel ID (e.g. `C0123ABC456`), NOT a human channel name. If the user references a channel by its name ("the Customer Success channel"), call `mcp__slack__slack.list_channels` first with `query: "customer success"` to get the matching `id`, then pass that id as `delivery_to` here. Do not guess channel ids.',
21774
+ // CR PR #1601: field names + delivery_to shape brought into line with the
21775
+ // actual zod schema below. The prior copy referenced `cron_expression` /
21776
+ // `interval` (which the schema doesn't accept) and described
21777
+ // `delivery_to` as a raw channel ID (it's a structured DeliveryTargetSchema
21778
+ // object). Agents reading the old wording were producing invalid calls.
21779
+ '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
21780
  {
21776
21781
  task_id: external_exports.string().describe("The task ID to update (from schedule_list)"),
21777
21782
  // Direct-field mode
@@ -22279,32 +22284,46 @@ async function forwardToolCall(toolName, args) {
22279
22284
  FORWARD_TOOL_CALL_TIMEOUT_MS
22280
22285
  );
22281
22286
  }
22287
+ var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
22288
+ "kanban_list",
22289
+ "kanban_add",
22290
+ "kanban_move",
22291
+ "kanban_update",
22292
+ "kanban_progress",
22293
+ "kanban_done",
22294
+ "status_standup",
22295
+ "status_update",
22296
+ "drift_report",
22297
+ "token_refresh",
22298
+ "acpx_prompt",
22299
+ "acpx_exec",
22300
+ "acpx_spawn",
22301
+ "acpx_cancel",
22302
+ "acpx_status",
22303
+ "acpx_close",
22304
+ "schedule_list",
22305
+ "schedule_create",
22306
+ "schedule_delete",
22307
+ "schedule_update",
22308
+ "knowledge_list",
22309
+ "knowledge_add",
22310
+ "knowledge_update",
22311
+ "knowledge_delete",
22312
+ "plugin_list",
22313
+ "plugin_improve",
22314
+ "dashboards_list",
22315
+ "dashboards_show",
22316
+ "dashboards_upsert",
22317
+ "dashboards_request_refresh",
22318
+ "dashboards_pending_refreshes",
22319
+ "dashboards_persist_widget",
22320
+ "projects_list",
22321
+ "projects_get",
22322
+ "projects_get_source_chunk"
22323
+ ]);
22282
22324
  async function registerForwardedApiTools() {
22283
22325
  const apiTools = await discoverApiTools();
22284
- const localToolNames = /* @__PURE__ */ new Set([
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
- ]);
22326
+ const localToolNames = LOCAL_TOOL_NAMES;
22308
22327
  let registered = 0;
22309
22328
  let skipped = 0;
22310
22329
  for (const tool of apiTools) {