@within-7/minto 0.3.0 → 0.3.4

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 (84) hide show
  1. package/dist/commands/setup.js +40 -2
  2. package/dist/commands/setup.js.map +2 -2
  3. package/dist/components/SubagentProgress.js +10 -2
  4. package/dist/components/SubagentProgress.js.map +2 -2
  5. package/dist/constants/prompts.js +22 -1
  6. package/dist/constants/prompts.js.map +2 -2
  7. package/dist/entrypoints/cli.js +15 -9
  8. package/dist/entrypoints/cli.js.map +2 -2
  9. package/dist/permissions.js +121 -2
  10. package/dist/permissions.js.map +2 -2
  11. package/dist/screens/ResumeConversation.js +2 -0
  12. package/dist/screens/ResumeConversation.js.map +2 -2
  13. package/dist/services/taskStore.js +205 -0
  14. package/dist/services/taskStore.js.map +7 -0
  15. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +40 -3
  16. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  17. package/dist/tools/BashTool/BashTool.js +21 -4
  18. package/dist/tools/BashTool/BashTool.js.map +2 -2
  19. package/dist/tools/BashTool/prompt.js +6 -0
  20. package/dist/tools/BashTool/prompt.js.map +2 -2
  21. package/dist/tools/FileEditTool/FileEditTool.js +24 -9
  22. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  23. package/dist/tools/FileEditTool/prompt.js +4 -1
  24. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  25. package/dist/tools/FileEditTool/utils.js +10 -4
  26. package/dist/tools/FileEditTool/utils.js.map +2 -2
  27. package/dist/tools/FileReadTool/FileReadTool.js +1 -1
  28. package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
  29. package/dist/tools/FileReadTool/prompt.js +16 -1
  30. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  31. package/dist/tools/FileWriteTool/FileWriteTool.js +1 -1
  32. package/dist/tools/FileWriteTool/FileWriteTool.js.map +1 -1
  33. package/dist/tools/FileWriteTool/prompt.js +8 -1
  34. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  35. package/dist/tools/GlobTool/prompt.js +12 -1
  36. package/dist/tools/GlobTool/prompt.js.map +2 -2
  37. package/dist/tools/GrepTool/GrepTool.js +333 -65
  38. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  39. package/dist/tools/GrepTool/prompt.js +15 -8
  40. package/dist/tools/GrepTool/prompt.js.map +2 -2
  41. package/dist/tools/NotebookEditTool/NotebookEditTool.js +57 -45
  42. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  43. package/dist/tools/NotebookEditTool/prompt.js +1 -1
  44. package/dist/tools/NotebookEditTool/prompt.js.map +1 -1
  45. package/dist/tools/TaskCreateTool/TaskCreateTool.js +102 -0
  46. package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +7 -0
  47. package/dist/tools/TaskCreateTool/prompt.js +47 -0
  48. package/dist/tools/TaskCreateTool/prompt.js.map +7 -0
  49. package/dist/tools/TaskGetTool/TaskGetTool.js +115 -0
  50. package/dist/tools/TaskGetTool/TaskGetTool.js.map +7 -0
  51. package/dist/tools/TaskGetTool/prompt.js +28 -0
  52. package/dist/tools/TaskGetTool/prompt.js.map +7 -0
  53. package/dist/tools/TaskListTool/TaskListTool.js +102 -0
  54. package/dist/tools/TaskListTool/TaskListTool.js.map +7 -0
  55. package/dist/tools/TaskListTool/prompt.js +27 -0
  56. package/dist/tools/TaskListTool/prompt.js.map +7 -0
  57. package/dist/tools/TaskStopTool/TaskStopTool.js +150 -0
  58. package/dist/tools/TaskStopTool/TaskStopTool.js.map +7 -0
  59. package/dist/tools/TaskStopTool/prompt.js +15 -0
  60. package/dist/tools/TaskStopTool/prompt.js.map +7 -0
  61. package/dist/tools/TaskTool/TaskTool.js +41 -1
  62. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  63. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +134 -0
  64. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +7 -0
  65. package/dist/tools/TaskUpdateTool/prompt.js +81 -0
  66. package/dist/tools/TaskUpdateTool/prompt.js.map +7 -0
  67. package/dist/tools/URLFetcherTool/prompt.js +1 -1
  68. package/dist/tools/URLFetcherTool/prompt.js.map +1 -1
  69. package/dist/tools.js +12 -0
  70. package/dist/tools.js.map +2 -2
  71. package/dist/utils/config.js.map +2 -2
  72. package/dist/utils/model.js +15 -2
  73. package/dist/utils/model.js.map +2 -2
  74. package/dist/utils/ripgrep.js +53 -1
  75. package/dist/utils/ripgrep.js.map +2 -2
  76. package/dist/utils/teamConfig.js +160 -0
  77. package/dist/utils/teamConfig.js.map +3 -3
  78. package/dist/utils/terminal.js +12 -0
  79. package/dist/utils/terminal.js.map +2 -2
  80. package/dist/utils/tooling/safeRender.js +13 -14
  81. package/dist/utils/tooling/safeRender.js.map +2 -2
  82. package/dist/version.js +2 -2
  83. package/dist/version.js.map +1 -1
  84. package/package.json +20 -28
