@within-7/minto 0.3.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/components/SubagentProgress.js +10 -2
  2. package/dist/components/SubagentProgress.js.map +2 -2
  3. package/dist/constants/prompts.js +22 -1
  4. package/dist/constants/prompts.js.map +2 -2
  5. package/dist/entrypoints/cli.js +15 -9
  6. package/dist/entrypoints/cli.js.map +2 -2
  7. package/dist/permissions.js +121 -2
  8. package/dist/permissions.js.map +2 -2
  9. package/dist/screens/ResumeConversation.js +2 -0
  10. package/dist/screens/ResumeConversation.js.map +2 -2
  11. package/dist/services/taskStore.js +205 -0
  12. package/dist/services/taskStore.js.map +7 -0
  13. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +40 -3
  14. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  15. package/dist/tools/BashTool/BashTool.js +21 -4
  16. package/dist/tools/BashTool/BashTool.js.map +2 -2
  17. package/dist/tools/BashTool/prompt.js +6 -0
  18. package/dist/tools/BashTool/prompt.js.map +2 -2
  19. package/dist/tools/FileEditTool/FileEditTool.js +24 -9
  20. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  21. package/dist/tools/FileEditTool/prompt.js +4 -1
  22. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  23. package/dist/tools/FileEditTool/utils.js +10 -4
  24. package/dist/tools/FileEditTool/utils.js.map +2 -2
  25. package/dist/tools/FileReadTool/FileReadTool.js +1 -1
  26. package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
  27. package/dist/tools/FileReadTool/prompt.js +16 -1
  28. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  29. package/dist/tools/FileWriteTool/FileWriteTool.js +1 -1
  30. package/dist/tools/FileWriteTool/FileWriteTool.js.map +1 -1
  31. package/dist/tools/FileWriteTool/prompt.js +8 -1
  32. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  33. package/dist/tools/GlobTool/prompt.js +12 -1
  34. package/dist/tools/GlobTool/prompt.js.map +2 -2
  35. package/dist/tools/GrepTool/GrepTool.js +333 -65
  36. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  37. package/dist/tools/GrepTool/prompt.js +15 -8
  38. package/dist/tools/GrepTool/prompt.js.map +2 -2
  39. package/dist/tools/NotebookEditTool/NotebookEditTool.js +57 -45
  40. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  41. package/dist/tools/NotebookEditTool/prompt.js +1 -1
  42. package/dist/tools/NotebookEditTool/prompt.js.map +1 -1
  43. package/dist/tools/TaskCreateTool/TaskCreateTool.js +102 -0
  44. package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +7 -0
  45. package/dist/tools/TaskCreateTool/prompt.js +47 -0
  46. package/dist/tools/TaskCreateTool/prompt.js.map +7 -0
  47. package/dist/tools/TaskGetTool/TaskGetTool.js +115 -0
  48. package/dist/tools/TaskGetTool/TaskGetTool.js.map +7 -0
  49. package/dist/tools/TaskGetTool/prompt.js +28 -0
  50. package/dist/tools/TaskGetTool/prompt.js.map +7 -0
  51. package/dist/tools/TaskListTool/TaskListTool.js +102 -0
  52. package/dist/tools/TaskListTool/TaskListTool.js.map +7 -0
  53. package/dist/tools/TaskListTool/prompt.js +27 -0
  54. package/dist/tools/TaskListTool/prompt.js.map +7 -0
  55. package/dist/tools/TaskStopTool/TaskStopTool.js +150 -0
  56. package/dist/tools/TaskStopTool/TaskStopTool.js.map +7 -0
  57. package/dist/tools/TaskStopTool/prompt.js +15 -0
  58. package/dist/tools/TaskStopTool/prompt.js.map +7 -0
  59. package/dist/tools/TaskTool/TaskTool.js +41 -1
  60. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  61. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +134 -0
  62. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +7 -0
  63. package/dist/tools/TaskUpdateTool/prompt.js +81 -0
  64. package/dist/tools/TaskUpdateTool/prompt.js.map +7 -0
  65. package/dist/tools/URLFetcherTool/prompt.js +1 -1
  66. package/dist/tools/URLFetcherTool/prompt.js.map +1 -1
  67. package/dist/tools.js +12 -0
  68. package/dist/tools.js.map +2 -2
  69. package/dist/utils/config.js.map +2 -2
  70. package/dist/utils/model.js +15 -2
  71. package/dist/utils/model.js.map +2 -2
  72. package/dist/utils/ripgrep.js +53 -1
  73. package/dist/utils/ripgrep.js.map +2 -2
  74. package/dist/utils/terminal.js +12 -0
  75. package/dist/utils/terminal.js.map +2 -2
  76. package/dist/utils/tooling/safeRender.js +13 -14
  77. package/dist/utils/tooling/safeRender.js.map +2 -2
  78. package/dist/version.js +2 -2
  79. package/dist/version.js.map +1 -1
  80. package/package.json +20 -28
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/ripgrep.ts"],
4
- "sourcesContent": ["import { findActualExecutable } from 'spawn-rx'\nimport { memoize } from 'lodash-es'\nimport { fileURLToPath, resolve } from 'node:url'\nimport * as path from 'path'\nimport { logError } from './log'\nimport { execFileNoThrow } from './execFileNoThrow'\nimport { execFile, spawn } from 'child_process'\nimport debug from 'debug'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = resolve(\n __filename,\n process.env.NODE_ENV === 'test' ? '../..' : '.',\n)\n\nconst d = debug('claude:ripgrep')\n\nconst useBuiltinRipgrep = !!process.env.USE_BUILTIN_RIPGREP\nif (useBuiltinRipgrep) {\n d('Using builtin ripgrep because USE_BUILTIN_RIPGREP is set')\n}\n\nconst ripgrepPath = memoize(() => {\n const { cmd } = findActualExecutable('rg', [])\n d(`ripgrep initially resolved as: ${cmd}`)\n\n if (cmd !== 'rg' && !useBuiltinRipgrep) {\n // NB: If we're able to find ripgrep in $PATH, cmd will be an absolute\n // path rather than just returning 'rg'\n return cmd\n } else {\n // Use the one we ship in-box\n const rgRoot = path.resolve(__dirname, 'vendor', 'ripgrep')\n if (process.platform === 'win32') {\n // NB: Ripgrep doesn't ship an aarch64 binary for Windows, boooooo\n return path.resolve(rgRoot, 'x64-win32', 'rg.exe')\n }\n\n const ret = path.resolve(\n rgRoot,\n `${process.arch}-${process.platform}`,\n 'rg',\n )\n\n d('internal ripgrep resolved as: %s', ret)\n return ret\n }\n})\n\nexport async function ripGrep(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): Promise<string[]> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep called: %s %o', rg, target, args)\n\n // NB: When running interactively, ripgrep does not require a path as its last\n // argument, but when run non-interactively, it will hang unless a path or file\n // pattern is provided\n return new Promise(resolve => {\n execFile(\n ripgrepPath(),\n [...args, target],\n {\n maxBuffer: 1_000_000,\n signal: abortSignal,\n timeout: 10_000,\n },\n (error, stdout) => {\n if (error) {\n // Exit code 1 from ripgrep means \"no matches found\" - this is normal\n if (error.code !== 1) {\n d('ripgrep error: %o', error)\n logError(error)\n }\n resolve([])\n } else {\n d('ripgrep succeeded with %s', stdout)\n resolve(stdout.trim().split('\\n').filter(Boolean))\n }\n },\n )\n })\n}\n\n/**\n * Streaming ripgrep result type\n */\nexport type RipGrepStreamChunk = {\n type: 'match'\n file: string\n}\n\nexport type RipGrepStreamResult = {\n type: 'complete'\n totalFiles: number\n durationMs: number\n}\n\nexport type RipGrepStreamYield = RipGrepStreamChunk | RipGrepStreamResult\n\n/**\n * Streaming version of ripGrep that yields matches as they are found.\n * This provides real-time feedback during searches of large codebases.\n */\nexport async function* ripGrepStreaming(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepStreamYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalFiles = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const file = line.trim()\n if (file) {\n totalFiles++\n yield { type: 'match', file }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalFiles++\n yield { type: 'match', file: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalFiles,\n durationMs: Date.now() - startTime,\n }\n}\n\n// NB: We do something tricky here. We know that ripgrep processes common\n// ignore files for us, so we just ripgrep for any character, which matches\n// all non-empty files\nexport async function listAllContentFiles(\n path: string,\n abortSignal: AbortSignal,\n limit: number,\n): Promise<string[]> {\n try {\n d('listAllContentFiles called: %s', path)\n return (await ripGrep(['-l', '.', path], path, abortSignal)).slice(0, limit)\n } catch (e) {\n d('listAllContentFiles failed: %o', e)\n\n logError(e)\n return []\n }\n}\n\nlet alreadyDoneSignCheck = false\nasync function codesignRipgrepIfNecessary() {\n if (process.platform !== 'darwin' || alreadyDoneSignCheck) {\n return\n }\n\n alreadyDoneSignCheck = true\n\n // First, check to see if ripgrep is already signed\n d('checking if ripgrep is already signed')\n const lines = (\n await execFileNoThrow(\n 'codesign',\n ['-vv', '-d', ripgrepPath()],\n undefined,\n undefined,\n false,\n )\n ).stdout.split('\\n')\n\n const needsSigned = lines.find(line => line.includes('linker-signed'))\n if (!needsSigned) {\n d('seems to be already signed')\n return\n }\n\n try {\n d('signing ripgrep')\n const signResult = await execFileNoThrow('codesign', [\n '--sign',\n '-',\n '--force',\n '--preserve-metadata=entitlements,requirements,flags,runtime',\n ripgrepPath(),\n ])\n\n if (signResult.code !== 0) {\n d('failed to sign ripgrep: %o', signResult)\n logError(\n `Failed to sign ripgrep: ${signResult.stdout} ${signResult.stderr}`,\n )\n }\n\n d('removing quarantine')\n const quarantineResult = await execFileNoThrow('xattr', [\n '-d',\n 'com.apple.quarantine',\n ripgrepPath(),\n ])\n\n if (quarantineResult.code !== 0) {\n d('failed to remove quarantine: %o', quarantineResult)\n logError(\n `Failed to remove quarantine: ${quarantineResult.stdout} ${quarantineResult.stderr}`,\n )\n }\n } catch (e) {\n d('failed during sign: %o', e)\n logError(e)\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { findActualExecutable } from 'spawn-rx'\nimport { memoize } from 'lodash-es'\nimport { fileURLToPath, resolve } from 'node:url'\nimport * as path from 'path'\nimport { logError } from './log'\nimport { execFileNoThrow } from './execFileNoThrow'\nimport { execFile, spawn } from 'child_process'\nimport debug from 'debug'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = resolve(\n __filename,\n process.env.NODE_ENV === 'test' ? '../..' : '.',\n)\n\nconst d = debug('claude:ripgrep')\n\nconst useBuiltinRipgrep = !!process.env.USE_BUILTIN_RIPGREP\nif (useBuiltinRipgrep) {\n d('Using builtin ripgrep because USE_BUILTIN_RIPGREP is set')\n}\n\nconst ripgrepPath = memoize(() => {\n const { cmd } = findActualExecutable('rg', [])\n d(`ripgrep initially resolved as: ${cmd}`)\n\n if (cmd !== 'rg' && !useBuiltinRipgrep) {\n // NB: If we're able to find ripgrep in $PATH, cmd will be an absolute\n // path rather than just returning 'rg'\n return cmd\n } else {\n // Use the one we ship in-box\n const rgRoot = path.resolve(__dirname, 'vendor', 'ripgrep')\n if (process.platform === 'win32') {\n // NB: Ripgrep doesn't ship an aarch64 binary for Windows, boooooo\n return path.resolve(rgRoot, 'x64-win32', 'rg.exe')\n }\n\n const ret = path.resolve(\n rgRoot,\n `${process.arch}-${process.platform}`,\n 'rg',\n )\n\n d('internal ripgrep resolved as: %s', ret)\n return ret\n }\n})\n\nexport async function ripGrep(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): Promise<string[]> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep called: %s %o', rg, target, args)\n\n // NB: When running interactively, ripgrep does not require a path as its last\n // argument, but when run non-interactively, it will hang unless a path or file\n // pattern is provided\n return new Promise(resolve => {\n execFile(\n ripgrepPath(),\n [...args, target],\n {\n maxBuffer: 1_000_000,\n signal: abortSignal,\n timeout: 10_000,\n },\n (error, stdout) => {\n if (error) {\n // Exit code 1 from ripgrep means \"no matches found\" - this is normal\n if (error.code !== 1) {\n d('ripgrep error: %o', error)\n logError(error)\n }\n resolve([])\n } else {\n d('ripgrep succeeded with %s', stdout)\n resolve(stdout.trim().split('\\n').filter(Boolean))\n }\n },\n )\n })\n}\n\n/**\n * Streaming ripgrep result type for file matching\n */\nexport type RipGrepStreamChunk = {\n type: 'match'\n file: string\n}\n\nexport type RipGrepStreamResult = {\n type: 'complete'\n totalFiles: number\n durationMs: number\n}\n\nexport type RipGrepStreamYield = RipGrepStreamChunk | RipGrepStreamResult\n\n/**\n * Streaming ripgrep result type for content output\n */\nexport type RipGrepContentChunk = {\n type: 'line'\n line: string\n}\n\nexport type RipGrepContentResult = {\n type: 'complete'\n totalLines: number\n durationMs: number\n}\n\nexport type RipGrepContentYield = RipGrepContentChunk | RipGrepContentResult\n\n/**\n * Streaming version of ripGrep that yields matches as they are found.\n * This provides real-time feedback during searches of large codebases.\n */\nexport async function* ripGrepStreaming(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepStreamYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalFiles = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const file = line.trim()\n if (file) {\n totalFiles++\n yield { type: 'match', file }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalFiles++\n yield { type: 'match', file: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalFiles,\n durationMs: Date.now() - startTime,\n }\n}\n\n/**\n * Streaming version of ripGrep that yields raw content lines.\n * Used for content mode and count mode where we need the full output.\n */\nexport async function* ripGrepStreamingWithContent(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepContentYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming with content called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalLines = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (line) {\n totalLines++\n yield { type: 'line', line }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalLines++\n yield { type: 'line', line: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming with content error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalLines,\n durationMs: Date.now() - startTime,\n }\n}\n\n// NB: We do something tricky here. We know that ripgrep processes common\n// ignore files for us, so we just ripgrep for any character, which matches\n// all non-empty files\nexport async function listAllContentFiles(\n path: string,\n abortSignal: AbortSignal,\n limit: number,\n): Promise<string[]> {\n try {\n d('listAllContentFiles called: %s', path)\n return (await ripGrep(['-l', '.', path], path, abortSignal)).slice(0, limit)\n } catch (e) {\n d('listAllContentFiles failed: %o', e)\n\n logError(e)\n return []\n }\n}\n\nlet alreadyDoneSignCheck = false\nasync function codesignRipgrepIfNecessary() {\n if (process.platform !== 'darwin' || alreadyDoneSignCheck) {\n return\n }\n\n alreadyDoneSignCheck = true\n\n // First, check to see if ripgrep is already signed\n d('checking if ripgrep is already signed')\n const lines = (\n await execFileNoThrow(\n 'codesign',\n ['-vv', '-d', ripgrepPath()],\n undefined,\n undefined,\n false,\n )\n ).stdout.split('\\n')\n\n const needsSigned = lines.find(line => line.includes('linker-signed'))\n if (!needsSigned) {\n d('seems to be already signed')\n return\n }\n\n try {\n d('signing ripgrep')\n const signResult = await execFileNoThrow('codesign', [\n '--sign',\n '-',\n '--force',\n '--preserve-metadata=entitlements,requirements,flags,runtime',\n ripgrepPath(),\n ])\n\n if (signResult.code !== 0) {\n d('failed to sign ripgrep: %o', signResult)\n logError(\n `Failed to sign ripgrep: ${signResult.stdout} ${signResult.stderr}`,\n )\n }\n\n d('removing quarantine')\n const quarantineResult = await execFileNoThrow('xattr', [\n '-d',\n 'com.apple.quarantine',\n ripgrepPath(),\n ])\n\n if (quarantineResult.code !== 0) {\n d('failed to remove quarantine: %o', quarantineResult)\n logError(\n `Failed to remove quarantine: ${quarantineResult.stdout} ${quarantineResult.stderr}`,\n )\n }\n } catch (e) {\n d('failed during sign: %o', e)\n logError(e)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["resolve", "path"]
7
7
  }
