@cosmicstack/mercury-agent 1.0.6 → 1.1.1

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/index.js CHANGED
@@ -1535,9 +1535,9 @@ var OpenAICompatProvider = class extends BaseProvider {
1535
1535
  });
1536
1536
  return {
1537
1537
  text: result.text,
1538
- inputTokens: result.usage?.promptTokens ?? 0,
1539
- outputTokens: result.usage?.completionTokens ?? 0,
1540
- totalTokens: (result.usage?.promptTokens ?? 0) + (result.usage?.completionTokens ?? 0),
1538
+ inputTokens: result.usage?.inputTokens ?? 0,
1539
+ outputTokens: result.usage?.outputTokens ?? 0,
1540
+ totalTokens: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0),
1541
1541
  model: this.model,
1542
1542
  provider: this.name
1543
1543
  };
@@ -1585,9 +1585,9 @@ var AnthropicProvider = class extends BaseProvider {
1585
1585
  });
1586
1586
  return {
1587
1587
  text: result.text,
1588
- inputTokens: result.usage?.promptTokens ?? 0,
1589
- outputTokens: result.usage?.completionTokens ?? 0,
1590
- totalTokens: (result.usage?.promptTokens ?? 0) + (result.usage?.completionTokens ?? 0),
1588
+ inputTokens: result.usage?.inputTokens ?? 0,
1589
+ outputTokens: result.usage?.outputTokens ?? 0,
1590
+ totalTokens: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0),
1591
1591
  model: this.model,
1592
1592
  provider: this.name
1593
1593
  };
@@ -1611,6 +1611,38 @@ var AnthropicProvider = class extends BaseProvider {
1611
1611
  }
1612
1612
  };
1613
1613
 
1614
+ // src/providers/deepseek.ts
1615
+ import { createDeepSeek } from "@ai-sdk/deepseek";
1616
+ var DeepSeekProvider = class extends BaseProvider {
1617
+ name;
1618
+ model;
1619
+ modelInstance;
1620
+ isReasoner;
1621
+ constructor(config) {
1622
+ super(config);
1623
+ this.name = config.name;
1624
+ this.model = config.model;
1625
+ this.isReasoner = config.model === "deepseek-reasoner";
1626
+ const client = createDeepSeek({
1627
+ apiKey: config.apiKey,
1628
+ baseURL: config.baseUrl
1629
+ });
1630
+ this.modelInstance = client(config.model);
1631
+ }
1632
+ async generateText(_prompt, _systemPrompt) {
1633
+ throw new Error("Use getModelInstance() with the AI SDK agent loop");
1634
+ }
1635
+ async *streamText(_prompt, _systemPrompt) {
1636
+ throw new Error("Use getModelInstance() with the AI SDK agent loop");
1637
+ }
1638
+ isAvailable() {
1639
+ return this.config.apiKey.length > 0;
1640
+ }
1641
+ getModelInstance() {
1642
+ return this.modelInstance;
1643
+ }
1644
+ };
1645
+
1614
1646
  // src/providers/ollama.ts
1615
1647
  import { createOllama } from "ollama-ai-provider";
1616
1648
  var OllamaProvider = class extends BaseProvider {
@@ -1668,6 +1700,8 @@ var ProviderRegistry = class {
1668
1700
  let provider;
1669
1701
  if (pc.name === "anthropic") {
1670
1702
  provider = new AnthropicProvider(pc);
1703
+ } else if (pc.name === "deepseek") {
1704
+ provider = new DeepSeekProvider(pc);
1671
1705
  } else if (pc.name === "ollamaCloud" || pc.name === "ollamaLocal") {
1672
1706
  provider = new OllamaProvider(pc);
1673
1707
  } else {
@@ -1720,7 +1754,7 @@ var ProviderRegistry = class {
1720
1754
  };
1721
1755
 
1722
1756
  // src/core/agent.ts
1723
- import { generateText as generateText3, streamText as streamText3 } from "ai";
1757
+ import { generateText as generateText3, streamText as streamText3, stepCountIs } from "ai";
1724
1758
 
1725
1759
  // src/core/lifecycle.ts
1726
1760
  var VALID_TRANSITIONS = [
@@ -3885,6 +3919,7 @@ You can override this:
3885
3919
  }
3886
3920
  for (const provider of fallbackIterator) {
3887
3921
  try {
3922
+ const deepseekProviderOptions = provider instanceof DeepSeekProvider && provider.isReasoner ? { deepseek: { thinking: { type: "enabled" } } } : void 0;
3888
3923
  logger.info({ provider: provider.name, model: provider.getModel(), steps: MAX_STEPS, stream: canStream }, "Generating agentic response");
3889
3924
  if (canStream && channel) {
3890
3925
  const streamResult = streamText3({
@@ -3892,8 +3927,9 @@ You can override this:
3892
3927
  system: systemPrompt,
3893
3928
  messages,
3894
3929
  tools: this.capabilities.getTools(),
3895
- maxSteps: MAX_STEPS,
3930
+ stopWhen: stepCountIs(MAX_STEPS),
3896
3931
  abortSignal: loopAbortController.signal,
3932
+ ...deepseekProviderOptions ? { providerOptions: deepseekProviderOptions } : {},
3897
3933
  onStepFinish: async ({ toolCalls, toolResults }) => {
3898
3934
  if (toolCalls && toolResults && toolCalls.length > 0) {
3899
3935
  const names = toolCalls.map((tc) => tc.toolName).join(", ");
@@ -3903,7 +3939,7 @@ You can override this:
3903
3939
  const tr = toolResults[i];
3904
3940
  const resultStr = typeof tr?.result === "string" ? tr.result : JSON.stringify(tr?.result ?? "");
3905
3941
  const failed = resultStr.length < 5e3 && (resultStr.startsWith("Error:") || resultStr.startsWith("\u26A0") || resultStr.includes("exited with code") || resultStr.includes("Command failed") || resultStr.startsWith("Command exited with code"));
3906
- loopDetector.record(tc.toolName, tc.args, failed);
3942
+ loopDetector.record(tc.toolName, tc.input, failed);
3907
3943
  }
3908
3944
  if (loopDetector.detectAbsoluteLimit()) {
3909
3945
  logger.warn("Absolute tool call limit reached \u2014 aborting");
@@ -3961,7 +3997,7 @@ You can override this:
3961
3997
  if (channel && msg.channelType !== "internal") {
3962
3998
  if (channel instanceof CLIChannel) {
3963
3999
  for (const tc of toolCalls) {
3964
- await channel.sendToolFeedback(tc.toolName, tc.args).catch(() => {
4000
+ await channel.sendToolFeedback(tc.toolName, tc.input).catch(() => {
3965
4001
  });
3966
4002
  }
3967
4003
  if (toolResults) {
@@ -3976,7 +4012,7 @@ You can override this:
3976
4012
  } else if (channel instanceof TelegramChannel) {
3977
4013
  const tgCh = channel;
3978
4014
  for (const tc of toolCalls) {
3979
- await tgCh.sendToolFeedback(tc.toolName, tc.args, msg.channelId).catch(() => {
4015
+ await tgCh.sendToolFeedback(tc.toolName, tc.input, msg.channelId).catch(() => {
3980
4016
  });
3981
4017
  }
3982
4018
  if (toolResults) {
@@ -4042,7 +4078,8 @@ You can override this:
4042
4078
  const [usage] = await Promise.all([
4043
4079
  streamResult.usage
4044
4080
  ]);
4045
- result = { text: fullText, usage };
4081
+ const streamReasoning = await streamResult.reasoning;
4082
+ result = { text: fullText, usage, reasoning: streamReasoning };
4046
4083
  streamedText = fullText;
4047
4084
  loopDetector.recordStepText(fullText);
4048
4085
  } else {
@@ -4051,8 +4088,9 @@ You can override this:
4051
4088
  system: systemPrompt,
4052
4089
  messages,
4053
4090
  tools: this.capabilities.getTools(),
4054
- maxSteps: MAX_STEPS,
4091
+ stopWhen: stepCountIs(MAX_STEPS),
4055
4092
  abortSignal: loopAbortController.signal,
4093
+ ...deepseekProviderOptions ? { providerOptions: deepseekProviderOptions } : {},
4056
4094
  onStepFinish: async ({ toolCalls, toolResults }) => {
4057
4095
  if (toolCalls && toolResults && toolCalls.length > 0) {
4058
4096
  const names = toolCalls.map((tc) => tc.toolName).join(", ");
@@ -4062,7 +4100,7 @@ You can override this:
4062
4100
  const tr = toolResults[i];
4063
4101
  const resultStr = typeof tr?.result === "string" ? tr.result : JSON.stringify(tr?.result ?? "");
4064
4102
  const failed = resultStr.length < 5e3 && (resultStr.startsWith("Error:") || resultStr.startsWith("\u26A0") || resultStr.includes("exited with code") || resultStr.includes("Command failed") || resultStr.startsWith("Command exited with code"));
4065
- loopDetector.record(tc.toolName, tc.args, failed);
4103
+ loopDetector.record(tc.toolName, tc.input, failed);
4066
4104
  }
4067
4105
  if (loopDetector.detectAbsoluteLimit()) {
4068
4106
  logger.warn("Absolute tool call limit reached \u2014 aborting");
@@ -4120,7 +4158,7 @@ You can override this:
4120
4158
  if (channel && msg.channelType !== "internal") {
4121
4159
  if (channel instanceof CLIChannel) {
4122
4160
  for (const tc of toolCalls) {
4123
- await channel.sendToolFeedback(tc.toolName, tc.args).catch(() => {
4161
+ await channel.sendToolFeedback(tc.toolName, tc.input).catch(() => {
4124
4162
  });
4125
4163
  }
4126
4164
  if (toolResults) {
@@ -4135,7 +4173,7 @@ You can override this:
4135
4173
  } else if (channel instanceof TelegramChannel) {
4136
4174
  const tgCh = channel;
4137
4175
  for (const tc of toolCalls) {
4138
- await tgCh.sendToolFeedback(tc.toolName, tc.args, msg.channelId).catch(() => {
4176
+ await tgCh.sendToolFeedback(tc.toolName, tc.input, msg.channelId).catch(() => {
4139
4177
  });
4140
4178
  }
4141
4179
  if (toolResults) {
@@ -4221,9 +4259,9 @@ You can override this:
4221
4259
  this.tokenBudget.recordUsage({
4222
4260
  provider: usedProvider.name,
4223
4261
  model: usedProvider.model,
4224
- inputTokens: result.usage?.promptTokens ?? 0,
4225
- outputTokens: result.usage?.completionTokens ?? 0,
4226
- totalTokens: (result.usage?.promptTokens ?? 0) + (result.usage?.completionTokens ?? 0),
4262
+ inputTokens: result.usage?.inputTokens ?? 0,
4263
+ outputTokens: result.usage?.outputTokens ?? 0,
4264
+ totalTokens: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0),
4227
4265
  channelType: msg.channelType
4228
4266
  });
4229
4267
  this.shortTerm.add(msg.channelId, {
@@ -4237,7 +4275,8 @@ You can override this:
4237
4275
  timestamp: Date.now(),
4238
4276
  role: "assistant",
4239
4277
  content: finalText,
4240
- tokenCount: (result.usage?.promptTokens ?? 0) + (result.usage?.completionTokens ?? 0)
4278
+ tokenCount: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0),
4279
+ reasoning: result.reasoning || void 0
4241
4280
  });
4242
4281
  this.episodic.record({
4243
4282
  type: "message",
@@ -4433,14 +4472,14 @@ All actions auto-approved for this run.`,
4433
4472
  { role: "user", content: `User: ${userMessage}
4434
4473
  Assistant: ${agentResponse}` }
4435
4474
  ],
4436
- maxTokens: 400
4475
+ maxOutputTokens: 400
4437
4476
  });
4438
4477
  this.tokenBudget.recordUsage({
4439
4478
  provider: provider.name,
4440
4479
  model: provider.getModel(),
4441
- inputTokens: result.usage?.promptTokens ?? 0,
4442
- outputTokens: result.usage?.completionTokens ?? 0,
4443
- totalTokens: (result.usage?.promptTokens ?? 0) + (result.usage?.completionTokens ?? 0),
4480
+ inputTokens: result.usage?.inputTokens ?? 0,
4481
+ outputTokens: result.usage?.outputTokens ?? 0,
4482
+ totalTokens: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0),
4444
4483
  channelType: "internal"
4445
4484
  });
4446
4485
  const text = result.text.trim();
@@ -4537,6 +4576,27 @@ Or use /budget override, /budget reset, /budget set <number> anytime.`,
4537
4576
  await channel.send(ctx.manual(), channelId);
4538
4577
  return true;
4539
4578
  }
4579
+ if (cmd === "/exit" || cmd === "/quit") {
4580
+ await channel.send("Goodbye! Shutting down Mercury...", channelId);
4581
+ this.shutdown();
4582
+ return true;
4583
+ }
4584
+ if (cmd === "/permissions") {
4585
+ if (channelType === "cli" && channel instanceof CLIChannel) {
4586
+ const mode = await channel.askPermissionMode?.();
4587
+ if (mode === "allow-all") {
4588
+ this.capabilities.permissions.setAutoApproveAll(true);
4589
+ this.capabilities.permissions.addTempScope("/", true, true);
4590
+ await channel.send("Allow All mode active for this session. All scopes, commands, and loops auto-approved. Resets on restart.", channelId);
4591
+ } else {
4592
+ this.capabilities.permissions.setAutoApproveAll(false);
4593
+ await channel.send("Ask Me mode active. Risky actions will prompt for confirmation.", channelId);
4594
+ }
4595
+ return true;
4596
+ }
4597
+ await channel.send("Use /permissions in CLI to switch permission mode. On Telegram, use the /permissions button or command.", channelId);
4598
+ return true;
4599
+ }
4540
4600
  if (cmd === "/status") {
4541
4601
  const config = ctx.config();
4542
4602
  const budget = ctx.tokenBudget();
@@ -4789,9 +4849,11 @@ Or use /budget override, /budget reset, /budget set <number> anytime.`,
4789
4849
  await channel.withMenu(async (select) => {
4790
4850
  while (true) {
4791
4851
  const streamLabel = this.telegramStreaming ? "Disable Telegram Streaming" : "Enable Telegram Streaming";
4852
+ const permLabel = this.capabilities.permissions.isAutoApproveAll() ? "Switch to Ask Me" : "Switch to Allow All";
4792
4853
  const action = await select("Mercury Commands", [
4793
4854
  { value: "status", label: "Status" },
4794
4855
  { value: "memory", label: "Memory" },
4856
+ { value: "permissions", label: permLabel },
4795
4857
  { value: "telegram", label: "Telegram" },
4796
4858
  { value: "tools", label: "Tools" },
4797
4859
  { value: "skills", label: "Skills" },
@@ -4814,6 +4876,10 @@ Or use /budget override, /budget reset, /budget set <number> anytime.`,
4814
4876
  }
4815
4877
  continue;
4816
4878
  }
4879
+ if (action === "permissions") {
4880
+ await this.handleChatCommand("/permissions", "cli", channelId);
4881
+ continue;
4882
+ }
4817
4883
  if (action === "telegram") {
4818
4884
  await this.openCliTelegramMenu(channel, channelId, select);
4819
4885
  continue;
@@ -5321,6 +5387,11 @@ var ChannelRegistry = class {
5321
5387
  import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
5322
5388
  import { join as join7 } from "path";
5323
5389
  var TOKEN_FILE = "token-usage.json";
5390
+ function safeNumber(value) {
5391
+ if (value === null || value === void 0) return 0;
5392
+ const n = Number(value);
5393
+ return isNaN(n) ? 0 : n;
5394
+ }
5324
5395
  var TokenBudget = class {
5325
5396
  constructor(config) {
5326
5397
  this.config = config;
@@ -5336,7 +5407,7 @@ var TokenBudget = class {
5336
5407
  forceNext = false;
5337
5408
  canAfford(estimatedTokens) {
5338
5409
  this.resetIfNewDay();
5339
- return this.dailyUsed + estimatedTokens <= this.dailyBudget;
5410
+ return safeNumber(this.dailyUsed) + estimatedTokens <= safeNumber(this.dailyBudget);
5340
5411
  }
5341
5412
  isOverBudget() {
5342
5413
  this.resetIfNewDay();
@@ -5344,7 +5415,7 @@ var TokenBudget = class {
5344
5415
  this.forceNext = false;
5345
5416
  return false;
5346
5417
  }
5347
- return this.dailyUsed >= this.dailyBudget;
5418
+ return safeNumber(this.dailyUsed) >= safeNumber(this.dailyBudget);
5348
5419
  }
5349
5420
  forceAllowNext() {
5350
5421
  this.forceNext = true;
@@ -5372,18 +5443,24 @@ var TokenBudget = class {
5372
5443
  }
5373
5444
  recordUsage(entry) {
5374
5445
  this.resetIfNewDay();
5375
- const logEntry = { ...entry, timestamp: Date.now() };
5376
- this.dailyUsed += entry.totalTokens;
5446
+ const inputTokens = safeNumber(entry.inputTokens);
5447
+ const outputTokens = safeNumber(entry.outputTokens);
5448
+ const totalTokens = safeNumber(entry.totalTokens) || inputTokens + outputTokens;
5449
+ const safeEntry = { ...entry, inputTokens, outputTokens, totalTokens };
5450
+ const logEntry = { ...safeEntry, timestamp: Date.now() };
5451
+ this.dailyUsed += totalTokens;
5377
5452
  this.requestLog.push(logEntry);
5378
5453
  this.persist();
5379
5454
  }
5380
5455
  getRemaining() {
5381
5456
  this.resetIfNewDay();
5382
- return Math.max(0, this.dailyBudget - this.dailyUsed);
5457
+ return Math.max(0, safeNumber(this.dailyBudget) - safeNumber(this.dailyUsed));
5383
5458
  }
5384
5459
  getUsagePercentage() {
5385
5460
  this.resetIfNewDay();
5386
- return this.dailyBudget > 0 ? this.dailyUsed / this.dailyBudget * 100 : 0;
5461
+ const budget = safeNumber(this.dailyBudget);
5462
+ const used = safeNumber(this.dailyUsed);
5463
+ return budget > 0 ? used / budget * 100 : 0;
5387
5464
  }
5388
5465
  getStatusText() {
5389
5466
  const pct = Math.round(this.getUsagePercentage());
@@ -5422,8 +5499,16 @@ var TokenBudget = class {
5422
5499
  const data = JSON.parse(raw);
5423
5500
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
5424
5501
  if (data.lastResetDate === today) {
5425
- this.dailyUsed = data.dailyUsed ?? 0;
5426
- this.requestLog = data.requestLog ?? [];
5502
+ const restored = safeNumber(data.dailyUsed);
5503
+ if (!isNaN(restored)) {
5504
+ this.dailyUsed = restored;
5505
+ }
5506
+ this.requestLog = (data.requestLog ?? []).map((entry) => ({
5507
+ ...entry,
5508
+ inputTokens: safeNumber(entry.inputTokens),
5509
+ outputTokens: safeNumber(entry.outputTokens),
5510
+ totalTokens: safeNumber(entry.totalTokens)
5511
+ }));
5427
5512
  }
5428
5513
  this.lastResetDate = data.lastResetDate ?? today;
5429
5514
  } catch (err) {
@@ -5548,7 +5633,6 @@ var PermissionManager = class {
5548
5633
  askHandler;
5549
5634
  autoApproveAll = false;
5550
5635
  elevatedCommands = /* @__PURE__ */ new Set();
5551
- pendingApprovals = /* @__PURE__ */ new Set();
5552
5636
  currentChannelType = "cli";
5553
5637
  tempScopes = [];
5554
5638
  constructor() {
@@ -5591,12 +5675,6 @@ var PermissionManager = class {
5591
5675
  isShellElevated() {
5592
5676
  return this.elevatedCommands.has("run_command");
5593
5677
  }
5594
- addPendingApproval(baseCommand) {
5595
- this.pendingApprovals.add(baseCommand);
5596
- }
5597
- clearPendingApprovals() {
5598
- this.pendingApprovals.clear();
5599
- }
5600
5678
  load() {
5601
5679
  if (existsSync7(PERMISSIONS_FILE)) {
5602
5680
  try {
@@ -5655,6 +5733,9 @@ var PermissionManager = class {
5655
5733
  if (mode === "write" && tempScope.write) return { allowed: true };
5656
5734
  return { allowed: false, reason: `Permission denied: ${mode} access to ${path3}` };
5657
5735
  }
5736
+ if (!this.autoApproveAll && this.askHandler && this.currentChannelType !== "internal") {
5737
+ return this.requestScopeExternal(path3, mode);
5738
+ }
5658
5739
  return { allowed: false, reason: `Permission denied for ${mode} access to ${path3}` };
5659
5740
  }
5660
5741
  async checkShellCommand(command) {
@@ -5672,10 +5753,6 @@ var PermissionManager = class {
5672
5753
  }
5673
5754
  const trimmed = command.trim();
5674
5755
  const baseCmd = trimmed.split(/\s+/)[0];
5675
- if (this.pendingApprovals.has(baseCmd)) {
5676
- logger.info({ cmd: trimmed }, "Shell command auto-approved (pending approval)");
5677
- return { allowed: true, needsApproval: false };
5678
- }
5679
5756
  for (const pattern of shell.blocked) {
5680
5757
  if (this.matchPattern(trimmed, pattern)) {
5681
5758
  return { allowed: false, reason: `Blocked command: matches "${pattern}"`, needsApproval: false };
@@ -5698,7 +5775,7 @@ var PermissionManager = class {
5698
5775
  }
5699
5776
  for (const pattern of shell.needsApproval) {
5700
5777
  if (this.matchPattern(trimmed, pattern)) {
5701
- if (this.currentChannelType === "telegram" && this.askHandler) {
5778
+ if (this.askHandler && this.currentChannelType !== "internal") {
5702
5779
  const result = await this.askHandler(`Run command: ${trimmed}`);
5703
5780
  if (result === "yes") {
5704
5781
  return { allowed: true, needsApproval: false };
@@ -5712,7 +5789,7 @@ var PermissionManager = class {
5712
5789
  return { allowed: false, reason: `Command requires approval: matches "${pattern}"`, needsApproval: true };
5713
5790
  }
5714
5791
  }
5715
- if (this.currentChannelType === "telegram" && this.askHandler) {
5792
+ if (this.askHandler && this.currentChannelType !== "internal") {
5716
5793
  const result = await this.askHandler(`Run command: ${trimmed}`);
5717
5794
  if (result === "yes") {
5718
5795
  return { allowed: true, needsApproval: false };
@@ -5818,6 +5895,11 @@ Allow access?`;
5818
5895
  return null;
5819
5896
  }
5820
5897
  mergeDefaults(parsed) {
5898
+ const mergeArray = (existing, defaults) => {
5899
+ if (!existing) return [...defaults];
5900
+ const combined = /* @__PURE__ */ new Set([...defaults, ...existing]);
5901
+ return [...combined];
5902
+ };
5821
5903
  return {
5822
5904
  capabilities: {
5823
5905
  filesystem: {
@@ -5826,9 +5908,9 @@ Allow access?`;
5826
5908
  },
5827
5909
  shell: {
5828
5910
  enabled: parsed.capabilities?.shell?.enabled ?? DEFAULT_MANIFEST.capabilities.shell.enabled,
5829
- blocked: parsed.capabilities?.shell?.blocked ?? DEFAULT_MANIFEST.capabilities.shell.blocked,
5830
- autoApproved: parsed.capabilities?.shell?.autoApproved ?? DEFAULT_MANIFEST.capabilities.shell.autoApproved,
5831
- needsApproval: parsed.capabilities?.shell?.needsApproval ?? DEFAULT_MANIFEST.capabilities.shell.needsApproval,
5911
+ blocked: mergeArray(parsed.capabilities?.shell?.blocked, DEFAULT_MANIFEST.capabilities.shell.blocked),
5912
+ autoApproved: mergeArray(parsed.capabilities?.shell?.autoApproved, DEFAULT_MANIFEST.capabilities.shell.autoApproved),
5913
+ needsApproval: mergeArray(parsed.capabilities?.shell?.needsApproval, DEFAULT_MANIFEST.capabilities.shell.needsApproval),
5832
5914
  cwdOnly: parsed.capabilities?.shell?.cwdOnly ?? DEFAULT_MANIFEST.capabilities.shell.cwdOnly
5833
5915
  },
5834
5916
  git: {
@@ -5842,16 +5924,16 @@ Allow access?`;
5842
5924
  };
5843
5925
 
5844
5926
  // src/capabilities/filesystem/read-file.ts
5845
- import { tool } from "ai";
5927
+ import { tool, zodSchema } from "ai";
5846
5928
  import { z } from "zod";
5847
5929
  import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
5848
5930
  import { resolve as resolve4, isAbsolute } from "path";
5849
5931
  function createReadFileTool(permissions, getCwd) {
5850
5932
  return tool({
5851
5933
  description: "Read the contents of a file. The path must be within an allowed scope.",
5852
- parameters: z.object({
5934
+ inputSchema: zodSchema(z.object({
5853
5935
  path: z.string().describe("Absolute or relative path to the file")
5854
- }),
5936
+ })),
5855
5937
  execute: async ({ path: path3 }) => {
5856
5938
  const resolved = isAbsolute(path3) ? resolve4(path3) : resolve4(getCwd(), path3);
5857
5939
  const check = await permissions.checkFsAccess(resolved, "read");
@@ -5879,17 +5961,17 @@ function createReadFileTool(permissions, getCwd) {
5879
5961
  }
5880
5962
 
5881
5963
  // src/capabilities/filesystem/write-file.ts
5882
- import { tool as tool2 } from "ai";
5964
+ import { tool as tool2, zodSchema as zodSchema2 } from "ai";
5883
5965
  import { z as z2 } from "zod";
5884
5966
  import { existsSync as existsSync9, writeFileSync as writeFileSync7 } from "fs";
5885
5967
  import { resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
5886
5968
  function createWriteFileTool(permissions, getCwd) {
5887
5969
  return tool2({
5888
5970
  description: "Write content to an existing file. The path must be within a writable scope.",
5889
- parameters: z2.object({
5971
+ inputSchema: zodSchema2(z2.object({
5890
5972
  path: z2.string().describe("Absolute or relative path to the file"),
5891
5973
  content: z2.string().describe("The content to write to the file")
5892
- }),
5974
+ })),
5893
5975
  execute: async ({ path: path3, content }) => {
5894
5976
  const resolved = isAbsolute2(path3) ? resolve5(path3) : resolve5(getCwd(), path3);
5895
5977
  const check = await permissions.checkFsAccess(resolved, "write");
@@ -5911,17 +5993,17 @@ function createWriteFileTool(permissions, getCwd) {
5911
5993
  }
5912
5994
 
5913
5995
  // src/capabilities/filesystem/create-file.ts
5914
- import { tool as tool3 } from "ai";
5996
+ import { tool as tool3, zodSchema as zodSchema3 } from "ai";
5915
5997
  import { z as z3 } from "zod";
5916
5998
  import { existsSync as existsSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
5917
5999
  import { resolve as resolve6, dirname as dirname3, isAbsolute as isAbsolute3 } from "path";
5918
6000
  function createCreateFileTool(permissions, getCwd) {
5919
6001
  return tool3({
5920
6002
  description: "Create a new file with the given content. Also creates parent directories if needed. The path must be within a writable scope.",
5921
- parameters: z3.object({
6003
+ inputSchema: zodSchema3(z3.object({
5922
6004
  path: z3.string().describe("Absolute or relative path for the new file"),
5923
6005
  content: z3.string().describe("The content of the new file")
5924
- }),
6006
+ })),
5925
6007
  execute: async ({ path: path3, content }) => {
5926
6008
  const resolved = isAbsolute3(path3) ? resolve6(path3) : resolve6(getCwd(), path3);
5927
6009
  const check = await permissions.checkFsAccess(resolved, "write");
@@ -5947,16 +6029,16 @@ function createCreateFileTool(permissions, getCwd) {
5947
6029
  }
5948
6030
 
5949
6031
  // src/capabilities/filesystem/list-dir.ts
5950
- import { tool as tool4 } from "ai";
6032
+ import { tool as tool4, zodSchema as zodSchema4 } from "ai";
5951
6033
  import { z as z4 } from "zod";
5952
6034
  import { existsSync as existsSync11, readdirSync as readdirSync2, statSync } from "fs";
5953
6035
  import { resolve as resolve7, isAbsolute as isAbsolute4, join as join9 } from "path";
5954
6036
  function createListDirTool(permissions, getCwd) {
5955
6037
  return tool4({
5956
6038
  description: "List the contents of a directory. Shows file names, types, and sizes.",
5957
- parameters: z4.object({
6039
+ inputSchema: zodSchema4(z4.object({
5958
6040
  path: z4.string().describe("Absolute or relative path to the directory")
5959
- }),
6041
+ })),
5960
6042
  execute: async ({ path: path3 }) => {
5961
6043
  const resolved = isAbsolute4(path3) ? resolve7(path3) : resolve7(getCwd(), path3);
5962
6044
  const check = await permissions.checkFsAccess(resolved, "read");
@@ -6002,16 +6084,16 @@ function formatSize(bytes) {
6002
6084
  }
6003
6085
 
6004
6086
  // src/capabilities/filesystem/delete-file.ts
6005
- import { tool as tool5 } from "ai";
6087
+ import { tool as tool5, zodSchema as zodSchema5 } from "ai";
6006
6088
  import { z as z5 } from "zod";
6007
6089
  import { existsSync as existsSync12, unlinkSync as unlinkSync2 } from "fs";
6008
6090
  import { resolve as resolve8, isAbsolute as isAbsolute5 } from "path";
6009
6091
  function createDeleteFileTool(permissions, getCwd) {
6010
6092
  return tool5({
6011
6093
  description: "Delete a file. This action cannot be undone. The path must be within a writable scope. Always asks for confirmation.",
6012
- parameters: z5.object({
6094
+ inputSchema: zodSchema5(z5.object({
6013
6095
  path: z5.string().describe("Absolute or relative path to the file to delete")
6014
- }),
6096
+ })),
6015
6097
  execute: async ({ path: path3 }) => {
6016
6098
  const resolved = isAbsolute5(path3) ? resolve8(path3) : resolve8(getCwd(), path3);
6017
6099
  const check = await permissions.checkFsAccess(resolved, "write");
@@ -6037,18 +6119,18 @@ function createDeleteFileTool(permissions, getCwd) {
6037
6119
  }
6038
6120
 
6039
6121
  // src/capabilities/filesystem/edit-file.ts
6040
- import { tool as tool6 } from "ai";
6122
+ import { tool as tool6, zodSchema as zodSchema6 } from "ai";
6041
6123
  import { z as z6 } from "zod";
6042
6124
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
6043
6125
  import { resolve as resolve9, isAbsolute as isAbsolute6 } from "path";
6044
6126
  function createEditFileTool(permissions, getCwd) {
6045
6127
  return tool6({
6046
6128
  description: "Edit a file by replacing an exact string match with new content. Use this instead of write_file when you only need to change part of a file. The old_string must match exactly (including whitespace and indentation). Fails if old_string is not found or found multiple times.",
6047
- parameters: z6.object({
6129
+ inputSchema: zodSchema6(z6.object({
6048
6130
  path: z6.string().describe("Absolute or relative path to the file"),
6049
6131
  old_string: z6.string().describe("The exact text to find in the file (must match exactly)"),
6050
6132
  new_string: z6.string().describe("The text to replace it with")
6051
- }),
6133
+ })),
6052
6134
  execute: async ({ path: path3, old_string, new_string }) => {
6053
6135
  const resolved = isAbsolute6(path3) ? resolve9(path3) : resolve9(getCwd(), path3);
6054
6136
  const fsCheck = await permissions.checkFsAccess(resolved, "write");
@@ -6081,16 +6163,16 @@ function createEditFileTool(permissions, getCwd) {
6081
6163
  }
6082
6164
 
6083
6165
  // src/capabilities/filesystem/send-file.ts
6084
- import { tool as tool7 } from "ai";
6166
+ import { tool as tool7, zodSchema as zodSchema7 } from "ai";
6085
6167
  import { z as z7 } from "zod";
6086
6168
  import { existsSync as existsSync13, statSync as statSync2 } from "fs";
6087
6169
  import { resolve as resolve10, basename as basename2, isAbsolute as isAbsolute7 } from "path";
6088
6170
  function createSendFileTool(permissions, getCwd, sendFile) {
6089
6171
  return tool7({
6090
6172
  description: "Send a file to the user. On Telegram the file is uploaded as an attachment to the relevant approved recipients. On CLI the file path and size are displayed. The path must be within an allowed read scope.",
6091
- parameters: z7.object({
6173
+ inputSchema: zodSchema7(z7.object({
6092
6174
  path: z7.string().describe("Absolute or relative path to the file to send")
6093
- }),
6175
+ })),
6094
6176
  execute: async ({ path: path3 }) => {
6095
6177
  const resolved = isAbsolute7(path3) ? resolve10(path3) : resolve10(getCwd(), path3);
6096
6178
  const check = await permissions.checkFsAccess(resolved, "read");
@@ -6121,14 +6203,14 @@ function createSendFileTool(permissions, getCwd, sendFile) {
6121
6203
  }
6122
6204
 
6123
6205
  // src/capabilities/messaging/send-message.ts
6124
- import { tool as tool8 } from "ai";
6206
+ import { tool as tool8, zodSchema as zodSchema8 } from "ai";
6125
6207
  import { z as z8 } from "zod";
6126
6208
  function createSendMessageTool(sendMessage) {
6127
6209
  return tool8({
6128
6210
  description: "Send a message through the configured outbound channel. For Telegram this sends to the approved Telegram recipients. Use this only when the user explicitly asks you to send something to Telegram or asks for scheduled results to be sent there.",
6129
- parameters: z8.object({
6211
+ inputSchema: zodSchema8(z8.object({
6130
6212
  content: z8.string().describe("The message content to send to the approved Telegram recipients")
6131
- }),
6213
+ })),
6132
6214
  execute: async ({ content }) => {
6133
6215
  const trimmed = content.trim();
6134
6216
  if (!trimmed) {
@@ -6145,16 +6227,16 @@ function createSendMessageTool(sendMessage) {
6145
6227
  }
6146
6228
 
6147
6229
  // src/capabilities/filesystem/approve-scope.ts
6148
- import { tool as tool9 } from "ai";
6230
+ import { tool as tool9, zodSchema as zodSchema9 } from "ai";
6149
6231
  import { z as z9 } from "zod";
6150
6232
  import { resolve as resolve11, isAbsolute as isAbsolute8 } from "path";
6151
6233
  function createApproveScopeTool(permissions, getCwd) {
6152
6234
  return tool9({
6153
6235
  description: 'Request user approval to access a directory outside current scopes. Use this when a file tool returns a permission denied error. The user gets an approval prompt (Allow/Always/Deny buttons on Telegram, yes/always/no on CLI). "Allow" grants session-only access. "Always" persists to disk. After approval, retry the original file operation.',
6154
- parameters: z9.object({
6236
+ inputSchema: zodSchema9(z9.object({
6155
6237
  path: z9.string().describe("The directory path to request access to"),
6156
6238
  mode: z9.enum(["read", "write"]).describe("The access mode needed")
6157
- }),
6239
+ })),
6158
6240
  execute: async ({ path: path3, mode }) => {
6159
6241
  const resolved = isAbsolute8(path3) ? resolve11(path3) : resolve11(getCwd(), path3);
6160
6242
  const result = await permissions.requestScopeExternal(resolved, mode);
@@ -6167,7 +6249,7 @@ function createApproveScopeTool(permissions, getCwd) {
6167
6249
  }
6168
6250
 
6169
6251
  // src/capabilities/shell/run-command.ts
6170
- import { tool as tool10 } from "ai";
6252
+ import { tool as tool10, zodSchema as zodSchema10 } from "ai";
6171
6253
  import { z as z10 } from "zod";
6172
6254
  import { execSync } from "child_process";
6173
6255
  import { resolve as resolve12, isAbsolute as isAbsolute9 } from "path";
@@ -6178,20 +6260,13 @@ function createRunCommandTool(permissions, getCwd, setCwd) {
6178
6260
  description: `Run a shell command in the current working directory. Use the cd tool to change directories first \u2014 cd commands within this tool only affect chained commands (e.g., "cd /path && ls"), not subsequent calls.
6179
6261
  Blocked commands (sudo, rm -rf /, etc.) are never executed.
6180
6262
  Auto-approved commands (ls, cat, git status, curl, etc.) run without asking.
6181
- Other commands require user approval.`,
6182
- parameters: z10.object({
6263
+ Other commands prompt the user for approval before execution.`,
6264
+ inputSchema: zodSchema10(z10.object({
6183
6265
  command: z10.string().describe("The shell command to execute")
6184
- }),
6266
+ })),
6185
6267
  execute: async ({ command }) => {
6186
6268
  const check = await permissions.checkShellCommand(command);
6187
6269
  if (!check.allowed) {
6188
- if (check.needsApproval) {
6189
- const baseCmd = command.trim().split(/\s+/)[0];
6190
- permissions.addPendingApproval(baseCmd);
6191
- return `\u26A0 Command requires approval: ${command}
6192
-
6193
- Tell the user what this command does and ask for permission. If they approve, try running it again. If they say "always", use the approve_command tool to permanently approve this command type.`;
6194
- }
6195
6270
  return `Error: ${check.reason}`;
6196
6271
  }
6197
6272
  const cwd = getCwd();
@@ -6245,16 +6320,16 @@ function detectCd(command, currentCwd, setCwd) {
6245
6320
  }
6246
6321
 
6247
6322
  // src/capabilities/shell/cd.ts
6248
- import { tool as tool11 } from "ai";
6323
+ import { tool as tool11, zodSchema as zodSchema11 } from "ai";
6249
6324
  import { z as z11 } from "zod";
6250
6325
  import { resolve as resolve13, isAbsolute as isAbsolute10 } from "path";
6251
6326
  import { existsSync as existsSync15, statSync as statSync3 } from "fs";
6252
6327
  function createCdTool(getCwd, setCwd) {
6253
6328
  return tool11({
6254
6329
  description: "Change the current working directory. All subsequent file operations, shell commands, and git operations will use this directory. Use this before running commands in a specific project folder.",
6255
- parameters: z11.object({
6330
+ inputSchema: zodSchema11(z11.object({
6256
6331
  path: z11.string().describe("The directory to change to. Can be absolute or relative to the current directory.")
6257
- }),
6332
+ })),
6258
6333
  execute: async ({ path: path3 }) => {
6259
6334
  const cwd = getCwd();
6260
6335
  const resolved = isAbsolute10(path3) ? resolve13(path3) : resolve13(cwd, path3);
@@ -6276,14 +6351,14 @@ function createCdTool(getCwd, setCwd) {
6276
6351
  }
6277
6352
 
6278
6353
  // src/capabilities/shell/approve-command.ts
6279
- import { tool as tool12 } from "ai";
6354
+ import { tool as tool12, zodSchema as zodSchema12 } from "ai";
6280
6355
  import { z as z12 } from "zod";
6281
6356
  function createApproveCommandTool(permissions) {
6282
6357
  return tool12({
6283
6358
  description: 'Permanently approve a command type so it runs without asking in the future. Use this when the user says "always" or "always approve" for a command. For example, if the user says "always approve curl", call this with command="curl".',
6284
- parameters: z12.object({
6359
+ inputSchema: zodSchema12(z12.object({
6285
6360
  command: z12.string().describe('The base command to permanently approve (e.g. "curl", "docker", "npm")')
6286
- }),
6361
+ })),
6287
6362
  execute: async ({ command }) => {
6288
6363
  const baseCmd = command.trim().split(/\s+/)[0];
6289
6364
  permissions.addApprovedCommand(baseCmd);
@@ -6293,16 +6368,16 @@ function createApproveCommandTool(permissions) {
6293
6368
  }
6294
6369
 
6295
6370
  // src/capabilities/skills/install-skill.ts
6296
- import { tool as tool13 } from "ai";
6371
+ import { tool as tool13, zodSchema as zodSchema13 } from "ai";
6297
6372
  import { z as z13 } from "zod";
6298
6373
  import { parse as parseYaml4 } from "yaml";
6299
6374
  function createInstallSkillTool(skillLoader) {
6300
6375
  return tool13({
6301
6376
  description: "Install a new skill by providing SKILL.md markdown content or a URL. The content must have YAML frontmatter (---) with at least name and description fields.",
6302
- parameters: z13.object({
6377
+ inputSchema: zodSchema13(z13.object({
6303
6378
  content: z13.string().optional().describe("Raw SKILL.md markdown content with YAML frontmatter"),
6304
6379
  url: z13.string().optional().describe("URL to fetch a SKILL.md from")
6305
- }),
6380
+ })),
6306
6381
  execute: async ({ content, url }) => {
6307
6382
  let skillContent;
6308
6383
  if (url && !content) {
@@ -6341,12 +6416,12 @@ function createInstallSkillTool(skillLoader) {
6341
6416
  }
6342
6417
 
6343
6418
  // src/capabilities/skills/list-skills.ts
6344
- import { tool as tool14 } from "ai";
6419
+ import { tool as tool14, zodSchema as zodSchema14 } from "ai";
6345
6420
  import { z as z14 } from "zod";
6346
6421
  function createListSkillsTool(skillLoader) {
6347
6422
  return tool14({
6348
6423
  description: "List all installed skills with their names and descriptions.",
6349
- parameters: z14.object({}),
6424
+ inputSchema: zodSchema14(z14.object({})),
6350
6425
  execute: async () => {
6351
6426
  const skills = skillLoader.getDiscovered();
6352
6427
  if (skills.length === 0) {
@@ -6358,14 +6433,14 @@ function createListSkillsTool(skillLoader) {
6358
6433
  }
6359
6434
 
6360
6435
  // src/capabilities/skills/use-skill.ts
6361
- import { tool as tool15 } from "ai";
6436
+ import { tool as tool15, zodSchema as zodSchema15 } from "ai";
6362
6437
  import { z as z15 } from "zod";
6363
6438
  function createUseSkillTool(skillLoader, permissions) {
6364
6439
  return tool15({
6365
6440
  description: "Load and invoke a skill by name. Returns the skill's full instructions which should be followed as guidance for the current task.",
6366
- parameters: z15.object({
6441
+ inputSchema: zodSchema15(z15.object({
6367
6442
  name: z15.string().describe("Name of the skill to invoke")
6368
- }),
6443
+ })),
6369
6444
  execute: async ({ name }) => {
6370
6445
  const skill = skillLoader.load(name);
6371
6446
  if (!skill) {
@@ -6391,19 +6466,19 @@ Allowed tools: ${skill["allowed-tools"].join(", ")}`;
6391
6466
  }
6392
6467
 
6393
6468
  // src/capabilities/scheduler/schedule-task.ts
6394
- import { tool as tool16 } from "ai";
6469
+ import { tool as tool16, zodSchema as zodSchema16 } from "ai";
6395
6470
  import { z as z16 } from "zod";
6396
6471
  import cron2 from "node-cron";
6397
6472
  function createScheduleTaskTool(scheduler, getContext) {
6398
6473
  return tool16({
6399
6474
  description: 'Schedule a task. Use "cron" for recurring tasks (e.g. "0 9 * * *" for daily at 9am) or "delay_seconds" for one-shot delayed tasks (e.g. 15 for "remind me in 15 seconds"). Provide exactly one of cron or delay_seconds.',
6400
- parameters: z16.object({
6475
+ inputSchema: zodSchema16(z16.object({
6401
6476
  cron: z16.string().optional().describe('Cron expression for recurring tasks (e.g. "0 9 * * *" for daily at 9am)'),
6402
6477
  delay_seconds: z16.number().optional().describe('Delay in seconds for one-shot tasks (e.g. 15 for "remind me in 15 seconds")'),
6403
6478
  description: z16.string().describe("Human-readable description of what this task does"),
6404
6479
  prompt: z16.string().optional().describe("Prompt to send to the agent when the task fires"),
6405
6480
  skill_name: z16.string().optional().describe("Name of a skill to invoke when the task fires")
6406
- }),
6481
+ })),
6407
6482
  execute: async ({ cron: cronExpr, delay_seconds, description, prompt, skill_name }) => {
6408
6483
  if (!cronExpr && !delay_seconds) {
6409
6484
  return "Either cron or delay_seconds must be provided.";
@@ -6455,12 +6530,12 @@ function createScheduleTaskTool(scheduler, getContext) {
6455
6530
  }
6456
6531
 
6457
6532
  // src/capabilities/scheduler/list-tasks.ts
6458
- import { tool as tool17 } from "ai";
6533
+ import { tool as tool17, zodSchema as zodSchema17 } from "ai";
6459
6534
  import { z as z17 } from "zod";
6460
6535
  function createListTasksTool(scheduler) {
6461
6536
  return tool17({
6462
6537
  description: "List all scheduled tasks with their cron expressions and descriptions.",
6463
- parameters: z17.object({}),
6538
+ inputSchema: zodSchema17(z17.object({})),
6464
6539
  execute: async () => {
6465
6540
  const manifests = scheduler.getManifests();
6466
6541
  if (manifests.length === 0) {
@@ -6475,14 +6550,14 @@ function createListTasksTool(scheduler) {
6475
6550
  }
6476
6551
 
6477
6552
  // src/capabilities/scheduler/cancel-task.ts
6478
- import { tool as tool18 } from "ai";
6553
+ import { tool as tool18, zodSchema as zodSchema18 } from "ai";
6479
6554
  import { z as z18 } from "zod";
6480
6555
  function createCancelTaskTool(scheduler) {
6481
6556
  return tool18({
6482
6557
  description: "Cancel and remove a scheduled task by its ID.",
6483
- parameters: z18.object({
6558
+ inputSchema: zodSchema18(z18.object({
6484
6559
  id: z18.string().describe("ID of the scheduled task to cancel")
6485
- }),
6560
+ })),
6486
6561
  execute: async ({ id }) => {
6487
6562
  const manifests = scheduler.getManifests();
6488
6563
  const exists = manifests.some((m) => m.id === id);
@@ -6497,12 +6572,12 @@ function createCancelTaskTool(scheduler) {
6497
6572
  }
6498
6573
 
6499
6574
  // src/capabilities/system/budget-status.ts
6500
- import { tool as tool19 } from "ai";
6575
+ import { tool as tool19, zodSchema as zodSchema19 } from "ai";
6501
6576
  import { z as z19 } from "zod";
6502
6577
  function createBudgetStatusTool(tokenBudget) {
6503
6578
  return tool19({
6504
6579
  description: "Check the current token budget status \u2014 how many tokens have been used today, how many remain, and what percentage is consumed.",
6505
- parameters: z19.object({}),
6580
+ inputSchema: zodSchema19(z19.object({})),
6506
6581
  execute: async () => {
6507
6582
  return tokenBudget.getStatusText();
6508
6583
  }
@@ -6510,15 +6585,15 @@ function createBudgetStatusTool(tokenBudget) {
6510
6585
  }
6511
6586
 
6512
6587
  // src/capabilities/git/git-status.ts
6513
- import { tool as tool20 } from "ai";
6588
+ import { tool as tool20, zodSchema as zodSchema20 } from "ai";
6514
6589
  import { z as z20 } from "zod";
6515
6590
  import { execSync as execSync2 } from "child_process";
6516
6591
  function createGitStatusTool(getCwd) {
6517
6592
  return tool20({
6518
6593
  description: "Show the working tree status. Returns staged, unstaged, and untracked files.",
6519
- parameters: z20.object({
6594
+ inputSchema: zodSchema20(z20.object({
6520
6595
  path: z20.string().optional().describe("Path to check (defaults to current directory)")
6521
- }),
6596
+ })),
6522
6597
  execute: async ({ path: path3 }) => {
6523
6598
  try {
6524
6599
  const cmd = path3 ? `git -C "${path3}" status --porcelain` : "git status --porcelain";
@@ -6533,16 +6608,16 @@ function createGitStatusTool(getCwd) {
6533
6608
  }
6534
6609
 
6535
6610
  // src/capabilities/git/git-diff.ts
6536
- import { tool as tool21 } from "ai";
6611
+ import { tool as tool21, zodSchema as zodSchema21 } from "ai";
6537
6612
  import { z as z21 } from "zod";
6538
6613
  import { execSync as execSync3 } from "child_process";
6539
6614
  function createGitDiffTool(getCwd) {
6540
6615
  return tool21({
6541
6616
  description: "Show changes between commits, commit and working tree, etc. Shows what has been modified.",
6542
- parameters: z21.object({
6617
+ inputSchema: zodSchema21(z21.object({
6543
6618
  path: z21.string().optional().describe("File or directory to diff"),
6544
6619
  staged: z21.boolean().optional().describe("Show staged changes (cached) instead of unstaged")
6545
- }),
6620
+ })),
6546
6621
  execute: async ({ path: path3, staged }) => {
6547
6622
  try {
6548
6623
  let cmd = "git diff";
@@ -6560,16 +6635,16 @@ function createGitDiffTool(getCwd) {
6560
6635
  }
6561
6636
 
6562
6637
  // src/capabilities/git/git-log.ts
6563
- import { tool as tool22 } from "ai";
6638
+ import { tool as tool22, zodSchema as zodSchema22 } from "ai";
6564
6639
  import { z as z22 } from "zod";
6565
6640
  import { execSync as execSync4 } from "child_process";
6566
6641
  function createGitLogTool(getCwd) {
6567
6642
  return tool22({
6568
6643
  description: "Show commit logs. Returns recent commit history with hash, author, date, and message.",
6569
- parameters: z22.object({
6644
+ inputSchema: zodSchema22(z22.object({
6570
6645
  count: z22.number().optional().describe("Number of commits to show (default 10)"),
6571
6646
  path: z22.string().optional().describe("File or directory to show log for")
6572
- }),
6647
+ })),
6573
6648
  execute: async ({ count, path: path3 }) => {
6574
6649
  try {
6575
6650
  const n = count ?? 10;
@@ -6586,15 +6661,15 @@ function createGitLogTool(getCwd) {
6586
6661
  }
6587
6662
 
6588
6663
  // src/capabilities/git/git-add.ts
6589
- import { tool as tool23 } from "ai";
6664
+ import { tool as tool23, zodSchema as zodSchema23 } from "ai";
6590
6665
  import { z as z23 } from "zod";
6591
6666
  import { execSync as execSync5 } from "child_process";
6592
6667
  function createGitAddTool(getCwd) {
6593
6668
  return tool23({
6594
6669
  description: "Add file contents to the index (staging area). Prepares files for commit.",
6595
- parameters: z23.object({
6670
+ inputSchema: zodSchema23(z23.object({
6596
6671
  paths: z23.array(z23.string()).describe("File paths to stage")
6597
- }),
6672
+ })),
6598
6673
  execute: async ({ paths }) => {
6599
6674
  try {
6600
6675
  const fileArgs = paths.map((p) => `"${p}"`).join(" ");
@@ -6608,7 +6683,7 @@ function createGitAddTool(getCwd) {
6608
6683
  }
6609
6684
 
6610
6685
  // src/capabilities/git/git-commit.ts
6611
- import { tool as tool24 } from "ai";
6686
+ import { tool as tool24, zodSchema as zodSchema24 } from "ai";
6612
6687
  import { z as z24 } from "zod";
6613
6688
  import { execSync as execSync6 } from "child_process";
6614
6689
  import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync3 } from "fs";
@@ -6617,9 +6692,9 @@ var CO_AUTHOR = "Mercury <mercury@cosmicstack.org>";
6617
6692
  function createGitCommitTool(getCwd) {
6618
6693
  return tool24({
6619
6694
  description: "Record changes to the repository. Creates a new commit with staged changes. Automatically includes a Co-authored-by trailer for attribution.",
6620
- parameters: z24.object({
6695
+ inputSchema: zodSchema24(z24.object({
6621
6696
  message: z24.string().describe("Commit message")
6622
- }),
6697
+ })),
6623
6698
  execute: async ({ message }) => {
6624
6699
  try {
6625
6700
  const fullMessage = `${message}
@@ -6654,25 +6729,19 @@ Co-authored-by: ${CO_AUTHOR}`;
6654
6729
  }
6655
6730
 
6656
6731
  // src/capabilities/git/git-push.ts
6657
- import { tool as tool25 } from "ai";
6732
+ import { tool as tool25, zodSchema as zodSchema25 } from "ai";
6658
6733
  import { z as z25 } from "zod";
6659
6734
  import { execSync as execSync7 } from "child_process";
6660
6735
  function createGitPushTool(permissions, getCwd) {
6661
6736
  return tool25({
6662
6737
  description: "Push commits to a remote repository. This modifies a remote and requires approval.",
6663
- parameters: z25.object({
6738
+ inputSchema: zodSchema25(z25.object({
6664
6739
  remote: z25.string().optional().describe("Remote name (default: origin)"),
6665
6740
  branch: z25.string().optional().describe("Branch name (default: current branch)")
6666
- }),
6741
+ })),
6667
6742
  execute: async ({ remote, branch }) => {
6668
6743
  const cmd = `git push ${remote || "origin"} ${branch || ""}`.trim();
6669
6744
  const check = await permissions.checkShellCommand(cmd);
6670
- if (!check.allowed && check.needsApproval) {
6671
- const baseCmd = "git";
6672
- permissions.addPendingApproval(baseCmd);
6673
- return `\u26A0 This command pushes to a remote: ${cmd}
6674
- Ask the user for permission. If they approve, try again. If they say "always", use the approve_command tool.`;
6675
- }
6676
6745
  if (!check.allowed) {
6677
6746
  return `Error: ${check.reason}`;
6678
6747
  }
@@ -6687,7 +6756,7 @@ Ask the user for permission. If they approve, try again. If they say "always", u
6687
6756
  }
6688
6757
 
6689
6758
  // src/capabilities/github/create-pr.ts
6690
- import { tool as tool26 } from "ai";
6759
+ import { tool as tool26, zodSchema as zodSchema26 } from "ai";
6691
6760
  import { z as z26 } from "zod";
6692
6761
 
6693
6762
  // src/utils/github.ts
@@ -6745,7 +6814,7 @@ async function githubRequest(path3, options = {}) {
6745
6814
  function createCreatePrTool() {
6746
6815
  return tool26({
6747
6816
  description: "Create a pull request on GitHub. Requires GITHUB_TOKEN to be configured.",
6748
- parameters: z26.object({
6817
+ inputSchema: zodSchema26(z26.object({
6749
6818
  owner: z26.string().describe("Repository owner (username or org)"),
6750
6819
  repo: z26.string().describe("Repository name"),
6751
6820
  title: z26.string().describe("PR title"),
@@ -6753,7 +6822,7 @@ function createCreatePrTool() {
6753
6822
  head: z26.string().describe("The branch containing the changes"),
6754
6823
  base: z26.string().describe("The branch to merge into").default("main"),
6755
6824
  draft: z26.boolean().describe("Create as draft PR").default(false)
6756
- }),
6825
+ })),
6757
6826
  execute: async ({ owner, repo, title, body, head, base, draft }) => {
6758
6827
  try {
6759
6828
  const result = await githubRequest(`/repos/${owner}/${repo}/pulls`, {
@@ -6771,17 +6840,17 @@ ${draft ? "(draft)" : ""} ${result.state}`;
6771
6840
  }
6772
6841
 
6773
6842
  // src/capabilities/github/review-pr.ts
6774
- import { tool as tool27 } from "ai";
6843
+ import { tool as tool27, zodSchema as zodSchema27 } from "ai";
6775
6844
  import { z as z27 } from "zod";
6776
6845
  function createReviewPrTool() {
6777
6846
  return tool27({
6778
6847
  description: "Get details of a pull request including the diff. Reviews the PR and returns the title, body, changed files, and diff. Optionally post a review comment.",
6779
- parameters: z27.object({
6848
+ inputSchema: zodSchema27(z27.object({
6780
6849
  owner: z27.string().describe("Repository owner (username or org)"),
6781
6850
  repo: z27.string().describe("Repository name"),
6782
6851
  number: z27.number().describe("PR number"),
6783
6852
  comment: z27.string().describe("Review comment to post on the PR (optional)").optional()
6784
- }),
6853
+ })),
6785
6854
  execute: async ({ owner, repo, number, comment }) => {
6786
6855
  try {
6787
6856
  const pr = await githubRequest(`/repos/${owner}/${repo}/pulls/${number}`);
@@ -6846,18 +6915,18 @@ Failed to post review comment: ${err.message}`;
6846
6915
  }
6847
6916
 
6848
6917
  // src/capabilities/github/list-issues.ts
6849
- import { tool as tool28 } from "ai";
6918
+ import { tool as tool28, zodSchema as zodSchema28 } from "ai";
6850
6919
  import { z as z28 } from "zod";
6851
6920
  function createListIssuesTool() {
6852
6921
  return tool28({
6853
6922
  description: "List GitHub issues for a repository. Requires GITHUB_TOKEN.",
6854
- parameters: z28.object({
6923
+ inputSchema: zodSchema28(z28.object({
6855
6924
  owner: z28.string().describe("Repository owner (username or org)"),
6856
6925
  repo: z28.string().describe("Repository name"),
6857
6926
  state: z28.enum(["open", "closed", "all"]).describe("Filter by issue state").default("open"),
6858
6927
  labels: z28.string().describe("Comma-separated label names to filter by (optional)").optional(),
6859
6928
  limit: z28.number().describe("Maximum number of issues to return").default(10)
6860
- }),
6929
+ })),
6861
6930
  execute: async ({ owner, repo, state, labels, limit }) => {
6862
6931
  try {
6863
6932
  const params = new URLSearchParams();
@@ -6884,18 +6953,18 @@ ${lines.join("\n")}`;
6884
6953
  }
6885
6954
 
6886
6955
  // src/capabilities/github/create-issue.ts
6887
- import { tool as tool29 } from "ai";
6956
+ import { tool as tool29, zodSchema as zodSchema29 } from "ai";
6888
6957
  import { z as z29 } from "zod";
6889
6958
  function createCreateIssueTool() {
6890
6959
  return tool29({
6891
6960
  description: "Create a new GitHub issue in a repository. Requires GITHUB_TOKEN.",
6892
- parameters: z29.object({
6961
+ inputSchema: zodSchema29(z29.object({
6893
6962
  owner: z29.string().describe("Repository owner (username or org)"),
6894
6963
  repo: z29.string().describe("Repository name"),
6895
6964
  title: z29.string().describe("Issue title"),
6896
6965
  body: z29.string().describe("Issue description (markdown supported)").default(""),
6897
6966
  labels: z29.array(z29.string()).describe("Label names to apply").optional()
6898
- }),
6967
+ })),
6899
6968
  execute: async ({ owner, repo, title, body, labels }) => {
6900
6969
  try {
6901
6970
  const payload = { title, body };
@@ -6914,7 +6983,7 @@ function createCreateIssueTool() {
6914
6983
  }
6915
6984
 
6916
6985
  // src/capabilities/github/github-api.ts
6917
- import { tool as tool30 } from "ai";
6986
+ import { tool as tool30, zodSchema as zodSchema30 } from "ai";
6918
6987
  import { z as z30 } from "zod";
6919
6988
  var CO_AUTHOR_NAME = "Mercury";
6920
6989
  var CO_AUTHOR_EMAIL = "mercury@cosmicstack.org";
@@ -6950,11 +7019,11 @@ Common operations you can perform:
6950
7019
  - Any other GitHub API v3 endpoint.
6951
7020
 
6952
7021
  IMPORTANT: When the user wants to push code or files to GitHub and git push fails (auth issues, no SSH key, etc.), use PUT /repos/{owner}/{repo}/contents/{path} to create or update files directly through the API. This bypasses local git and creates a commit with Mercury as co-author.`,
6953
- parameters: z30.object({
7022
+ inputSchema: zodSchema30(z30.object({
6954
7023
  path: z30.string().describe("Full API path (e.g., /repos/owner/repo/issues or /repos/owner/repo/contents/path/to/file)"),
6955
7024
  method: z30.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method").default("GET"),
6956
7025
  body: z30.string().describe("JSON body for write requests (as a JSON string)").optional()
6957
- }),
7026
+ })),
6958
7027
  execute: async ({ path: path3, method, body }) => {
6959
7028
  try {
6960
7029
  let parsedBody;
@@ -6983,7 +7052,7 @@ IMPORTANT: When the user wants to push code or files to GitHub and git push fail
6983
7052
  }
6984
7053
 
6985
7054
  // src/capabilities/web/fetch-url.ts
6986
- import { tool as tool31 } from "ai";
7055
+ import { tool as tool31, zodSchema as zodSchema31 } from "ai";
6987
7056
  import { z as z31 } from "zod";
6988
7057
  var MAX_CONTENT_LENGTH = 15e3;
6989
7058
  function stripHtml(html) {
@@ -7019,10 +7088,10 @@ function stripHtml(html) {
7019
7088
  function createFetchUrlTool() {
7020
7089
  return tool31({
7021
7090
  description: "Fetch a URL and return its content as text. Strips HTML to readable markdown-like format. Useful for reading documentation, APIs, or web pages.",
7022
- parameters: z31.object({
7091
+ inputSchema: zodSchema31(z31.object({
7023
7092
  url: z31.string().describe("The URL to fetch"),
7024
7093
  format: z31.enum(["text", "markdown"]).optional().describe("Output format (default: markdown)")
7025
- }),
7094
+ })),
7026
7095
  execute: async ({ url, format }) => {
7027
7096
  const outputFormat = format ?? "markdown";
7028
7097
  try {