@@ -21,17 +21,19 @@ const inputSchema = z.strictObject({
21
21
  notebook_path: z.string().describe(
22
22
  "The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)"
23
23
  ),
24
- cell_number: z.number().describe("The index of the cell to edit (0-based)"),
24
+ cell_id: z.string().optional().describe(
25
+ "The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified."
26
+ ),
25
27
  new_source: z.string().describe("The new source for the cell"),
26
28
  cell_type: z.enum(["code", "markdown"]).optional().describe(
27
29
  "The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required."
28
30
  ),
29
- edit_mode: z.string().optional().describe(
31
+ edit_mode: z.enum(["replace", "insert", "delete"]).optional().describe(
30
32
  "The type of edit to make (replace, insert, delete). Defaults to replace."
31
33
  )
32
34
  });
33
35
  const NotebookEditTool = {
34
- name: "NotebookEditCell",
36
+ name: "NotebookEdit",
35
37
  async description() {
36
38
  return DESCRIPTION;
37
39
  },
@@ -54,21 +56,21 @@ const NotebookEditTool = {
54
56
  needsPermissions({ notebook_path }) {
55
57
  return !hasWritePermission(notebook_path);
56
58
  },
57
- renderResultForAssistant({ cell_number, edit_mode, new_source, error }) {
59
+ renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {
58
60
  if (error) {
59
61
  return error;
60
62
  }
61
63
  switch (edit_mode) {
62
64
  case "replace":
63
- return `Updated cell ${cell_number} with ${new_source}`;
65
+ return `Updated cell ${cell_id} with ${new_source}`;
64
66
  case "insert":
65
- return `Inserted cell ${cell_number} with ${new_source}`;
67
+ return `Inserted cell after ${cell_id || "beginning"} with ${new_source}`;
66
68
  case "delete":
67
- return `Deleted cell ${cell_number}`;
69
+ return `Deleted cell ${cell_id}`;
68
70
  }
69
71
  },
70
72
  renderToolUseMessage(input, { verbose }) {
71
- return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell: ${input.cell_number}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? "replace"}`;
73
+ return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || "(beginning)"}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? "replace"}`;
72
74
  },
73
75
  renderToolUseRejectedMessage() {
74
76
  return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
@@ -77,15 +79,15 @@ const NotebookEditTool = {
77
79
  if (!output) {
78
80
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Notebook cell updated"));
79
81
  }
80
- const { cell_number, new_source, language, error } = output;
82
+ const { cell_id, new_source, language, error } = output;
81
83
  if (error) {
82
84
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "red" }, error));
83
85
  }
84
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Updated cell ", cell_number, ":"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(HighlightedCode, { code: new_source, language })));
86
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Updated cell ", cell_id, ":"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(HighlightedCode, { code: new_source, language })));
85
87
  },
86
88
  async validateInput({
87
89
  notebook_path,
88
- cell_number,
90
+ cell_id,
89
91
  cell_type,
90
92
  edit_mode = "replace"
91
93
  }) {
@@ -102,18 +104,6 @@ const NotebookEditTool = {
102
104
  message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`
103
105
  };
104
106
  }
105
- if (cell_number < 0) {
106
- return {
107
- result: false,
108
- message: "Cell number must be non-negative."
109
- };
110
- }
111
- if (edit_mode !== "replace" && edit_mode !== "insert" && edit_mode !== "delete") {
112
- return {
113
- result: false,
114
- message: "Edit mode must be replace, insert, or delete."
115
- };
116
- }
117
107
  if (edit_mode === "insert" && !cell_type) {
118
108
  return {
119
109
  result: false,
@@ -129,48 +119,70 @@ const NotebookEditTool = {
129
119
  message: "Notebook is not valid JSON."
130
120
  };
131
121
  }
132
- if (edit_mode === "insert" && cell_number > notebook.cells.length) {
133
- return {
134
- result: false,
135
- message: `Cell number is out of bounds. For insert mode, the maximum value is ${notebook.cells.length} (to append at the end).`
136
- };
137
- } else if ((edit_mode === "replace" || edit_mode === "delete") && (cell_number >= notebook.cells.length || !notebook.cells[cell_number])) {
122
+ if ((edit_mode === "replace" || edit_mode === "delete") && !cell_id) {
138
123
  return {
139
124
  result: false,
140
- message: `Cell number is out of bounds. Notebook has ${notebook.cells.length} cells.`
125
+ message: "cell_id is required for replace and delete operations."
141
126
  };
142
127
  }
128
+ if (cell_id) {
129
+ const cellIndex = notebook.cells.findIndex(
130
+ (cell, index) => cell.id === cell_id || String(index) === cell_id
131
+ );
132
+ if (cellIndex === -1 && edit_mode !== "insert") {
133
+ return {
134
+ result: false,
135
+ message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`
136
+ };
137
+ }
138
+ }
143
139
  return { result: true };
