@integrity-labs/agt-cli 0.28.341 → 0.28.343

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 CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-SRRZO75K.js";
43
+ } from "../chunk-GAYSFNTX.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -4829,7 +4829,7 @@ import { execFileSync, execSync } from "child_process";
4829
4829
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4830
4830
  import chalk18 from "chalk";
4831
4831
  import ora16 from "ora";
4832
- var cliVersion = true ? "0.28.341" : "dev";
4832
+ var cliVersion = true ? "0.28.343" : "dev";
4833
4833
  async function fetchLatestVersion() {
4834
4834
  const host2 = getHost();
4835
4835
  if (!host2) return null;
@@ -6001,7 +6001,7 @@ function handleError(err) {
6001
6001
  }
6002
6002
 
6003
6003
  // src/bin/agt.ts
6004
- var cliVersion2 = true ? "0.28.341" : "dev";
6004
+ var cliVersion2 = true ? "0.28.343" : "dev";
6005
6005
  var program = new Command();
6006
6006
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6007
6007
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -1,4 +1,4 @@
1
- // src/lib/claude-scheduler.ts
1
+ // src/lib/scheduler-engine.ts
2
2
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { homedir } from "os";
@@ -175,7 +175,7 @@ function markTaskFired(codeName, taskId, status) {
175
175
  saveSchedulerState(codeName, state);
176
176
  } catch (err) {
177
177
  console.error(
178
- `[claude-scheduler] markTaskFired: failed to persist state for '${codeName}': ${err.message}`
178
+ `[scheduler-engine] markTaskFired: failed to persist state for '${codeName}': ${err.message}`
179
179
  );
180
180
  }
181
181
  return state;
@@ -199,4 +199,4 @@ export {
199
199
  findTaskByTemplate,
200
200
  getProjectDir
201
201
  };
202
- //# sourceMappingURL=chunk-I3YS5WFV.js.map
202
+ //# sourceMappingURL=chunk-EP6E6CIY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/scheduler-engine.ts"],"sourcesContent":["/**\n * Framework-agnostic scheduled-task state machine.\n *\n * The pure scheduling engine: schedule definitions -> next-fire computation ->\n * ready-task detection -> post-fire state advance, with on-disk persistence so\n * nextFireAt/lastFireAt survive manager restarts. It owns the WHEN, not the HOW:\n * each framework supplies its own firing leaf and calls back into\n * `markTaskFired`.\n * - Claude Code fires via the in-session kanban todo-card route\n * (manager/scheduler/execution.ts + kanban-route.ts).\n * - opencode fires via an HTTP inject into `opencode serve`\n * (manager/opencode-scheduler.ts).\n * Both share this engine verbatim, so cadence, one-shot completion,\n * manual-trigger, and cross-restart recovery are identical across frameworks.\n * (Named claude-scheduler.ts historically, when the claude `-p` oneshot was the\n * only consumer.)\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { Cron } from 'croner';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SchedulerTaskState {\n taskId: string;\n templateId: string;\n name: string;\n agentCodeName: string;\n agentId: string;\n scheduleKind: 'cron' | 'every' | 'at';\n scheduleExpr: string | null;\n scheduleEvery: string | null;\n scheduleAt: string | null;\n timezone: string;\n prompt: string;\n sessionTarget: string;\n deliveryMode: string;\n /** ENG-6107: always | conditional | never — whether results deliver.\n * Optional: states persisted by older CLIs lack it; absent = 'always'. */\n deliveryPolicy?: string | null;\n deliveryChannel: string | null;\n /** ENG-4422 §4: JSONB DeliveryTarget (or null). Legacy string form is gone\n * after the migration; in-memory shape is the structured object. */\n deliveryTo: unknown | null;\n enabled: boolean;\n triggeredAt: number | null; // epoch ms — manual trigger from webapp\n nextFireAt: number | null; // epoch ms, null = completed one-shot\n lastFireAt: number | null;\n lastStatus: 'ok' | 'error' | null;\n firedCount: number;\n}\n\nexport interface SchedulerState {\n version: 1;\n tasks: Record<string, SchedulerTaskState>;\n updatedAt: string;\n}\n\nexport interface SchedulerTaskInput {\n id: string;\n template_id: string;\n name: string;\n schedule_kind: 'cron' | 'every' | 'at';\n schedule_expr: string | null;\n schedule_every: string | null;\n schedule_at: string | null;\n timezone: string;\n prompt: string;\n session_target: string;\n delivery_mode: string;\n /** ENG-6107: absent from older APIs — treated as 'always'. */\n delivery_policy?: string | null;\n delivery_channel: string | null;\n /** ENG-4422 §4: JSONB DeliveryTarget or null (post-migration). */\n delivery_to: unknown | null;\n enabled: boolean;\n triggered_at?: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Interval parsing (reused from Claude Code adapter)\n// ---------------------------------------------------------------------------\n\nfunction parseIntervalMs(scheduleEvery: string | null): number {\n if (!scheduleEvery) return 60 * 60_000; // 1hr default\n const match = scheduleEvery.match(/^(\\d+)\\s*(m|min|h|hr|d)$/i);\n if (!match) return 60 * 60_000;\n const value = parseInt(match[1]!, 10);\n const unit = match[2]!.toLowerCase();\n if (unit === 'h' || unit === 'hr') return value * 60 * 60_000;\n if (unit === 'd') return value * 24 * 60 * 60_000;\n return value * 60_000; // minutes\n}\n\n// ---------------------------------------------------------------------------\n// Next-fire computation\n// ---------------------------------------------------------------------------\n\nexport function computeNextFire(\n kind: 'cron' | 'every' | 'at',\n expr: string | null,\n every: string | null,\n at: string | null,\n timezone: string,\n afterMs?: number,\n): number | null {\n const now = afterMs ?? Date.now();\n\n if (kind === 'cron' && expr) {\n try {\n const cron = new Cron(expr, { timezone: timezone || undefined });\n const next = cron.nextRun(new Date(now));\n return next ? next.getTime() : null;\n } catch {\n return null;\n }\n }\n\n if (kind === 'every') {\n const intervalMs = parseIntervalMs(every);\n return now + intervalMs;\n }\n\n if (kind === 'at' && at) {\n const ts = new Date(at).getTime();\n if (isNaN(ts)) return null;\n // If the 'at' timestamp is in the past and afterMs is set (meaning we already\n // fired), return null to prevent re-firing on state rebuild.\n if (afterMs && ts <= afterMs) return null;\n return ts;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// State persistence\n// ---------------------------------------------------------------------------\n\nfunction getStateDir(codeName: string): string {\n // ENG-4418: unified agent dir — scheduler state lives at the agent root\n // alongside other runtime state files (plugins.json, schedules.json,\n // registration.json). Legacy ~/.augmented/<codeName>/claudecode/scheduler-state.json\n // is migrated up by claudeCodeAdapter.getAgentDir on first poll.\n return join(homedir(), '.augmented', codeName);\n}\n\nfunction getStatePath(codeName: string): string {\n return join(getStateDir(codeName), 'scheduler-state.json');\n}\n\nexport function loadSchedulerState(codeName: string): SchedulerState {\n const path = getStatePath(codeName);\n if (existsSync(path)) {\n try {\n return JSON.parse(readFileSync(path, 'utf-8'));\n } catch { /* corrupted — start fresh */ }\n }\n return { version: 1, tasks: {}, updatedAt: new Date().toISOString() };\n}\n\nexport function saveSchedulerState(codeName: string, state: SchedulerState): void {\n const dir = getStateDir(codeName);\n mkdirSync(dir, { recursive: true });\n state.updatedAt = new Date().toISOString();\n const path = getStatePath(codeName);\n const tmpPath = path + '.tmp';\n writeFileSync(tmpPath, JSON.stringify(state, null, 2));\n renameSync(tmpPath, path);\n}\n\n// ---------------------------------------------------------------------------\n// Sync API tasks → scheduler state\n// ---------------------------------------------------------------------------\n\nexport function syncTasksToScheduler(\n codeName: string,\n agentId: string,\n tasks: SchedulerTaskInput[],\n): SchedulerState {\n const state = loadSchedulerState(codeName);\n const desiredIds = new Set(tasks.map((t) => t.id));\n\n // Remove tasks no longer in API\n for (const id of Object.keys(state.tasks)) {\n if (!desiredIds.has(id)) {\n delete state.tasks[id];\n }\n }\n\n // Add or update tasks\n for (const t of tasks) {\n const existing = state.tasks[t.id];\n if (existing) {\n // Only recompute nextFireAt if the schedule definition actually changed.\n // Without this guard, every sync cycle resets nextFireAt from \"now\",\n // preventing past-due tasks from ever being detected as ready.\n const scheduleChanged =\n existing.scheduleKind !== t.schedule_kind ||\n existing.scheduleExpr !== t.schedule_expr ||\n existing.scheduleEvery !== t.schedule_every ||\n existing.scheduleAt !== t.schedule_at ||\n existing.timezone !== t.timezone;\n\n // Update mutable fields, preserve fire history\n existing.name = t.name;\n existing.templateId = t.template_id;\n existing.scheduleKind = t.schedule_kind;\n existing.scheduleExpr = t.schedule_expr;\n existing.scheduleEvery = t.schedule_every;\n existing.scheduleAt = t.schedule_at;\n existing.timezone = t.timezone;\n existing.prompt = t.prompt;\n existing.sessionTarget = t.session_target;\n existing.deliveryMode = t.delivery_mode;\n existing.deliveryPolicy = t.delivery_policy ?? 'always';\n existing.deliveryChannel = t.delivery_channel;\n existing.deliveryTo = t.delivery_to;\n existing.enabled = t.enabled;\n if (t.triggered_at) existing.triggeredAt = new Date(t.triggered_at).getTime();\n if (scheduleChanged) {\n existing.nextFireAt = computeNextFire(\n t.schedule_kind, t.schedule_expr, t.schedule_every, t.schedule_at,\n t.timezone, existing.lastFireAt ?? undefined,\n );\n }\n } else {\n // New task\n state.tasks[t.id] = {\n taskId: t.id,\n templateId: t.template_id,\n name: t.name,\n agentCodeName: codeName,\n agentId,\n scheduleKind: t.schedule_kind,\n scheduleExpr: t.schedule_expr,\n scheduleEvery: t.schedule_every,\n scheduleAt: t.schedule_at,\n timezone: t.timezone,\n prompt: t.prompt,\n sessionTarget: t.session_target,\n deliveryMode: t.delivery_mode,\n deliveryPolicy: t.delivery_policy ?? 'always',\n deliveryChannel: t.delivery_channel,\n deliveryTo: t.delivery_to,\n enabled: t.enabled,\n triggeredAt: t.triggered_at ? new Date(t.triggered_at).getTime() : null,\n nextFireAt: computeNextFire(\n t.schedule_kind, t.schedule_expr, t.schedule_every, t.schedule_at, t.timezone,\n ),\n lastFireAt: null,\n lastStatus: null,\n firedCount: 0,\n };\n }\n }\n\n saveSchedulerState(codeName, state);\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Ready-task detection\n// ---------------------------------------------------------------------------\n\n// ENG-4675: pass `inFlightTaskIds` so the manager's poll loop doesn't\n// re-detect tasks that already have a `claude -p` subprocess running.\n// Without this, every supervisor tick (~17s) saw the manual trigger as\n// still ready (because lastFireAt is only set on completion, not on\n// fire start), spamming \"N ready task(s)\" + \"Firing task\" log lines that\n// looked like duplicate fires. The in-flight guard at the spawn site\n// prevented actual duplicate subprocesses, but the log was misleading.\nexport function getReadyTasks(\n state: SchedulerState,\n inFlightTaskIds?: ReadonlySet<string>,\n): SchedulerTaskState[] {\n const now = Date.now();\n const ready = Object.values(state.tasks).filter((t) => {\n if (!t.enabled) return false;\n if (inFlightTaskIds?.has(t.taskId)) return false;\n // Manual trigger: triggered_at is set and hasn't been fired yet\n if (t.triggeredAt) {\n const triggerReady = !t.lastFireAt || t.triggeredAt > t.lastFireAt;\n if (triggerReady) return true;\n }\n // Normal schedule\n return t.nextFireAt !== null && t.nextFireAt <= now;\n });\n // Deduplicate by templateId — only fire one task per template per cycle\n const seen = new Set<string>();\n return ready.filter((t) => {\n if (seen.has(t.templateId)) return false;\n seen.add(t.templateId);\n return true;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Post-execution state update\n// ---------------------------------------------------------------------------\n\nexport function markTaskFired(\n codeName: string,\n taskId: string,\n status: 'ok' | 'error',\n): SchedulerState {\n const state = loadSchedulerState(codeName);\n const task = state.tasks[taskId];\n if (!task) return state;\n\n task.lastFireAt = Date.now();\n task.lastStatus = status;\n task.firedCount++;\n\n // Compute next fire\n if (task.scheduleKind === 'at') {\n // One-shot — mark as completed\n task.nextFireAt = null;\n } else {\n task.nextFireAt = computeNextFire(\n task.scheduleKind, task.scheduleExpr, task.scheduleEvery, task.scheduleAt,\n task.timezone, task.lastFireAt,\n );\n }\n\n // Persisting is best-effort: the SchedulerState the caller stores in memory\n // (claudeSchedulerStates) is the running source of truth — getReadyTasks\n // reads it, not the disk file. A disk-write failure (ENOSPC/EACCES) must NOT\n // throw, or the caller's in-memory state would never advance and the task\n // would be treated as ready again next poll (ENG-5599: a duplicate\n // scheduled-task card materialised every tick). The mutated `state` is\n // returned regardless; cross-restart recovery is a separate concern.\n try {\n saveSchedulerState(codeName, state);\n } catch (err) {\n console.error(\n `[scheduler-engine] markTaskFired: failed to persist state for '${codeName}': ${(err as Error).message}`,\n );\n }\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Find a task by template ID (for work triggers)\n// ---------------------------------------------------------------------------\n\nexport function findTaskByTemplate(state: SchedulerState, templateId: string): SchedulerTaskState | undefined {\n return Object.values(state.tasks).find(\n (t) => t.templateId === templateId && t.enabled,\n );\n}\n\nexport function getProjectDir(codeName: string): string {\n return join(homedir(), '.augmented', codeName, 'project');\n}\n"],"mappings":";AAkBA,SAAS,YAAY,WAAW,cAAc,YAAY,qBAAqB;AAC/E,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,YAAY;AAkErB,SAAS,gBAAgB,eAAsC;AAC7D,MAAI,CAAC,cAAe,QAAO,KAAK;AAChC,QAAM,QAAQ,cAAc,MAAM,2BAA2B;AAC7D,MAAI,CAAC,MAAO,QAAO,KAAK;AACxB,QAAM,QAAQ,SAAS,MAAM,CAAC,GAAI,EAAE;AACpC,QAAM,OAAO,MAAM,CAAC,EAAG,YAAY;AACnC,MAAI,SAAS,OAAO,SAAS,KAAM,QAAO,QAAQ,KAAK;AACvD,MAAI,SAAS,IAAK,QAAO,QAAQ,KAAK,KAAK;AAC3C,SAAO,QAAQ;AACjB;AAMO,SAAS,gBACd,MACA,MACA,OACA,IACA,UACA,SACe;AACf,QAAM,MAAM,WAAW,KAAK,IAAI;AAEhC,MAAI,SAAS,UAAU,MAAM;AAC3B,QAAI;AACF,YAAM,OAAO,IAAI,KAAK,MAAM,EAAE,UAAU,YAAY,OAAU,CAAC;AAC/D,YAAM,OAAO,KAAK,QAAQ,IAAI,KAAK,GAAG,CAAC;AACvC,aAAO,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB,UAAM,aAAa,gBAAgB,KAAK;AACxC,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,SAAS,QAAQ,IAAI;AACvB,UAAM,KAAK,IAAI,KAAK,EAAE,EAAE,QAAQ;AAChC,QAAI,MAAM,EAAE,EAAG,QAAO;AAGtB,QAAI,WAAW,MAAM,QAAS,QAAO;AACrC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMA,SAAS,YAAY,UAA0B;AAK7C,SAAO,KAAK,QAAQ,GAAG,cAAc,QAAQ;AAC/C;AAEA,SAAS,aAAa,UAA0B;AAC9C,SAAO,KAAK,YAAY,QAAQ,GAAG,sBAAsB;AAC3D;AAEO,SAAS,mBAAmB,UAAkC;AACnE,QAAM,OAAO,aAAa,QAAQ;AAClC,MAAI,WAAW,IAAI,GAAG;AACpB,QAAI;AACF,aAAO,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,IAC/C,QAAQ;AAAA,IAAgC;AAAA,EAC1C;AACA,SAAO,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AACtE;AAEO,SAAS,mBAAmB,UAAkB,OAA6B;AAChF,QAAM,MAAM,YAAY,QAAQ;AAChC,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,QAAM,OAAO,aAAa,QAAQ;AAClC,QAAM,UAAU,OAAO;AACvB,gBAAc,SAAS,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACrD,aAAW,SAAS,IAAI;AAC1B;AAMO,SAAS,qBACd,UACA,SACA,OACgB;AAChB,QAAM,QAAQ,mBAAmB,QAAQ;AACzC,QAAM,aAAa,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAGjD,aAAW,MAAM,OAAO,KAAK,MAAM,KAAK,GAAG;AACzC,QAAI,CAAC,WAAW,IAAI,EAAE,GAAG;AACvB,aAAO,MAAM,MAAM,EAAE;AAAA,IACvB;AAAA,EACF;AAGA,aAAW,KAAK,OAAO;AACrB,UAAM,WAAW,MAAM,MAAM,EAAE,EAAE;AACjC,QAAI,UAAU;AAIZ,YAAM,kBACJ,SAAS,iBAAiB,EAAE,iBAC5B,SAAS,iBAAiB,EAAE,iBAC5B,SAAS,kBAAkB,EAAE,kBAC7B,SAAS,eAAe,EAAE,eAC1B,SAAS,aAAa,EAAE;AAG1B,eAAS,OAAO,EAAE;AAClB,eAAS,aAAa,EAAE;AACxB,eAAS,eAAe,EAAE;AAC1B,eAAS,eAAe,EAAE;AAC1B,eAAS,gBAAgB,EAAE;AAC3B,eAAS,aAAa,EAAE;AACxB,eAAS,WAAW,EAAE;AACtB,eAAS,SAAS,EAAE;AACpB,eAAS,gBAAgB,EAAE;AAC3B,eAAS,eAAe,EAAE;AAC1B,eAAS,iBAAiB,EAAE,mBAAmB;AAC/C,eAAS,kBAAkB,EAAE;AAC7B,eAAS,aAAa,EAAE;AACxB,eAAS,UAAU,EAAE;AACrB,UAAI,EAAE,aAAc,UAAS,cAAc,IAAI,KAAK,EAAE,YAAY,EAAE,QAAQ;AAC5E,UAAI,iBAAiB;AACnB,iBAAS,aAAa;AAAA,UACpB,EAAE;AAAA,UAAe,EAAE;AAAA,UAAe,EAAE;AAAA,UAAgB,EAAE;AAAA,UACtD,EAAE;AAAA,UAAU,SAAS,cAAc;AAAA,QACrC;AAAA,MACF;AAAA,IACF,OAAO;AAEL,YAAM,MAAM,EAAE,EAAE,IAAI;AAAA,QAClB,QAAQ,EAAE;AAAA,QACV,YAAY,EAAE;AAAA,QACd,MAAM,EAAE;AAAA,QACR,eAAe;AAAA,QACf;AAAA,QACA,cAAc,EAAE;AAAA,QAChB,cAAc,EAAE;AAAA,QAChB,eAAe,EAAE;AAAA,QACjB,YAAY,EAAE;AAAA,QACd,UAAU,EAAE;AAAA,QACZ,QAAQ,EAAE;AAAA,QACV,eAAe,EAAE;AAAA,QACjB,cAAc,EAAE;AAAA,QAChB,gBAAgB,EAAE,mBAAmB;AAAA,QACrC,iBAAiB,EAAE;AAAA,QACnB,YAAY,EAAE;AAAA,QACd,SAAS,EAAE;AAAA,QACX,aAAa,EAAE,eAAe,IAAI,KAAK,EAAE,YAAY,EAAE,QAAQ,IAAI;AAAA,QACnE,YAAY;AAAA,UACV,EAAE;AAAA,UAAe,EAAE;AAAA,UAAe,EAAE;AAAA,UAAgB,EAAE;AAAA,UAAa,EAAE;AAAA,QACvE;AAAA,QACA,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAEA,qBAAmB,UAAU,KAAK;AAClC,SAAO;AACT;AAaO,SAAS,cACd,OACA,iBACsB;AACtB,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,QAAQ,OAAO,OAAO,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM;AACrD,QAAI,CAAC,EAAE,QAAS,QAAO;AACvB,QAAI,iBAAiB,IAAI,EAAE,MAAM,EAAG,QAAO;AAE3C,QAAI,EAAE,aAAa;AACjB,YAAM,eAAe,CAAC,EAAE,cAAc,EAAE,cAAc,EAAE;AACxD,UAAI,aAAc,QAAO;AAAA,IAC3B;AAEA,WAAO,EAAE,eAAe,QAAQ,EAAE,cAAc;AAAA,EAClD,CAAC;AAED,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO,MAAM,OAAO,CAAC,MAAM;AACzB,QAAI,KAAK,IAAI,EAAE,UAAU,EAAG,QAAO;AACnC,SAAK,IAAI,EAAE,UAAU;AACrB,WAAO;AAAA,EACT,CAAC;AACH;AAMO,SAAS,cACd,UACA,QACA,QACgB;AAChB,QAAM,QAAQ,mBAAmB,QAAQ;AACzC,QAAM,OAAO,MAAM,MAAM,MAAM;AAC/B,MAAI,CAAC,KAAM,QAAO;AAElB,OAAK,aAAa,KAAK,IAAI;AAC3B,OAAK,aAAa;AAClB,OAAK;AAGL,MAAI,KAAK,iBAAiB,MAAM;AAE9B,SAAK,aAAa;AAAA,EACpB,OAAO;AACL,SAAK,aAAa;AAAA,MAChB,KAAK;AAAA,MAAc,KAAK;AAAA,MAAc,KAAK;AAAA,MAAe,KAAK;AAAA,MAC/D,KAAK;AAAA,MAAU,KAAK;AAAA,IACtB;AAAA,EACF;AASA,MAAI;AACF,uBAAmB,UAAU,KAAK;AAAA,EACpC,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN,kEAAkE,QAAQ,MAAO,IAAc,OAAO;AAAA,IACxG;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,OAAuB,YAAoD;AAC5G,SAAO,OAAO,OAAO,MAAM,KAAK,EAAE;AAAA,IAChC,CAAC,MAAM,EAAE,eAAe,cAAc,EAAE;AAAA,EAC1C;AACF;AAEO,SAAS,cAAc,UAA0B;AACtD,SAAO,KAAK,QAAQ,GAAG,cAAc,UAAU,SAAS;AAC1D;","names":[]}
@@ -6277,6 +6277,12 @@ function buildChannelServerEnv(channelId, config, options) {
6277
6277
  const avatar = options?.agentAvatarUrl?.trim();
6278
6278
  if (avatar)
6279
6279
  env["SLACK_AGENT_AVATAR_URL"] = avatar;
6280
+ const ackReaction = typeof config["ack_reaction"] === "string" ? config["ack_reaction"].trim() : "";
6281
+ if (ackReaction)
6282
+ env["SLACK_ACK_REACTION"] = ackReaction;
6283
+ const skipReaction = typeof config["skip_reaction"] === "string" ? config["skip_reaction"].trim() : "";
6284
+ if (skipReaction)
6285
+ env["SLACK_SKIP_REACTION"] = skipReaction;
6280
6286
  return env;
6281
6287
  }
6282
6288
  if (channelId === "telegram") {
@@ -6317,6 +6323,8 @@ function toOpencodeModel(primaryModel) {
6317
6323
  return `openai/${m}`;
6318
6324
  if (/^gemini/i.test(m))
6319
6325
  return `google/${m}`;
6326
+ if (/^grok/i.test(m))
6327
+ return `xai/${m}`;
6320
6328
  return `anthropic/${m}`;
6321
6329
  }
6322
6330
  function providerOf(opencodeModel) {
@@ -6327,7 +6335,8 @@ function buildProvider(opencodeModel) {
6327
6335
  const keyEnv = {
6328
6336
  anthropic: "ANTHROPIC_API_KEY",
6329
6337
  openai: "OPENAI_API_KEY",
6330
- google: "GOOGLE_GENERATIVE_AI_API_KEY"
6338
+ google: "GOOGLE_GENERATIVE_AI_API_KEY",
6339
+ xai: "XAI_API_KEY"
6331
6340
  };
6332
6341
  const envVar = keyEnv[provider] ?? `${provider.toUpperCase()}_API_KEY`;
6333
6342
  return { [provider]: { options: { apiKey: `{env:${envVar}}` } } };
@@ -6424,7 +6433,7 @@ function generateAgentsMd(input) {
6424
6433
  if (input.resolvedChannels.length > 0) {
6425
6434
  out.push("## Channels");
6426
6435
  out.push("");
6427
- out.push(`You reach people over: ${input.resolvedChannels.map((c) => `\`${c}\``).join(", ")}. Each channel is wired as an MCP server; use the matching tool to send and to reply on the same thread you were addressed on.`);
6436
+ out.push(`You reach people over: ${input.resolvedChannels.map((c) => `\`${c}\``).join(", ")}. An inbound message arrives as a turn tagged \`<channel ...>\` that names its channel and sender. Reply by writing your answer as your normal assistant response: the platform captures that reply text and delivers it back to the same channel and thread for you, automatically. There is no channel tool and no separate send or post step, so do NOT call a tool to deliver, post, or "reply on the thread". Just answer in plain text and end your turn.`);
6428
6437
  out.push("");
6429
6438
  }
6430
6439
  if (input.guardrails && input.guardrails.length > 0) {
@@ -7031,7 +7040,7 @@ function requireHost() {
7031
7040
  }
7032
7041
 
7033
7042
  // src/lib/api-client.ts
7034
- var agtCliVersion = true ? "0.28.341" : "dev";
7043
+ var agtCliVersion = true ? "0.28.343" : "dev";
7035
7044
  var lastConfigHash = null;
7036
7045
  function setConfigHash(hash) {
7037
7046
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -9480,4 +9489,4 @@ export {
9480
9489
  managerInstallSystemUnitCommand,
9481
9490
  managerUninstallSystemUnitCommand
9482
9491
  };
9483
- //# sourceMappingURL=chunk-SRRZO75K.js.map
9492
+ //# sourceMappingURL=chunk-GAYSFNTX.js.map