@@ -38,9 +38,21 @@ function clearTerminal() {
38
38
  function clearScreen() {
39
39
  process.stdout.write("\x1B[2J\x1B[H");
40
40
  }
41
+ function prepareTerminalForREPL() {
42
+ return new Promise((resolve) => {
43
+ if (!process.stdout.isTTY) {
44
+ resolve();
45
+ return;
46
+ }
47
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H\x1B[?25h", () => {
48
+ resolve();
49
+ });
50
+ });
51
+ }
41
52
  export {
42
53
  clearScreen,
43
54
  clearTerminal,
55
+ prepareTerminalForREPL,
44
56
  setTerminalTitle,
45
57
  updateTerminalTitle
46
58
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/terminal.ts"],
4
- "sourcesContent": ["import { safeParseJSON } from './json'\nimport { logError } from './log'\nimport { queryQuick } from '@services/claude'\n\nexport function setTerminalTitle(title: string): void {\n if (process.platform === 'win32') {\n process.title = title ? `\u2733 ${title}` : title\n } else {\n process.stdout.write(`\\x1b]0;${title ? `\u2733 ${title}` : ''}\\x07`)\n }\n}\n\nexport async function updateTerminalTitle(message: string): Promise<void> {\n try {\n const result = await queryQuick({\n systemPrompt: [\n \"Analyze if this message indicates a new conversation topic. If it does, extract a 2-3 word title that captures the new topic. Format your response as a JSON object with two fields: 'isNewTopic' (boolean) and 'title' (string, or null if isNewTopic is false). Only include these fields, no other text.\",\n ],\n userPrompt: message,\n enablePromptCaching: true,\n })\n\n const content = result.message.content\n .filter(_ => _.type === 'text')\n .map(_ => _.text)\n .join('')\n\n const response = safeParseJSON(content)\n if (\n response &&\n typeof response === 'object' &&\n 'isNewTopic' in response &&\n 'title' in response\n ) {\n if (response.isNewTopic && response.title) {\n setTerminalTitle(response.title as string)\n }\n }\n } catch (error) {\n logError(error)\n }\n}\n\nexport function clearTerminal(): Promise<void> {\n return new Promise(resolve => {\n process.stdout.write('\\x1b[2J\\x1b[3J\\x1b[H', () => {\n resolve()\n })\n })\n}\n\n/**\n * Synchronous clear screen (for immediate feedback with hotkeys like Ctrl-L)\n * Uses ANSI escape sequences: \\x1b[2J clears screen, \\x1b[H moves cursor to home\n */\nexport function clearScreen(): void {\n process.stdout.write('\\x1b[2J\\x1b[H')\n}\n"],
5
- "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAEpB,SAAS,iBAAiB,OAAqB;AACpD,MAAI,QAAQ,aAAa,SAAS;AAChC,YAAQ,QAAQ,QAAQ,UAAK,KAAK,KAAK;AAAA,EACzC,OAAO;AACL,YAAQ,OAAO,MAAM,UAAU,QAAQ,UAAK,KAAK,KAAK,EAAE,MAAM;AAAA,EAChE;AACF;AAEA,eAAsB,oBAAoB,SAAgC;AACxE,MAAI;AACF,UAAM,SAAS,MAAM,WAAW;AAAA,MAC9B,cAAc;AAAA,QACZ;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MACZ,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,UAAU,OAAO,QAAQ,QAC5B,OAAO,OAAK,EAAE,SAAS,MAAM,EAC7B,IAAI,OAAK,EAAE,IAAI,EACf,KAAK,EAAE;AAEV,UAAM,WAAW,cAAc,OAAO;AACtC,QACE,YACA,OAAO,aAAa,YACpB,gBAAgB,YAChB,WAAW,UACX;AACA,UAAI,SAAS,cAAc,SAAS,OAAO;AACzC,yBAAiB,SAAS,KAAe;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,aAAS,KAAK;AAAA,EAChB;AACF;AAEO,SAAS,gBAA+B;AAC7C,SAAO,IAAI,QAAQ,aAAW;AAC5B,YAAQ,OAAO,MAAM,wBAAwB,MAAM;AACjD,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAMO,SAAS,cAAoB;AAClC,UAAQ,OAAO,MAAM,eAAe;AACtC;",
4
+ "sourcesContent": ["import { safeParseJSON } from './json'\nimport { logError } from './log'\nimport { queryQuick } from '@services/claude'\n\nexport function setTerminalTitle(title: string): void {\n if (process.platform === 'win32') {\n process.title = title ? `\u2733 ${title}` : title\n } else {\n process.stdout.write(`\\x1b]0;${title ? `\u2733 ${title}` : ''}\\x07`)\n }\n}\n\nexport async function updateTerminalTitle(message: string): Promise<void> {\n try {\n const result = await queryQuick({\n systemPrompt: [\n \"Analyze if this message indicates a new conversation topic. If it does, extract a 2-3 word title that captures the new topic. Format your response as a JSON object with two fields: 'isNewTopic' (boolean) and 'title' (string, or null if isNewTopic is false). Only include these fields, no other text.\",\n ],\n userPrompt: message,\n enablePromptCaching: true,\n })\n\n const content = result.message.content\n .filter(_ => _.type === 'text')\n .map(_ => _.text)\n .join('')\n\n const response = safeParseJSON(content)\n if (\n response &&\n typeof response === 'object' &&\n 'isNewTopic' in response &&\n 'title' in response\n ) {\n if (response.isNewTopic && response.title) {\n setTerminalTitle(response.title as string)\n }\n }\n } catch (error) {\n logError(error)\n }\n}\n\nexport function clearTerminal(): Promise<void> {\n return new Promise(resolve => {\n process.stdout.write('\\x1b[2J\\x1b[3J\\x1b[H', () => {\n resolve()\n })\n })\n}\n\n/**\n * Synchronous clear screen (for immediate feedback with hotkeys like Ctrl-L)\n * Uses ANSI escape sequences: \\x1b[2J clears screen, \\x1b[H moves cursor to home\n */\nexport function clearScreen(): void {\n process.stdout.write('\\x1b[2J\\x1b[H')\n}\n\n/**\n * Prepare terminal for REPL rendering\n * Clears screen and normalizes terminal state before Ink starts rendering\n *\n * This ensures a clean slate for the REPL interface:\n * - \\x1b[2J - Clear entire screen\n * - \\x1b[3J - Clear scrollback buffer (provides fresh start)\n * - \\x1b[H - Move cursor to home position (0,0)\n * - \\x1b[?25h - Show cursor (in case it was hidden)\n *\n * @returns Promise that resolves when terminal is ready\n */\nexport function prepareTerminalForREPL(): Promise<void> {\n return new Promise(resolve => {\n if (!process.stdout.isTTY) {\n resolve()\n return\n }\n\n // Clear screen, scrollback, move cursor home, show cursor\n process.stdout.write('\\x1b[2J\\x1b[3J\\x1b[H\\x1b[?25h', () => {\n resolve()\n })\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAEpB,SAAS,iBAAiB,OAAqB;AACpD,MAAI,QAAQ,aAAa,SAAS;AAChC,YAAQ,QAAQ,QAAQ,UAAK,KAAK,KAAK;AAAA,EACzC,OAAO;AACL,YAAQ,OAAO,MAAM,UAAU,QAAQ,UAAK,KAAK,KAAK,EAAE,MAAM;AAAA,EAChE;AACF;AAEA,eAAsB,oBAAoB,SAAgC;AACxE,MAAI;AACF,UAAM,SAAS,MAAM,WAAW;AAAA,MAC9B,cAAc;AAAA,QACZ;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MACZ,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,UAAU,OAAO,QAAQ,QAC5B,OAAO,OAAK,EAAE,SAAS,MAAM,EAC7B,IAAI,OAAK,EAAE,IAAI,EACf,KAAK,EAAE;AAEV,UAAM,WAAW,cAAc,OAAO;AACtC,QACE,YACA,OAAO,aAAa,YACpB,gBAAgB,YAChB,WAAW,UACX;AACA,UAAI,SAAS,cAAc,SAAS,OAAO;AACzC,yBAAiB,SAAS,KAAe;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,aAAS,KAAK;AAAA,EAChB;AACF;AAEO,SAAS,gBAA+B;AAC7C,SAAO,IAAI,QAAQ,aAAW;AAC5B,YAAQ,OAAO,MAAM,wBAAwB,MAAM;AACjD,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAMO,SAAS,cAAoB;AAClC,UAAQ,OAAO,MAAM,eAAe;AACtC;AAcO,SAAS,yBAAwC;AACtD,SAAO,IAAI,QAAQ,aAAW;AAC5B,QAAI,CAAC,QAAQ,OAAO,OAAO;AACzB,cAAQ;AACR;AAAA,IACF;AAGA,YAAQ,OAAO,MAAM,iCAAiC,MAAM;AAC1D,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -4,22 +4,21 @@ import { SEMANTIC_COLORS } from "../../constants/colors.js";
4
4
  function DefaultToolResult({
5
5
  output
6
6
  }) {
7
- let displayContent;
8
- if (output === null || output === void 0) {
9
- displayContent = "(no output)";
10
- } else if (typeof output === "string") {
11
- displayContent = output.length > 500 ? output.slice(0, 500) + "..." : output;
12
- } else if (typeof output === "object") {
13
- try {
14
- const json = JSON.stringify(output, null, 2);
15
- displayContent = json.length > 500 ? json.slice(0, 500) + "..." : json;
16
- } catch {
17
- displayContent = "[Object - cannot stringify]";
7
+ if (output !== null && output !== void 0 && typeof output === "object") {
8
+ const obj = output;
9
+ if ("success" in obj || "result" in obj || "data" in obj) {
10
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "Done"));
18
11
  }
19
- } else {
20
- displayContent = String(output);
12
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "Completed"));
13
+ }
14
+ if (typeof output === "string") {
15
+ const displayContent = output.length > 500 ? output.slice(0, 500) + "..." : output;
16
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, displayContent));
17
+ }
18
+ if (output === null || output === void 0) {
19
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(no output)"));
21
20
  }