144
140
  },
145
- async *call({
146
- notebook_path,
147
- cell_number,
148
- new_source,
149
- cell_type,
150
- edit_mode
151
- }) {
141
+ async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {
152
142
  const fullPath = isAbsolute(notebook_path) ? notebook_path : resolve(getCwd(), notebook_path);
153
143
  try {
154
144
  const enc = detectFileEncoding(fullPath);
155
145
  const content = readFileSync(fullPath, enc);
156
146
  const notebook = JSON.parse(content);
157
147
  const language = notebook.metadata.language_info?.name ?? "python";
148
+ const findCellIndex = (id) => {
149
+ if (!id) return 0;
150
+ const byId = notebook.cells.findIndex(
151
+ (cell) => cell.id === id
152
+ );
153
+ if (byId !== -1) return byId;
154
+ const numIndex = parseInt(id, 10);
155
+ if (!isNaN(numIndex) && numIndex >= 0 && numIndex < notebook.cells.length) {
156
+ return numIndex;
157
+ }
158
+ return -1;
159
+ };
160
+ const cellIndex = findCellIndex(cell_id);
158
161
  if (edit_mode === "delete") {
159
- notebook.cells.splice(cell_number, 1);
162
+ if (cellIndex === -1) {
163
+ throw new Error(`Cell with ID '${cell_id}' not found`);
164
+ }
165
+ notebook.cells.splice(cellIndex, 1);
160
166
  } else if (edit_mode === "insert") {
167
+ const insertIndex = cell_id ? cellIndex + 1 : 0;
168
+ const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
161
169
  const new_cell = {
170
+ id: newCellId,
162
171
  cell_type,
163
172
  // validateInput ensures cell_type is not undefined
164
173
  source: new_source,
165
174
  metadata: {}
166
175
  };
167
176
  notebook.cells.splice(
168
- cell_number,
177
+ insertIndex,
169
178
  0,
170
- cell_type == "markdown" ? new_cell : { ...new_cell, outputs: [] }
179
+ cell_type === "markdown" ? new_cell : { ...new_cell, outputs: [] }
171
180
  );
172
181
  } else {
173
- const targetCell = notebook.cells[cell_number];
182
+ if (cellIndex === -1) {
183
+ throw new Error(`Cell with ID '${cell_id}' not found`);
184
+ }
185
+ const targetCell = notebook.cells[cellIndex];
174
186
  targetCell.source = new_source;
175
187
  targetCell.execution_count = void 0;
176
188
  targetCell.outputs = [];
@@ -184,7 +196,7 @@ const NotebookEditTool = {
184
196
  recordFileEdit(fullPath, updatedNotebook);
185
197
  emitReminderEvent("file:edited", {
186
198
  filePath: fullPath,
187
- cellNumber: cell_number,
199
+ cellId: cell_id,
188
200
  newSource: new_source,
189
201
  cellType: cell_type,
190
202
  editMode: edit_mode || "replace",
@@ -192,7 +204,7 @@ const NotebookEditTool = {
192
204
  operation: "notebook_edit"
193
205
  });
194
206
  const data = {
195
- cell_number,
207
+ cell_id: cell_id || "0",
196
208
  new_source,
197
209
  cell_type: cell_type ?? "code",
198
210
  language,
@@ -207,7 +219,7 @@ const NotebookEditTool = {
207
219
  } catch (error) {
208
220
  if (error instanceof Error) {
209
221
  const data2 = {
210
- cell_number,
222
+ cell_id: cell_id || "0",
211
223
  new_source,
212
224
  cell_type: cell_type ?? "code",
213
225
  language: "python",
@@ -222,7 +234,7 @@ const NotebookEditTool = {
222
234
  return;
223
235
  }
224
236
  const data = {
225
- cell_number,
237
+ cell_id: cell_id || "0",
226
238
  new_source,
227
239
  cell_type: cell_type ?? "code",
228
240
  language: "python",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/tools/NotebookEditTool/NotebookEditTool.tsx"],
4
- "sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_number: z.number().describe('The index of the cell to edit (0-based)'),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .string()\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEditCell',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_number, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_number} with ${new_source}`\n case 'insert':\n return `Inserted cell ${cell_number} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_number}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell: ${input.cell_number}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_number, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_number}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_number,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (cell_number < 0) {\n return {\n result: false,\n message: 'Cell number must be non-negative.',\n }\n }\n\n if (\n edit_mode !== 'replace' &&\n edit_mode !== 'insert' &&\n edit_mode !== 'delete'\n ) {\n return {\n result: false,\n message: 'Edit mode must be replace, insert, or delete.',\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n if (edit_mode === 'insert' && cell_number > notebook.cells.length) {\n return {\n result: false,\n message: `Cell number is out of bounds. For insert mode, the maximum value is ${notebook.cells.length} (to append at the end).`,\n }\n } else if (\n (edit_mode === 'replace' || edit_mode === 'delete') &&\n (cell_number >= notebook.cells.length || !notebook.cells[cell_number])\n ) {\n return {\n result: false,\n message: `Cell number is out of bounds. Notebook has ${notebook.cells.length} cells.`,\n }\n }\n\n return { result: true }\n },\n async *call({\n notebook_path,\n cell_number,\n new_source,\n cell_type,\n edit_mode,\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n notebook.cells.splice(cell_number, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell\n const new_cell = {\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n cell_number,\n 0,\n cell_type == 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Find the specified cell\n const targetCell = notebook.cells[cell_number]! // validateInput ensures cell_number is in bounds\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellNumber: cell_number,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n {\n cell_number: number\n new_source: string\n cell_type: NotebookCellType\n language: string\n edit_mode: string\n error?: string\n }\n>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_id: z\n .string()\n .optional()\n .describe(\n 'The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified.',\n ),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .enum(['replace', 'insert', 'delete'])\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEdit',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_id} with ${new_source}`\n case 'insert':\n return `Inserted cell after ${cell_id || 'beginning'} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_id}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || '(beginning)'}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_id, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_id}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_id,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n // For replace and delete, cell_id is required and must exist\n if ((edit_mode === 'replace' || edit_mode === 'delete') && !cell_id) {\n return {\n result: false,\n message: 'cell_id is required for replace and delete operations.',\n }\n }\n\n // Validate cell_id exists in notebook (if provided)\n if (cell_id) {\n const cellIndex = notebook.cells.findIndex(\n (cell: { id?: string }, index: number) =>\n cell.id === cell_id || String(index) === cell_id,\n )\n if (cellIndex === -1 && edit_mode !== 'insert') {\n return {\n result: false,\n message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n // Find cell index by ID (or treat cell_id as index string for backward compatibility)\n const findCellIndex = (id: string | undefined): number => {\n if (!id) return 0 // Insert at beginning if no cell_id\n const byId = notebook.cells.findIndex(\n (cell: { id?: string }) => cell.id === id,\n )\n if (byId !== -1) return byId\n // Fallback: treat as numeric index for backward compatibility\n const numIndex = parseInt(id, 10)\n if (\n !isNaN(numIndex) &&\n numIndex >= 0 &&\n numIndex < notebook.cells.length\n ) {\n return numIndex\n }\n return -1\n }\n\n const cellIndex = findCellIndex(cell_id)\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n notebook.cells.splice(cellIndex, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell after the specified cell (or at beginning if no cell_id)\n const insertIndex = cell_id ? cellIndex + 1 : 0\n const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n const new_cell = {\n id: newCellId,\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n insertIndex,\n 0,\n cell_type === 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Replace: Find the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n const targetCell = notebook.cells[cellIndex]!\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellId: cell_id,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n {\n cell_id: string\n new_source: string\n cell_type: NotebookCellType\n language: string\n edit_mode: string\n error?: string\n }\n>\n"],
5
+ "mappings": "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",
6
6
  "names": ["data"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  const DESCRIPTION = "Replace the contents of a specific cell in a Jupyter notebook.";
2
- const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number.`;
2
+ const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_id is the ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified. Use edit_mode=insert to add a new cell at the index specified by cell_id. Use edit_mode=delete to delete the cell at the index specified by cell_id.`;
3
3
  export {
4
4
  DESCRIPTION,
5
5
  PROMPT
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/tools/NotebookEditTool/prompt.ts"],
4
- "sourcesContent": ["export const DESCRIPTION =\n 'Replace the contents of a specific cell in a Jupyter notebook.'\nexport const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number.`\n"],
4
+ "sourcesContent": ["export const DESCRIPTION =\n 'Replace the contents of a specific cell in a Jupyter notebook.'\nexport const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_id is the ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified. Use edit_mode=insert to add a new cell at the index specified by cell_id. Use edit_mode=delete to delete the cell at the index specified by cell_id.`\n"],
5
5
  "mappings": "AAAO,MAAM,cACX;AACK,MAAM,SAAS;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,102 @@
1
+ import { Box, Text } from "ink";
2
+ import * as React from "react";
3
+ import { z } from "zod";
4
+ import { FallbackToolUseRejectedMessage } from "../../components/FallbackToolUseRejectedMessage.js";
5
+ import { createTask } from "../../services/taskStore.js";
6
+ import { DESCRIPTION, PROMPT } from "./prompt.js";
7
+ import { getTheme } from "../../utils/theme.js";
8
+ const inputSchema = z.strictObject({
9
+ subject: z.string().describe("A brief title for the task"),
10
+ description: z.string().describe("A detailed description of what needs to be done"),
11
+ activeForm: z.string().optional().describe(
12
+ 'Present continuous form shown in spinner when in_progress (e.g., "Running tests")'
13
+ ),
14
+ metadata: z.record(z.unknown()).optional().describe("Arbitrary metadata to attach to the task")
15
+ });
16
+ const TaskCreateTool = {
17
+ name: "TaskCreate",
18
+ async description() {
19
+ return DESCRIPTION;
20
+ },
21
+ async prompt() {
22
+ return PROMPT;
23
+ },
24
+ inputSchema,
25
+ userFacingName() {
26
+ return "Create Task";
27
+ },
28
+ async isEnabled() {
29
+ return true;
30
+ },
31
+ isReadOnly() {
32
+ return false;
33
+ },
34
+ isConcurrencySafe() {
35
+ return false;
36
+ },
37
+ needsPermissions() {
38
+ return false;
39
+ },
40
+ renderToolUseMessage(input) {
41
+ const subject = input.subject || "";
42
+ const truncated = subject.length > 50 ? subject.slice(0, 50) + "..." : subject;
43
+ return `subject: "${truncated}"`;
44
+ },
45
+ renderToolUseRejectedMessage() {
46
+ return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
47
+ },
48
+ renderToolResultMessage(output) {
49
+ if (!output || !output.taskId) {
50
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, null, "Task created"));
51
+ }
52
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: getTheme().success }, "Task #", output.taskId, " created: ", output.subject));
53
+ },
54
+ renderResultForAssistant(result) {
55
+ return `Task #${result.taskId} created successfully: ${result.subject}`;
56
+ },
57
+ async validateInput({ subject, description }) {
58
+ if (!subject?.trim()) {
59
+ return {
60
+ result: false,
61
+ message: "Task subject cannot be empty"
62
+ };
63
+ }
64
+ if (!description?.trim()) {
65
+ return {
66
+ result: false,
67
+ message: "Task description cannot be empty"
68
+ };
69
+ }
70
+ return { result: true };
71
+ },
72
+ async *call(input) {
73
+ try {
74
+ const task = createTask({
75
+ subject: input.subject,
76
+ description: input.description,
77
+ activeForm: input.activeForm,
78
+ metadata: input.metadata
79
+ });
80
+ const result = {
81
+ taskId: task.id,
82
+ subject: task.subject
83
+ };
84
+ yield {
85
+ type: "result",
86
+ data: result,
87
+ resultForAssistant: this.renderResultForAssistant(result)
88
+ };
89
+ } catch (error) {
90
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
91
+ yield {
92
+ type: "result",
93
+ data: { error: errorMessage },
94
+ resultForAssistant: `Error creating task: ${errorMessage}`
95
+ };
96
+ }
97
+ }
98
+ };
99
+ export {
100
+ TaskCreateTool
101
+ };
102
+ //# sourceMappingURL=TaskCreateTool.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/TaskCreateTool/TaskCreateTool.tsx"],
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { createTask } from '@services/taskStore'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n subject: z.string().describe('A brief title for the task'),\n description: z\n .string()\n .describe('A detailed description of what needs to be done'),\n activeForm: z\n .string()\n .optional()\n .describe(\n 'Present continuous form shown in spinner when in_progress (e.g., \"Running tests\")',\n ),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Arbitrary metadata to attach to the task'),\n})\n\nexport const TaskCreateTool = {\n name: 'TaskCreate',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Create Task'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false\n },\n needsPermissions() {\n return false\n },\n renderToolUseMessage(input: z.infer<typeof inputSchema>) {\n const subject = input.subject || ''\n const truncated =\n subject.length > 50 ? subject.slice(0, 50) + '...' : subject\n return `subject: \"${truncated}\"`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output: { taskId: string; subject: string }) {\n if (!output || !output.taskId) {\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text>Task created</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={getTheme().success}>\n Task #{output.taskId} created: {output.subject}\n </Text>\n </Box>\n )\n },\n renderResultForAssistant(result: { taskId: string; subject: string }) {\n return `Task #${result.taskId} created successfully: ${result.subject}`\n },\n async validateInput({ subject, description }: z.infer<typeof inputSchema>) {\n if (!subject?.trim()) {\n return {\n result: false,\n message: 'Task subject cannot be empty',\n }\n }\n if (!description?.trim()) {\n return {\n result: false,\n message: 'Task description cannot be empty',\n }\n }\n return { result: true }\n },\n async *call(input: z.infer<typeof inputSchema>) {\n try {\n const task = createTask({\n subject: input.subject,\n description: input.description,\n activeForm: input.activeForm,\n metadata: input.metadata,\n })\n\n const result = {\n taskId: task.id,\n subject: task.subject,\n }\n\n yield {\n type: 'result',\n data: result,\n resultForAssistant: this.renderResultForAssistant(result),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n yield {\n type: 'result',\n data: { error: errorMessage },\n resultForAssistant: `Error creating task: ${errorMessage}`,\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n { taskId: string; subject: string } | { error: string }\n>\n"],
5
+ "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,kBAAkB;AAC3B,SAAS,aAAa,cAAc;AACpC,SAAS,gBAAgB;AAEzB,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,SAAS,EAAE,OAAO,EAAE,SAAS,4BAA4B;AAAA,EACzD,aAAa,EACV,OAAO,EACP,SAAS,iDAAiD;AAAA,EAC7D,YAAY,EACT,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,UAAU,EACP,OAAO,EAAE,QAAQ,CAAC,EAClB,SAAS,EACT,SAAS,0CAA0C;AACxD,CAAC;AAEM,MAAM,iBAAiB;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;AAChB,WAAO;AAAA,EACT;AAAA,EACA,aAAa;AACX,WAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAClB,WAAO;AAAA,EACT;AAAA,EACA,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,qBAAqB,OAAoC;AACvD,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,YACJ,QAAQ,SAAS,KAAK,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AACvD,WAAO,aAAa,SAAS;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAC7B,WAAO,oCAAC,oCAA+B;AAAA,EACzC;AAAA,EACA,wBAAwB,QAA6C;AACnE,QAAI,CAAC,UAAU,CAAC,OAAO,QAAQ;AAC7B,aACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,YAAK,cAAY,CACpB;AAAA,IAEJ;AAEA,WACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,WAAS,UACxB,OAAO,QAAO,cAAW,OAAO,OACzC,CACF;AAAA,EAEJ;AAAA,EACA,yBAAyB,QAA6C;AACpE,WAAO,SAAS,OAAO,MAAM,0BAA0B,OAAO,OAAO;AAAA,EACvE;AAAA,EACA,MAAM,cAAc,EAAE,SAAS,YAAY,GAAgC;AACzE,QAAI,CAAC,SAAS,KAAK,GAAG;AACpB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AACA,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAAA,EACA,OAAO,KAAK,OAAoC;AAC9C,QAAI;AACF,YAAM,OAAO,WAAW;AAAA,QACtB,SAAS,MAAM;AAAA,QACf,aAAa,MAAM;AAAA,QACnB,YAAY,MAAM;AAAA,QAClB,UAAU,MAAM;AAAA,MAClB,CAAC;AAED,YAAM,SAAS;AAAA,QACb,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,MAChB;AAEA,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,MAAM;AAAA,QACN,oBAAoB,KAAK,yBAAyB,MAAM;AAAA,MAC1D;AAAA,IACF,SAAS,OAAO;AACd,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,MAAM,EAAE,OAAO,aAAa;AAAA,QAC5B,oBAAoB,wBAAwB,YAAY;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,47 @@
1
+ const PROMPT = `Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
2
+ It also helps the user understand the progress of the task and overall progress of their requests.
3
+
4
+ ## When to Use This Tool
5
+
6
+ Use this tool proactively in these scenarios:
7
+
8
+ - Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
9
+ - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
10
+ - Plan mode - When using plan mode, create a task list to track the work
11
+ - User explicitly requests todo list - When the user directly asks you to use the todo list
12
+ - User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
13
+ - After receiving new instructions - Immediately capture user requirements as tasks
14
+ - When you start working on a task - Mark it as in_progress BEFORE beginning work
15
+ - After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
16
+
17
+ ## When NOT to Use This Tool
18
+
19
+ Skip using this tool when:
20
+ - There is only a single, straightforward task
21
+ - The task is trivial and tracking it provides no organizational benefit
22
+ - The task can be completed in less than 3 trivial steps
23
+ - The task is purely conversational or informational
24
+
25
+ NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
26
+
27
+ ## Task Fields
28
+
29
+ - **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
30
+ - **description**: Detailed description of what needs to be done, including context and acceptance criteria
31
+ - **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.
32
+
33
+ **IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests"). All tasks are created with status \`pending\`.
34
+
35
+ ## Tips
36
+
37
+ - Create tasks with clear, specific subjects that describe the outcome
38
+ - Include enough detail in the description for another agent to understand and complete the task
39
+ - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
40
+ - Check TaskList first to avoid creating duplicate tasks
41
+ `;
42
+ const DESCRIPTION = "Create a new task to track progress on complex work";
43
+ export {
44
+ DESCRIPTION,
45
+ PROMPT
46
+ };
47
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/TaskCreateTool/prompt.ts"],
4
+ "sourcesContent": ["export const PROMPT = `Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.\nIt also helps the user understand the progress of the task and overall progress of their requests.\n\n## When to Use This Tool\n\nUse this tool proactively in these scenarios:\n\n- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions\n- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations\n- Plan mode - When using plan mode, create a task list to track the work\n- User explicitly requests todo list - When the user directly asks you to use the todo list\n- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)\n- After receiving new instructions - Immediately capture user requirements as tasks\n- When you start working on a task - Mark it as in_progress BEFORE beginning work\n- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation\n\n## When NOT to Use This Tool\n\nSkip using this tool when:\n- There is only a single, straightforward task\n- The task is trivial and tracking it provides no organizational benefit\n- The task can be completed in less than 3 trivial steps\n- The task is purely conversational or informational\n\nNOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.\n\n## Task Fields\n\n- **subject**: A brief, actionable title in imperative form (e.g., \"Fix authentication bug in login flow\")\n- **description**: Detailed description of what needs to be done, including context and acceptance criteria\n- **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., \"Fixing authentication bug\"). This is displayed to the user while you work on the task.\n\n**IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative (\"Run tests\") while activeForm should be present continuous (\"Running tests\"). All tasks are created with status \\`pending\\`.\n\n## Tips\n\n- Create tasks with clear, specific subjects that describe the outcome\n- Include enough detail in the description for another agent to understand and complete the task\n- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed\n- Check TaskList first to avoid creating duplicate tasks\n`\n\nexport const DESCRIPTION = 'Create a new task to track progress on complex work'\n"],
5
+ "mappings": "AAAO,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0Cf,MAAM,cAAc;",
6
+ "names": []
7
+ }
@@ -0,0 +1,115 @@
1
+ import { Box, Text } from "ink";
2
+ import * as React from "react";
3
+ import { z } from "zod";
4
+ import { FallbackToolUseRejectedMessage } from "../../components/FallbackToolUseRejectedMessage.js";
5
+ import { getTaskById } from "../../services/taskStore.js";
6
+ import { DESCRIPTION, PROMPT } from "./prompt.js";
7
+ import { getTheme } from "../../utils/theme.js";
8
+ const inputSchema = z.strictObject({
9
+ taskId: z.string().describe("The ID of the task to retrieve")
10
+ });
11
+ const TaskGetTool = {
12
+ name: "TaskGet",
13
+ async description() {
14
+ return DESCRIPTION;
15
+ },
16
+ async prompt() {
17
+ return PROMPT;
18
+ },
19
+ inputSchema,
20
+ userFacingName() {
21
+ return "Get Task";
22
+ },
23
+ async isEnabled() {
24
+ return true;
25
+ },
26
+ isReadOnly() {
27
+ return true;
28
+ },
29
+ isConcurrencySafe() {
30
+ return true;
31
+ },
32
+ needsPermissions() {
33
+ return false;
34
+ },
35
+ renderToolUseMessage(input) {
36
+ return `taskId: ${input.taskId}`;
37
+ },
38
+ renderToolUseRejectedMessage() {
39
+ return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
40
+ },
41
+ renderToolResultMessage(output) {
42
+ if (!output || "error" in output) {
43
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: getTheme().error }, output && "error" in output ? output.error : "Task not found"));
44
+ }
45
+ const statusColor = output.status === "completed" ? getTheme().success : output.status === "in_progress" ? getTheme().warning : getTheme().secondaryText;
46
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { bold: true }, "#", output.id), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, null, output.subject)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", paddingLeft: 5 }, /* @__PURE__ */ React.createElement(Text, { color: statusColor }, "[", output.status, "]"), output.owner && /* @__PURE__ */ React.createElement(Text, { color: getTheme().secondaryText }, " owner: ", output.owner)));
47
+ },
48
+ renderResultForAssistant(result) {
49
+ if ("error" in result) {
50
+ return `Error: ${result.error}`;
51
+ }
52
+ const lines = [
53
+ `Task #${result.id}:`,
54
+ ` Subject: ${result.subject}`,
55
+ ` Status: ${result.status}`,
56
+ ` Description: ${result.description}`
57
+ ];
58
+ if (result.activeForm) {
59
+ lines.push(` Active Form: ${result.activeForm}`);
60
+ }
61
+ if (result.owner) {
62
+ lines.push(` Owner: ${result.owner}`);
63
+ }
64
+ if (result.blocks && result.blocks.length > 0) {
65
+ lines.push(` Blocks: [${result.blocks.join(", ")}]`);
66
+ }
67
+ if (result.blockedBy && result.blockedBy.length > 0) {
68
+ lines.push(` Blocked By: [${result.blockedBy.join(", ")}]`);
69
+ }
70
+ if (result.metadata && Object.keys(result.metadata).length > 0) {
71
+ lines.push(` Metadata: ${JSON.stringify(result.metadata)}`);
72
+ }
73
+ return lines.join("\n");
74
+ },
75
+ async validateInput({ taskId }) {
76
+ if (!taskId?.trim()) {
77
+ return {
78
+ result: false,
79
+ message: "Task ID is required"
80
+ };
81
+ }
82
+ return { result: true };
83
+ },
84
+ async *call(input) {
85
+ try {
86
+ const task = getTaskById(input.taskId);
87
+ if (!task) {
88
+ const result = { error: `Task with ID '${input.taskId}' not found` };
89
+ yield {
90
+ type: "result",
91
+ data: result,
92
+ resultForAssistant: this.renderResultForAssistant(result)
93
+ };
94
+ return;
95
+ }
96
+ yield {
97
+ type: "result",
98
+ data: task,
99
+ resultForAssistant: this.renderResultForAssistant(task)
100
+ };
101
+ } catch (error) {
102
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
103
+ const result = { error: errorMessage };
104
+ yield {
105
+ type: "result",
106
+ data: result,
107
+ resultForAssistant: `Error getting task: ${errorMessage}`
108
+ };
109
+ }
110
+ }
111
+ };
112
+ export {
113
+ TaskGetTool
114
+ };
115
+ //# sourceMappingURL=TaskGetTool.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/TaskGetTool/TaskGetTool.tsx"],
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { getTaskById, Task } from '@services/taskStore'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n taskId: z.string().describe('The ID of the task to retrieve'),\n})\n\nexport const TaskGetTool = {\n name: 'TaskGet',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Get Task'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true\n },\n needsPermissions() {\n return false\n },\n renderToolUseMessage(input: z.infer<typeof inputSchema>) {\n return `taskId: ${input.taskId}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output: Task | { error: string }) {\n if (!output || 'error' in output) {\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={getTheme().error}>\n {output && 'error' in output ? output.error : 'Task not found'}\n </Text>\n </Box>\n )\n }\n\n const statusColor =\n output.status === 'completed'\n ? getTheme().success\n : output.status === 'in_progress'\n ? getTheme().warning\n : getTheme().secondaryText\n\n return (\n <Box flexDirection=\"column\">\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text bold>#{output.id}</Text>\n <Text> </Text>\n <Text>{output.subject}</Text>\n </Box>\n <Box flexDirection=\"row\" paddingLeft={5}>\n <Text color={statusColor}>[{output.status}]</Text>\n {output.owner && (\n <Text color={getTheme().secondaryText}> owner: {output.owner}</Text>\n )}\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(result: Task | { error: string }) {\n if ('error' in result) {\n return `Error: ${result.error}`\n }\n\n const lines: string[] = [\n `Task #${result.id}:`,\n ` Subject: ${result.subject}`,\n ` Status: ${result.status}`,\n ` Description: ${result.description}`,\n ]\n\n if (result.activeForm) {\n lines.push(` Active Form: ${result.activeForm}`)\n }\n if (result.owner) {\n lines.push(` Owner: ${result.owner}`)\n }\n if (result.blocks && result.blocks.length > 0) {\n lines.push(` Blocks: [${result.blocks.join(', ')}]`)\n }\n if (result.blockedBy && result.blockedBy.length > 0) {\n lines.push(` Blocked By: [${result.blockedBy.join(', ')}]`)\n }\n if (result.metadata && Object.keys(result.metadata).length > 0) {\n lines.push(` Metadata: ${JSON.stringify(result.metadata)}`)\n }\n\n return lines.join('\\n')\n },\n async validateInput({ taskId }: z.infer<typeof inputSchema>) {\n if (!taskId?.trim()) {\n return {\n result: false,\n message: 'Task ID is required',\n }\n }\n return { result: true }\n },\n async *call(input: z.infer<typeof inputSchema>) {\n try {\n const task = getTaskById(input.taskId)\n\n if (!task) {\n const result = { error: `Task with ID '${input.taskId}' not found` }\n yield {\n type: 'result',\n data: result,\n resultForAssistant: this.renderResultForAssistant(result),\n }\n return\n }\n\n yield {\n type: 'result',\n data: task,\n resultForAssistant: this.renderResultForAssistant(task),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const result = { error: errorMessage }\n yield {\n type: 'result',\n data: result,\n resultForAssistant: `Error getting task: ${errorMessage}`,\n }\n }\n },\n} satisfies Tool<typeof inputSchema, Task | { error: string }>\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }