sparkecoder 0.1.87 → 0.1.94

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.
Files changed (125) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/index.d.ts +3 -3
  3. package/dist/agent/index.js +158 -68
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/cli.js +416 -108
  6. package/dist/cli.js.map +1 -1
  7. package/dist/db/index.d.ts +2 -2
  8. package/dist/{index-BvIissiB.d.ts → index-C7Kkn5vq.d.ts} +29 -29
  9. package/dist/index.d.ts +5 -5
  10. package/dist/index.js +272 -97
  11. package/dist/index.js.map +1 -1
  12. package/dist/{schema-CohdIL13.d.ts → schema-D7BJyHLl.d.ts} +3 -3
  13. package/dist/{search-CCffrVJE.d.ts → search-CVVfuBPZ.d.ts} +4 -4
  14. package/dist/server/index.js +272 -97
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/tools/index.d.ts +31 -4
  17. package/dist/tools/index.js +38 -4
  18. package/dist/tools/index.js.map +1 -1
  19. package/package.json +5 -5
  20. package/web/.next/BUILD_ID +1 -1
  21. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  22. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  23. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  24. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  25. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  27. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +3 -3
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +3 -3
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +2 -2
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +3 -3
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +3 -3
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +3 -3
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +3 -3
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs.rsc +3 -3
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +3 -3
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +2 -2
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +2 -2
  81. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
  84. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  85. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  86. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  87. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__36edac7c._.js +1 -1
  91. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__be5e2967._.js +1 -1
  92. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_page_tsx_5ac4794b._.js +1 -1
  93. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  94. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  95. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  96. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  97. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  98. package/web/.next/{static/chunks/26eb5fab5216f3cc.js → standalone/web/.next/static/chunks/58fd0aaa2746b444.js} +1 -1
  99. package/web/.next/standalone/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
  100. package/web/.next/standalone/web/.next/static/chunks/{8d3efc76109d2efc.js → a888d448ceab1abe.js} +1 -1
  101. package/web/.next/standalone/web/.next/static/static/chunks/{26eb5fab5216f3cc.js → 58fd0aaa2746b444.js} +1 -1
  102. package/web/.next/standalone/web/.next/static/static/chunks/9fce2ce79c4c834e.js +1 -0
  103. package/web/.next/{static/chunks/8d3efc76109d2efc.js → standalone/web/.next/static/static/chunks/a888d448ceab1abe.js} +1 -1
  104. package/web/.next/standalone/web/package-lock.json +27 -27
  105. package/web/.next/standalone/web/package.json +1 -1
  106. package/web/.next/standalone/web/src/app/(main)/page.tsx +2 -2
  107. package/web/.next/standalone/web/src/app/api/config/route.ts +3 -2
  108. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +1 -1
  109. package/web/.next/standalone/web/src/lib/config.ts +2 -1
  110. package/web/.next/{standalone/web/.next/static/chunks/26eb5fab5216f3cc.js → static/chunks/58fd0aaa2746b444.js} +1 -1
  111. package/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
  112. package/web/.next/{standalone/web/.next/static/static/chunks/8d3efc76109d2efc.js → static/chunks/a888d448ceab1abe.js} +1 -1
  113. package/web/package.json +1 -1
  114. package/web/.next/standalone/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
  115. package/web/.next/standalone/web/.next/static/static/chunks/b31b0765abe0c427.js +0 -1
  116. package/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
  117. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
  118. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
  119. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
  120. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
  121. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
  122. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
  123. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_buildManifest.js +0 -0
  124. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_clientMiddlewareManifest.json +0 -0
  125. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → glGjCSPew_3EV65tkHmVO}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -139,7 +139,7 @@ Create a `sparkecoder.config.json` file:
139
139
 
140
140
  | Option | Description | Default |
141
141
  |--------|-------------|---------|
142
- | `defaultModel` | Vercel AI Gateway model string | `anthropic/claude-opus-4-6` |
142
+ | `defaultModel` | Vercel AI Gateway model string | `anthropic/claude-opus-4.7` |
143
143
  | `workingDirectory` | Base directory for file operations | Current directory |
144
144
  | `toolApprovals` | Which tools require user approval | `{ bash: true }` |