22
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, displayContent));
21
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, String(output)));
23
22
  }
24
23
  function ErrorToolResult({
25
24
  error,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/tooling/safeRender.tsx"],
4
- "sourcesContent": ["/**\n * Safe Rendering Utilities for Tool Results\n *\n * Provides null-safe wrappers for tool rendering methods to prevent\n * crashes from undefined returns or exceptions.\n *\n * Part of Phase 1.3: Null Guards Completion\n */\n\nimport * as React from 'react'\nimport { Box, Text } from 'ink'\nimport { Tool } from '@tool'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\n/**\n * Default tool result component when tool doesn't provide a renderer.\n */\nexport function DefaultToolResult({\n output,\n}: {\n output: unknown\n}): React.ReactElement {\n let displayContent: string\n\n if (output === null || output === undefined) {\n displayContent = '(no output)'\n } else if (typeof output === 'string') {\n displayContent = output.length > 500 ? output.slice(0, 500) + '...' : output\n } else if (typeof output === 'object') {\n try {\n const json = JSON.stringify(output, null, 2)\n displayContent = json.length > 500 ? json.slice(0, 500) + '...' : json\n } catch {\n displayContent = '[Object - cannot stringify]'\n }\n } else {\n displayContent = String(output)\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text color={SEMANTIC_COLORS.dim}>{displayContent}</Text>\n </Box>\n )\n}\n\n/**\n * Error display component for tool rendering failures.\n */\nexport function ErrorToolResult({\n error,\n toolName,\n}: {\n error: unknown\n toolName?: string\n}): React.ReactElement {\n const errorMessage =\n error instanceof Error ? error.message : String(error || 'Unknown error')\n\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">\n {toolName ? `[${toolName}] ` : ''}Error rendering result:\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>{errorMessage}</Text>\n </Box>\n )\n}\n\n/**\n * Safely render a tool result with comprehensive error handling.\n *\n * @param tool - The tool that produced the result\n * @param output - The tool's output data\n * @param options - Rendering options\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolResult(\n tool: Tool | undefined | null,\n output: unknown,\n options: { verbose: boolean },\n): React.ReactNode {\n // No tool provided\n if (!tool) {\n return <DefaultToolResult output={output} />\n }\n\n // Tool doesn't have a renderer\n if (!tool.renderToolResultMessage) {\n return <DefaultToolResult output={output} />\n }\n\n try {\n const rendered = tool.renderToolResultMessage(output, options)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return <DefaultToolResult output={output} />\n }\n\n return rendered\n } catch (error) {\n // Catch any rendering errors\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Safely render a tool use message with comprehensive error handling.\n *\n * @param tool - The tool being used\n * @param input - The tool's input parameters\n * @param options - Rendering options\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolUseMessage(\n tool: Tool | undefined | null,\n input: unknown,\n options: { verbose: boolean },\n): React.ReactNode {\n // No tool provided\n if (!tool) {\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>Unknown tool call</Text>\n </Box>\n )\n }\n\n // Tool doesn't have a renderer\n if (!tool.renderToolUseMessage) {\n return (\n <Box>\n <Text>\n <Text color=\"cyan\">{tool.name}</Text>\n {options.verbose && (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {JSON.stringify(input).slice(0, 100)}\n </Text>\n )}\n </Text>\n </Box>\n )\n }\n\n try {\n const rendered = tool.renderToolUseMessage(input, options)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return (\n <Box>\n <Text color=\"cyan\">{tool.name}</Text>\n </Box>\n )\n }\n\n return rendered\n } catch (error) {\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Safely render a tool rejection message with comprehensive error handling.\n *\n * @param tool - The tool that was rejected\n * @param args - Arguments to pass to the rejection renderer\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolRejectedMessage(\n tool: Tool | undefined | null,\n ...args: unknown[]\n): React.ReactNode {\n // No tool or no renderer\n if (!tool || !tool.renderToolUseRejectedMessage) {\n return (\n <Box>\n <Text color=\"yellow\">Tool use rejected</Text>\n </Box>\n )\n }\n\n try {\n const rendered = tool.renderToolUseRejectedMessage(...args)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return (\n <Box>\n <Text color=\"yellow\">{tool.name} rejected</Text>\n </Box>\n )\n }\n\n return rendered\n } catch (error) {\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Type guard to check if a value is a valid React node.\n */\nexport function isValidReactNode(value: unknown): value is React.ReactNode {\n if (value === null || value === undefined) {\n return true // React accepts null/undefined\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return true\n }\n\n if (Array.isArray(value)) {\n return value.every(isValidReactNode)\n }\n\n // Check for React element\n if (typeof value === 'object' && value !== null) {\n return '$$typeof' in value || React.isValidElement(value)\n }\n\n return false\n}\n\n/**\n * Wrap a potentially unsafe render function with error boundaries.\n *\n * @param renderFn - The render function to wrap\n * @param fallback - Fallback content on error\n * @returns A safe render function\n */\nexport function wrapRenderFunction<TArgs extends unknown[]>(\n renderFn: (...args: TArgs) => React.ReactNode,\n fallback: React.ReactNode,\n): (...args: TArgs) => React.ReactNode {\n return (...args: TArgs) => {\n try {\n const result = renderFn(...args)\n if (result === null || result === undefined) {\n return fallback\n }\n return result\n } catch {\n return fallback\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Safe Rendering Utilities for Tool Results\n *\n * Provides null-safe wrappers for tool rendering methods to prevent\n * crashes from undefined returns or exceptions.\n *\n * Part of Phase 1.3: Null Guards Completion\n */\n\nimport * as React from 'react'\nimport { Box, Text } from 'ink'\nimport { Tool } from '@tool'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\n/**\n * Default tool result component when tool doesn't provide a renderer.\n *\n * This is used as a fallback when:\n * 1. Tool is not found (e.g., MCP tool no longer available)\n * 2. Tool doesn't have a renderToolResultMessage method\n * 3. Tool's renderToolResultMessage returns null/undefined\n *\n * For better UX, we display a simple success message instead of raw JSON data,\n * which can be confusing for users.\n */\nexport function DefaultToolResult({\n output,\n}: {\n output: unknown\n}): React.ReactElement {\n // For objects (like tool data), show a simple success message\n // instead of raw JSON which can be confusing\n if (output !== null && output !== undefined && typeof output === 'object') {\n // Try to extract meaningful info from the object\n const obj = output as Record<string, unknown>\n\n // Check for common success indicators\n if ('success' in obj || 'result' in obj || 'data' in obj) {\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={SEMANTIC_COLORS.success}>Done</Text>\n </Box>\n )\n }\n\n // For other objects, show a generic completion message\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={SEMANTIC_COLORS.success}>Completed</Text>\n </Box>\n )\n }\n\n // For strings, show the content (truncated if too long)\n if (typeof output === 'string') {\n const displayContent = output.length > 500 ? output.slice(0, 500) + '...' : output\n return (\n <Box flexDirection=\"column\">\n <Text color={SEMANTIC_COLORS.dim}>{displayContent}</Text>\n </Box>\n )\n }\n\n // For null/undefined, show no output message\n if (output === null || output === undefined) {\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={SEMANTIC_COLORS.dim}>(no output)</Text>\n </Box>\n )\n }\n\n // For other primitives, convert to string\n return (\n <Box flexDirection=\"column\">\n <Text color={SEMANTIC_COLORS.dim}>{String(output)}</Text>\n </Box>\n )\n}\n\n/**\n * Error display component for tool rendering failures.\n */\nexport function ErrorToolResult({\n error,\n toolName,\n}: {\n error: unknown\n toolName?: string\n}): React.ReactElement {\n const errorMessage =\n error instanceof Error ? error.message : String(error || 'Unknown error')\n\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">\n {toolName ? `[${toolName}] ` : ''}Error rendering result:\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>{errorMessage}</Text>\n </Box>\n )\n}\n\n/**\n * Safely render a tool result with comprehensive error handling.\n *\n * @param tool - The tool that produced the result\n * @param output - The tool's output data\n * @param options - Rendering options\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolResult(\n tool: Tool | undefined | null,\n output: unknown,\n options: { verbose: boolean },\n): React.ReactNode {\n // No tool provided\n if (!tool) {\n return <DefaultToolResult output={output} />\n }\n\n // Tool doesn't have a renderer\n if (!tool.renderToolResultMessage) {\n return <DefaultToolResult output={output} />\n }\n\n try {\n const rendered = tool.renderToolResultMessage(output, options)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return <DefaultToolResult output={output} />\n }\n\n return rendered\n } catch (error) {\n // Catch any rendering errors\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Safely render a tool use message with comprehensive error handling.\n *\n * @param tool - The tool being used\n * @param input - The tool's input parameters\n * @param options - Rendering options\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolUseMessage(\n tool: Tool | undefined | null,\n input: unknown,\n options: { verbose: boolean },\n): React.ReactNode {\n // No tool provided\n if (!tool) {\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>Unknown tool call</Text>\n </Box>\n )\n }\n\n // Tool doesn't have a renderer\n if (!tool.renderToolUseMessage) {\n return (\n <Box>\n <Text>\n <Text color=\"cyan\">{tool.name}</Text>\n {options.verbose && (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {JSON.stringify(input).slice(0, 100)}\n </Text>\n )}\n </Text>\n </Box>\n )\n }\n\n try {\n const rendered = tool.renderToolUseMessage(input, options)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return (\n <Box>\n <Text color=\"cyan\">{tool.name}</Text>\n </Box>\n )\n }\n\n return rendered\n } catch (error) {\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Safely render a tool rejection message with comprehensive error handling.\n *\n * @param tool - The tool that was rejected\n * @param args - Arguments to pass to the rejection renderer\n * @returns A React node that is guaranteed to be renderable\n */\nexport function safeRenderToolRejectedMessage(\n tool: Tool | undefined | null,\n ...args: unknown[]\n): React.ReactNode {\n // No tool or no renderer\n if (!tool || !tool.renderToolUseRejectedMessage) {\n return (\n <Box>\n <Text color=\"yellow\">Tool use rejected</Text>\n </Box>\n )\n }\n\n try {\n const rendered = tool.renderToolUseRejectedMessage(...args)\n\n // Handle null/undefined returns\n if (rendered === null || rendered === undefined) {\n return (\n <Box>\n <Text color=\"yellow\">{tool.name} rejected</Text>\n </Box>\n )\n }\n\n return rendered\n } catch (error) {\n return <ErrorToolResult error={error} toolName={tool.name} />\n }\n}\n\n/**\n * Type guard to check if a value is a valid React node.\n */\nexport function isValidReactNode(value: unknown): value is React.ReactNode {\n if (value === null || value === undefined) {\n return true // React accepts null/undefined\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return true\n }\n\n if (Array.isArray(value)) {\n return value.every(isValidReactNode)\n }\n\n // Check for React element\n if (typeof value === 'object' && value !== null) {\n return '$$typeof' in value || React.isValidElement(value)\n }\n\n return false\n}\n\n/**\n * Wrap a potentially unsafe render function with error boundaries.\n *\n * @param renderFn - The render function to wrap\n * @param fallback - Fallback content on error\n * @returns A safe render function\n */\nexport function wrapRenderFunction<TArgs extends unknown[]>(\n renderFn: (...args: TArgs) => React.ReactNode,\n fallback: React.ReactNode,\n): (...args: TArgs) => React.ReactNode {\n return (...args: TArgs) => {\n try {\n const result = renderFn(...args)\n if (result === null || result === undefined) {\n return fallback\n }\n return result\n } catch {\n return fallback\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
- const VERSION = "0.3.0";
2
- const BUILD_DATE = "2026-02-02T01:21:32.241Z";
1
+ const VERSION = "0.3.3";
2
+ const BUILD_DATE = "2026-02-02T12:05:51.819Z";
3
3
  export {
4
4
  BUILD_DATE,
5
5
  VERSION
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["/**\n * Application version\n * This file is auto-generated during build process\n */\n\nexport const VERSION = '0.3.0'\nexport const BUILD_DATE = '2026-02-02T01:21:32.241Z'\n"],
4
+ "sourcesContent": ["/**\n * Application version\n * This file is auto-generated during build process\n */\n\nexport const VERSION = '0.3.3'\nexport const BUILD_DATE = '2026-02-02T12:05:51.819Z'\n"],
5
5
  "mappings": "AAKO,MAAM,UAAU;AAChB,MAAM,aAAa;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@within-7/minto",
3
- "version": "0.3.0",
4
- "bin": {
5
- "minto": "cli.js"
6
- },
7
- "engines": {
8
- "node": ">=20.0.0"
9
- },
10
- "main": "cli.js",
3
+ "version": "0.3.3",
4
+ "description": "AI-powered strategic research and planning assistant",
11
5
  "author": "Lib <within-7>",
12
6
  "license": "Apache-2.0",
13
- "description": "AI-powered strategic research and planning assistant. Facilitates strategic thinking, research coordination, and planning workflows through intelligent conversation.",
14
7
  "homepage": "https://within-7.com/minto",
15
8
  "repository": {
16
9
  "type": "git",
17
- "url": "https://github.com/within-7/minto.git"
10
+ "url": "git+https://github.com/within-7/minto.git"
11
+ },
12
+ "bin": {
13
+ "minto": "cli.js"
14
+ },
15
+ "main": "cli.js",
16
+ "engines": {
17
+ "node": ">=20.0.0"
18
18
  },
19
19
  "files": [
20
20
  "cli.js",
@@ -28,28 +28,22 @@
28
28
  "dev": "bun run ./src/entrypoints/cli.tsx --verbose",
29
29
  "build": "node scripts/build.mjs",
30
30
  "build:packages": "node scripts/build-platform-packages.mjs",
31
- "clean": "rm -rf cli.js binaries packages",
32
- "prepublishOnly": "node scripts/build.mjs && node scripts/prepublish-check.js",
33
- "postinstall": "node scripts/postinstall.js || true",
31
+ "clean": "rm -rf cli.js dist binaries packages",
32
+ "test": "bun test",
33
+ "typecheck": "tsc --noEmit",
34
34
  "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json}\"",
35
35
  "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\"",
36
- "lint": "eslint . --ext .ts,.tsx,.js --max-warnings 0",
37
- "lint:fix": "eslint . --ext .ts,.tsx,.js --fix",
38
- "test": "cd tests && bun test",
39
- "typecheck": "tsc --noEmit",
40
- "prepare": "",
41
- "publish:packages": "node scripts/publish-platform-packages.mjs",
42
- "publish:dev": "node scripts/publish-dev.js",
43
- "publish:release": "node scripts/publish-release.js",
36
+ "prepublishOnly": "node scripts/build.mjs && node scripts/prepublish-check.js",
37
+ "postinstall": "node scripts/postinstall.js || true",
44
38
  "release": "node scripts/release-full.js",
45
39
  "release:dry-run": "node scripts/release-full.js --dry-run"
46
40
  },
47
41
  "optionalDependencies": {
48
- "@within-7/minto-darwin-arm64": "0.3.0",
49
- "@within-7/minto-darwin-x64": "0.3.0",
50
- "@within-7/minto-linux-arm64": "0.3.0",
51
- "@within-7/minto-linux-x64": "0.3.0",
52
- "@within-7/minto-win32-x64": "0.3.0"
42
+ "@within-7/minto-darwin-arm64": "0.3.3",
43
+ "@within-7/minto-darwin-x64": "0.3.3",
44
+ "@within-7/minto-linux-arm64": "0.3.3",
45
+ "@within-7/minto-linux-x64": "0.3.3",
46
+ "@within-7/minto-win32-x64": "0.3.3"
53
47
  },
54
48
  "dependencies": {
55
49
  "@anthropic-ai/bedrock-sdk": "^0.12.6",
@@ -86,7 +80,6 @@
86
80
  "node-html-parser": "^7.0.1",
87
81
  "openai": "^4.104.0",
88
82
  "react": "18.3.1",
89
- "react-devtools-core": "^4.28.5",
90
83
  "semver": "^7.7.2",
91
84
  "shell-quote": "^1.8.3",
92
85
  "signal-exit": "3.0.7",
@@ -102,7 +95,6 @@
102
95
  },
103
96
  "devDependencies": {
104
97
  "@types/bun": "latest",
105
- "@types/jest": "^30.0.0",
106
98
  "@types/minimatch": "6.0.0",
107
99
  "@types/node": "^24.1.0",
108
100
  "bun-types": "latest",