145
145
  | `skills.directory` | Directory containing skill files | `./skills` |
@@ -1,6 +1,6 @@
1
1
  import 'ai';
2
- import '../schema-CohdIL13.js';
3
- export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, C as ContextManager, M as MessageAttachment, d as buildSystemPrompt, e as buildTaskPromptAddendum } from '../index-BvIissiB.js';
4
- import '../search-CCffrVJE.js';
2
+ import '../schema-D7BJyHLl.js';
3
+ export { A as Agent, a as AgentOptions, b as AgentRunOptions, c as AgentStreamResult, C as ContextManager, M as MessageAttachment, d as buildSystemPrompt, e as buildTaskPromptAddendum } from '../index-C7Kkn5vq.js';
4
+ import '../search-CVVfuBPZ.js';
5
5
  import 'drizzle-orm/sqlite-core';
6
6
  import 'zod';
@@ -107,7 +107,7 @@ var init_types = __esm({
107
107
  }).optional();
108
108
  SparkcoderConfigSchema = z.object({
109
109
  // Default model to use (Vercel AI Gateway format)
110
- defaultModel: z.string().default("anthropic/claude-opus-4-6"),
110
+ defaultModel: z.string().default("anthropic/claude-opus-4.7"),
111
111
  // Working directory for file operations
112
112
  workingDirectory: z.string().optional(),
113
113
  // Tool approval settings
@@ -225,9 +225,9 @@ __export(remote_exports, {
225
225
  remoteToolExecutionQueries: () => remoteToolExecutionQueries,
226
226
  storageQueries: () => storageQueries
227
227
  });
228
- function initRemoteDatabase(serverUrl, key) {
228
+ function initRemoteDatabase(serverUrl, key2) {
229
229
  remoteServerUrl = serverUrl.replace(/\/$/, "");
230
- authKey = key;
230
+ authKey = key2;
231
231
  }
232
232
  function closeRemoteDatabase() {
233
233
  remoteServerUrl = null;
@@ -241,14 +241,14 @@ function parseDates(obj) {
241
241
  if (Array.isArray(obj)) return obj.map(parseDates);
242
242
  if (typeof obj !== "object" || obj instanceof Date) return obj;
243
243
  const result = { ...obj };
244
- for (const key of Object.keys(result)) {
245
- if (MODEL_MESSAGE_FIELDS.includes(key)) {
244
+ for (const key2 of Object.keys(result)) {
245
+ if (MODEL_MESSAGE_FIELDS.includes(key2)) {
246
246
  continue;
247
247
  }
248
- if (DATE_FIELDS.includes(key) && typeof result[key] === "string") {
249
- result[key] = new Date(result[key]);
250
- } else if (typeof result[key] === "object") {
251
- result[key] = parseDates(result[key]);
248
+ if (DATE_FIELDS.includes(key2) && typeof result[key2] === "string") {
249
+ result[key2] = new Date(result[key2]);
250
+ } else if (typeof result[key2] === "object") {
251
+ result[key2] = parseDates(result[key2]);
252
252
  }
253
253
  }
254
254
  return result;
@@ -729,10 +729,10 @@ function parseSkillFrontmatter(content) {
729
729
  }
730
730
  const colonIndex = line.indexOf(":");
731
731
  if (colonIndex > 0) {
732
- const key = line.slice(0, colonIndex).trim();
732
+ const key2 = line.slice(0, colonIndex).trim();
733
733
  let value = line.slice(colonIndex + 1).trim();
734
734
  if (value === "" || value === "[]") {
735
- currentArrayKey = key;
735
+ currentArrayKey = key2;
736
736
  currentArray = [];
737
737
  continue;
738
738
  }
@@ -745,18 +745,18 @@ function parseSkillFrontmatter(content) {
745
745
  }
746
746
  return trimmed;
747
747
  }).filter((item) => item.length > 0);
748
- data[key] = items;
748
+ data[key2] = items;
749
749
  continue;
750
750
  }
751
751
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
752
752
  value = value.slice(1, -1);
753
753
  }
754
754
  if (value === "true") {
755
- data[key] = true;
755
+ data[key2] = true;
756
756
  } else if (value === "false") {
757
- data[key] = false;
757
+ data[key2] = false;
758
758
  } else {
759
- data[key] = value;
759
+ data[key2] = value;
760
760
  }
761
761
  }
762
762
  }
@@ -1088,9 +1088,9 @@ var init_chunker = __esm({
1088
1088
  });
1089
1089
 
1090
1090
  // src/semantic/client.ts
1091
- function initVectorClient(serverUrl, key) {
1091
+ function initVectorClient(serverUrl, key2) {
1092
1092
  remoteServerUrl2 = serverUrl.replace(/\/$/, "");
1093
- authKey2 = key;
1093
+ authKey2 = key2;
1094
1094
  }
1095
1095
  function isVectorClientConfigured() {
1096
1096
  return !!remoteServerUrl2 && !!authKey2;
@@ -1636,7 +1636,7 @@ import { promisify as promisify6 } from "util";
1636
1636
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
1637
1637
  import { join as join9 } from "path";
1638
1638
  import { tmpdir as tmpdir2 } from "os";
1639
- import { nanoid as nanoid4 } from "nanoid";
1639
+ import { nanoid as nanoid5 } from "nanoid";
1640
1640
  async function checkFfmpeg() {
1641
1641
  try {
1642
1642
  await execAsync6("ffmpeg -version", { timeout: 5e3 });
@@ -1691,7 +1691,7 @@ var init_recorder = __esm({
1691
1691
  */
1692
1692
  async encode() {
1693
1693
  if (this.frames.length === 0) return null;
1694
- const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid4(8)}`);
1694
+ const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid5(8)}`);
1695
1695
  await mkdir4(workDir, { recursive: true });
1696
1696
  try {
1697
1697
  for (let i = 0; i < this.frames.length; i++) {
@@ -1911,6 +1911,23 @@ function isAnthropicModel(modelId) {
1911
1911
  const normalized = modelId.trim().toLowerCase();
1912
1912
  return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
1913
1913
  }
1914
+ function requiresAdaptiveThinking(modelId) {
1915
+ const m = modelId.toLowerCase().match(/claude-(?:opus|sonnet|haiku)-(\d+)[.-](\d{1,2})(?!\d)/);
1916
+ if (!m) return false;
1917
+ const major = Number(m[1]);
1918
+ const minor = Number(m[2]);
1919
+ if (Number.isNaN(major) || Number.isNaN(minor)) return false;
1920
+ if (major > 4) return true;
1921
+ if (major === 4 && minor >= 6) return true;
1922
+ return false;
1923
+ }
1924
+ function getAnthropicProviderOptions(modelId, opts = {}) {
1925
+ const { toolStreaming, budgetTokens = 1e4 } = opts;
1926
+ const thinking = requiresAdaptiveThinking(modelId) ? { type: "adaptive" } : { type: "enabled", budgetTokens };
1927
+ const out = { thinking };
1928
+ if (toolStreaming) out.toolStreaming = true;
1929
+ return out;
1930
+ }
1914
1931
  function resolveModel(modelId) {
1915
1932
  try {
1916
1933
  const config = getConfig();
@@ -1934,7 +1951,7 @@ var SUBAGENT_MODELS = {
1934
1951
  init_db();
1935
1952
  init_config();
1936
1953
  import { z as z15 } from "zod";
1937
- import { nanoid as nanoid5 } from "nanoid";
1954
+ import { nanoid as nanoid6 } from "nanoid";
1938
1955
 
1939
1956
  // src/tools/bash.ts
1940
1957
  import { tool } from "ai";
@@ -2219,11 +2236,11 @@ async function sendInput(terminalId, input, options = {}) {
2219
2236
  return false;
2220
2237
  }
2221
2238
  }
2222
- async function sendKey(terminalId, key) {
2239
+ async function sendKey(terminalId, key2) {
2223
2240
  const session = getSessionName(terminalId);
2224
2241
  try {
2225
2242
  await execAsync(`tmux has-session -t ${session}`, { timeout: 1e3 });
2226
- await execAsync(`tmux send-keys -t ${session} ${key}`, { timeout: 1e3 });
2243
+ await execAsync(`tmux send-keys -t ${session} ${key2}`, { timeout: 1e3 });
2227
2244
  return true;
2228
2245
  } catch {
2229
2246
  return false;
@@ -2362,7 +2379,7 @@ bash({ id: "abc123", input: "my text" }) // send text input
2362
2379
  Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.`,
2363
2380
  inputSchema: bashInputSchema,
2364
2381
  execute: async (inputArgs) => {
2365
- const { command, background, id, kill, tail, input: textInput, key } = inputArgs;
2382
+ const { command, background, id, kill, tail, input: textInput, key: key2 } = inputArgs;
2366
2383
  if (id) {
2367
2384
  if (kill) {
2368
2385
  const success = await killTerminal(id);
@@ -2393,8 +2410,8 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
2393
2410
  message: `Sent input "${textInput}" to terminal`
2394
2411
  };
2395
2412
  }
2396
- if (key) {
2397
- const success = await sendKey(id, key);
2413
+ if (key2) {
2414
+ const success = await sendKey(id, key2);
2398
2415
  if (!success) {
2399
2416
  return {
2400
2417
  success: false,
@@ -2410,7 +2427,7 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
2410
2427
  id,
2411
2428
  output: truncatedOutput2,
2412
2429
  status: status2,
2413
- message: `Sent key "${key}" to terminal`
2430
+ message: `Sent key "${key2}" to terminal`
2414
2431
  };
2415
2432
  }
2416
2433
  const { output, status } = await getLogs(id, options.workingDirectory, { tail, sessionId: options.sessionId });
@@ -2552,13 +2569,13 @@ async function resizeImageIfNeeded(buffer, mediaType) {
2552
2569
  const needsResize = longEdge > MAX_LONG_EDGE;
2553
2570
  const needsShrink = buffer.length > MAX_FILE_BYTES;
2554
2571
  if (!needsResize && !needsShrink) return { buffer, mediaType: inputMediaType };
2555
- const key = cacheKey(buffer);
2572
+ const key2 = cacheKey(buffer);
2556
2573
  const cacheDir = getCacheDir();
2557
2574
  const isPng = inputMediaType.includes("png");
2558
2575
  const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
2559
2576
  const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
2560
2577
  const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
2561
- const cachePath = join3(cacheDir, key + ext);
2578
+ const cachePath = join3(cacheDir, key2 + ext);
2562
2579
  if (existsSync3(cachePath)) {
2563
2580
  console.log(`[image-resize] Cache hit for ${width}x${height} image`);
2564
2581
  return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
@@ -3313,31 +3330,31 @@ async function getClientForFile(filePath) {
3313
3330
  return null;
3314
3331
  }
3315
3332
  const root = dirname4(normalized);
3316
- const key = `${serverDef.id}:${root}`;
3317
- const existing = state.clients.get(key);
3333
+ const key2 = `${serverDef.id}:${root}`;
3334
+ const existing = state.clients.get(key2);
3318
3335
  if (existing) {
3319
3336
  return existing;
3320
3337
  }
3321
- if (state.broken.has(key)) {
3338
+ if (state.broken.has(key2)) {
3322
3339
  return null;
3323
3340
  }
3324
3341
  try {
3325
3342
  const handle = await serverDef.spawn(root);
3326
3343
  if (!handle) {
3327
- state.broken.add(key);
3344
+ state.broken.add(key2);
3328
3345
  return null;
3329
3346
  }
3330
3347
  console.log(`[lsp] Started ${serverDef.name} for ${root}`);
3331
3348
  const client = await createClient(serverDef.id, handle, root);
3332
- state.clients.set(key, client);
3349
+ state.clients.set(key2, client);
3333
3350
  handle.process.on("exit", (code) => {
3334
3351
  console.log(`[lsp] ${serverDef.name} exited with code ${code}`);
3335
- state.clients.delete(key);
3352
+ state.clients.delete(key2);
3336
3353
  });
3337
3354
  return client;
3338
3355
  } catch (error) {
3339
3356
  console.error(`[lsp] Failed to start ${serverDef.name}:`, error);
3340
- state.broken.add(key);
3357
+ state.broken.add(key2);
3341
3358
  return null;
3342
3359
  }
3343
3360
  }
@@ -5437,6 +5454,7 @@ init_semantic_search();
5437
5454
  import { tool as tool11 } from "ai";
5438
5455
  import { z as z12 } from "zod";
5439
5456
  import Ajv from "ajv";
5457
+ import { nanoid as nanoid3 } from "nanoid";
5440
5458
  var ajv = new Ajv({ allErrors: true });
5441
5459
  function createCompleteTaskTool(options) {
5442
5460
  const validate = ajv.compile(options.outputSchema);
@@ -5483,6 +5501,37 @@ function createTaskFailedTool(options) {
5483
5501
  }
5484
5502
  });
5485
5503
  }
5504
+ function createAskQuestionToUserTool(options) {
5505
+ return tool11({
5506
+ description: "Ask the user a blocking clarification question when you cannot safely continue without more information. Use this only after trying to infer the answer from the available context. The task will pause until the orchestrator or user answers.",
5507
+ inputSchema: z12.object({
5508
+ question: z12.string().min(1).describe("The concise question you need answered."),
5509
+ context: z12.string().optional().describe("Brief context explaining why this answer is needed and what you already tried."),
5510
+ choices: z12.array(z12.string().min(1)).max(10).optional().describe("Optional suggested answer choices when the question is multiple choice.")
5511
+ }),
5512
+ execute: async (input) => {
5513
+ if (!options.onQuestion) {
5514
+ return {
5515
+ status: "unavailable",
5516
+ message: "Question routing is not configured for this task. Continue with the best safe assumption or call task_failed if blocked."
5517
+ };
5518
+ }
5519
+ const questionId = `q_${nanoid3(12)}`;
5520
+ const answer = await options.onQuestion({
5521
+ questionId,
5522
+ question: input.question,
5523
+ context: input.context,
5524
+ choices: input.choices
5525
+ });
5526
+ return {
5527
+ status: "answered",
5528
+ questionId,
5529
+ answer: answer.answer,
5530
+ answeredBy: answer.answeredBy ?? "unknown"
5531
+ };
5532
+ }
5533
+ });
5534
+ }
5486
5535
 
5487
5536
  // src/tools/upload-file.ts
5488
5537
  import { tool as tool12 } from "ai";
@@ -5588,7 +5637,7 @@ import { promisify as promisify5 } from "util";
5588
5637
  import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
5589
5638
  import { join as join8 } from "path";
5590
5639
  import { tmpdir } from "os";
5591
- import { nanoid as nanoid3 } from "nanoid";
5640
+ import { nanoid as nanoid4 } from "nanoid";
5592
5641
  var execAsync5 = promisify5(exec5);
5593
5642
  var DEFAULT_WIDTH = 1280;
5594
5643
  var DEFAULT_HEIGHT = 800;
@@ -5712,9 +5761,9 @@ async function runScroll(dx, dy) {
5712
5761
  { timeout: 5e3 }
5713
5762
  );
5714
5763
  }
5715
- function translateKeyForCliclick(key) {
5716
- if (!key) return [];
5717
- const parts = key.split("+").map((p) => p.trim()).filter(Boolean);
5764
+ function translateKeyForCliclick(key2) {
5765
+ if (!key2) return [];
5766
+ const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
5718
5767
  if (parts.length === 0) return [];
5719
5768
  const modMap = {
5720
5769
  ctrl: "ctrl",
@@ -5810,7 +5859,7 @@ function createComputerUseTool(options) {
5810
5859
  try {
5811
5860
  switch (input.action) {
5812
5861
  case "screenshot": {
5813
- const path = join8(tmpdir(), `cu-${nanoid3(8)}.png`);
5862
+ const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
5814
5863
  await runScreencapture(path);
5815
5864
  const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
5816
5865
  try {
@@ -5941,7 +5990,7 @@ function createComputerUseTool(options) {
5941
5990
  case "zoom": {
5942
5991
  const region = input.region ?? [0, 0, displayWidth, displayHeight];
5943
5992
  const [x1, y1, x2, y2] = region;
5944
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid3(8)}.png`);
5993
+ const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
5945
5994
  await runScreencapture(tmpPath);
5946
5995
  const sharpModule = await import("sharp");
5947
5996
  const sharp2 = sharpModule.default || sharpModule;
@@ -6220,6 +6269,7 @@ async function createTools(options) {
6220
6269
  if (options.taskTools) {
6221
6270
  tools.complete_task = createCompleteTaskTool(options.taskTools);
6222
6271
  tools.task_failed = createTaskFailedTool(options.taskTools);
6272
+ tools.ask_question_to_user = createAskQuestionToUserTool(options.taskTools);
6223
6273
  }
6224
6274
  return tools;
6225
6275
  }
@@ -6626,9 +6676,10 @@ If you need to give the user a downloadable file (report, image, export, etc.),
6626
6676
  ### Rules
6627
6677
  1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
6628
6678
  2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
6629
- 3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
6630
- 4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
6631
- 5. Do NOT stop without calling one of these two tools.
6679
+ 3. If you are blocked by missing information, call \`ask_question_to_user\` with a concise question. The run will pause until the orchestrator or user answers, then you should continue from that answer.
6680
+ 4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
6681
+ 5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
6682
+ 6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
6632
6683
 
6633
6684
  ### Verification \u2014 BE EXTREMELY THOROUGH
6634
6685
  Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
@@ -6699,6 +6750,7 @@ ${JSON.stringify(outputSchema, null, 2)}
6699
6750
  ### Completion Tools
6700
6751
  - **\`complete_task({ result: ... })\`** \u2014 Call ONLY after thorough verification. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
6701
6752
  - **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
6753
+ - **\`ask_question_to_user({ question, context?, choices? })\`** \u2014 Call only when you need information that is not available in the repo, task prompt, files, logs, or tools. Ask one clear question; after the answer is returned, continue working.
6702
6754
  `;
6703
6755
  }
6704
6756
  function createSummaryPrompt(conversationHistory) {
@@ -6854,6 +6906,7 @@ function sanitizeModelMessages(messages) {
6854
6906
 
6855
6907
  // src/agent/model-limits.ts
6856
6908
  var MODEL_LIMITS = {
6909
+ "anthropic/claude-opus-4.7": { contextWindow: 2e5, rollingTarget: 15e4 },
6857
6910
  "anthropic/claude-opus-4-6": { contextWindow: 2e5, rollingTarget: 15e4 },
6858
6911
  "anthropic/claude-sonnet-4": { contextWindow: 2e5, rollingTarget: 15e4 },
6859
6912
  "anthropic/claude-3.5-sonnet": { contextWindow: 2e5, rollingTarget: 15e4 },
@@ -7231,18 +7284,38 @@ async function sendWebhook(url, event) {
7231
7284
  }
7232
7285
  }
7233
7286
 
7287
+ // src/tasks/questions.ts
7288
+ var pendingQuestions = /* @__PURE__ */ new Map();
7289
+ function key(taskId, questionId) {
7290
+ return `${taskId}:${questionId}`;
7291
+ }
7292
+ function waitForTaskQuestionAnswer(question) {
7293
+ const k = key(question.taskId, question.questionId);
7294
+ if (pendingQuestions.has(k)) {
7295
+ return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
7296
+ }
7297
+ return new Promise((resolve10, reject) => {
7298
+ pendingQuestions.set(k, {
7299
+ ...question,
7300
+ createdAt: /* @__PURE__ */ new Date(),
7301
+ resolve: resolve10,
7302
+ reject
7303
+ });
7304
+ });
7305
+ }
7306
+
7234
7307
  // src/agent/index.ts
7235
7308
  var MAX_SSE_FIELD_LENGTH = 8 * 1024;
7236
7309
  var SSE_PREVIEW_LENGTH = 2 * 1024;
7237
7310
  function truncateWriteFileInput(input) {
7238
7311
  const out = { ...input };
7239
- for (const key of ["content", "old_string", "new_string"]) {
7240
- const val = out[key];
7312
+ for (const key2 of ["content", "old_string", "new_string"]) {
7313
+ const val = out[key2];
7241
7314
  if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
7242
- out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7315
+ out[key2] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7243
7316
  ... (truncated)`;
7244
- out[`${key}Truncated`] = true;
7245
- out[`${key}Length`] = val.length;
7317
+ out[`${key2}Truncated`] = true;
7318
+ out[`${key2}Length`] = val.length;
7246
7319
  }
7247
7320
  }
7248
7321
  return out;
@@ -7412,13 +7485,7 @@ ${prompt}` });
7412
7485
  abortSignal: options.abortSignal,
7413
7486
  // Enable extended thinking/reasoning for models that support it
7414
7487
  providerOptions: useAnthropic ? {
7415
- anthropic: {
7416
- toolStreaming: true,
7417
- thinking: {
7418
- type: "enabled",
7419
- budgetTokens: 1e4
7420
- }
7421
- }
7488
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
7422
7489
  } : void 0,
7423
7490
  onStepFinish: async (step) => {
7424
7491
  options.onStepFinish?.(step);
@@ -7465,12 +7532,7 @@ ${prompt}` });
7465
7532
  stopWhen: stepCountIs2(500),
7466
7533
  // Enable extended thinking/reasoning for models that support it
7467
7534
  providerOptions: useAnthropic ? {
7468
- anthropic: {
7469
- thinking: {
7470
- type: "enabled",
7471
- budgetTokens: 1e4
7472
- }
7473
- }
7535
+ anthropic: getAnthropicProviderOptions(this.session.model)
7474
7536
  } : void 0
7475
7537
  });
7476
7538
  const responseMessages = result.response.messages;
@@ -7557,7 +7619,38 @@ ${prompt}` });
7557
7619
  },
7558
7620
  taskTools: {
7559
7621
  outputSchema: options.taskConfig.outputSchema,
7560
- onComplete
7622
+ onComplete,
7623
+ onQuestion: async (question) => {
7624
+ const payload = {
7625
+ questionId: question.questionId,
7626
+ question: question.question,
7627
+ context: question.context,
7628
+ choices: question.choices,
7629
+ status: "pending"
7630
+ };
7631
+ const answerPromise = waitForTaskQuestionAnswer({
7632
+ taskId: this.session.id,
7633
+ questionId: question.questionId,
7634
+ question: question.question,
7635
+ context: question.context,
7636
+ choices: question.choices
7637
+ });
7638
+ fireWebhook("task.question", payload);
7639
+ if (emit) {
7640
+ await emit(JSON.stringify({ type: "task-question", data: payload }));
7641
+ }
7642
+ const answer = await answerPromise;
7643
+ const answeredPayload = {
7644
+ questionId: question.questionId,
7645
+ answer: answer.answer,
7646
+ answeredBy: answer.answeredBy
7647
+ };
7648
+ fireWebhook("task.question_answered", answeredPayload);
7649
+ if (emit) {
7650
+ await emit(JSON.stringify({ type: "task-question-answered", data: answeredPayload }));
7651
+ }
7652
+ return answer;
7653
+ }
7561
7654
  }
7562
7655
  });
7563
7656
  const baseSystemPrompt = await buildSystemPrompt({
@@ -7602,10 +7695,7 @@ ${taskAddendum}`;
7602
7695
  stopWhen: stepCountIs2(500),
7603
7696
  abortSignal: options.abortSignal,
7604
7697
  providerOptions: useAnthropic ? {
7605
- anthropic: {
7606
- toolStreaming: true,
7607
- thinking: { type: "enabled", budgetTokens: 1e4 }
7608
- }
7698
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
7609
7699
  } : void 0,
7610
7700
  onStepFinish: async (step) => {
7611
7701
  options.onStepFinish?.(step);
@@ -7892,7 +7982,7 @@ ${taskAddendum}`;
7892
7982
  description: originalTool.description || "",
7893
7983
  inputSchema: originalTool.inputSchema || z15.object({}),
7894
7984
  execute: async (input, toolOptions) => {
7895
- const toolCallId = toolOptions.toolCallId || nanoid5();
7985
+ const toolCallId = toolOptions.toolCallId || nanoid6();
7896
7986
  const execution = toolExecutionQueries.create({
7897
7987
  sessionId: this.session.id,
7898
7988
  toolName: name,