shortcutxl 0.3.48 → 0.3.49

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 (61) hide show
  1. package/CHANGELOG.md +17 -11
  2. package/agent-docs/docs/tui.md +24 -0
  3. package/agent-docs/examples/rpc-extension-ui.ts +1 -1
  4. package/dist/app/agent-session.d.ts +2 -3
  5. package/dist/app/agent-session.js +3 -7
  6. package/dist/app/prompts/com-api-reference.json +215 -146
  7. package/dist/app/subagents/clone/agent.js +2 -2
  8. package/dist/app/subagents/defaults.d.ts +1 -0
  9. package/dist/app/subagents/defaults.js +1 -0
  10. package/dist/app/subagents/document-reader/agent.js +2 -2
  11. package/dist/app/subagents/general/agent.js +2 -2
  12. package/dist/app/subagents/index.d.ts +1 -1
  13. package/dist/app/subagents/index.js +1 -1
  14. package/dist/app/subagents/simulation/agent.js +2 -2
  15. package/dist/app/subagents/verification/agent.js +2 -2
  16. package/dist/app/subagents/workbook-reader/agent.js +2 -2
  17. package/dist/app/tools/task/task.js +2 -2
  18. package/dist/cli/config-selector.js +1 -1
  19. package/dist/cli/session-picker.js +1 -1
  20. package/dist/cli.js +1080 -1082
  21. package/dist/constants.d.ts +4 -0
  22. package/dist/constants.js +17 -0
  23. package/dist/embedded-agent/host-tools/task/agent-definition.d.ts +1 -0
  24. package/dist/embedded-agent/host-tools/task/agent-definition.js +1 -1
  25. package/dist/embedded-agent/host-tools/task/agents/document-reader.d.ts +1 -1
  26. package/dist/embedded-agent/host-tools/task/agents/document-reader.js +2 -2
  27. package/dist/embedded-agent/host-tools/task/agents/general.d.ts +1 -1
  28. package/dist/embedded-agent/host-tools/task/agents/general.js +2 -2
  29. package/dist/embedded-agent/host-tools/task/agents/verification.d.ts +1 -1
  30. package/dist/embedded-agent/host-tools/task/agents/verification.js +2 -2
  31. package/dist/embedded-agent/host-tools/task/agents/workbook-reader.d.ts +1 -1
  32. package/dist/embedded-agent/host-tools/task/agents/workbook-reader.js +2 -2
  33. package/dist/rpc/rpc-mode.js +1 -1
  34. package/dist/shell/components/interactive-shell-layout.d.ts +16 -0
  35. package/dist/shell/components/interactive-shell-layout.js +90 -0
  36. package/dist/shell/dev/interactive-render-trace.d.ts +3 -0
  37. package/dist/shell/dev/interactive-render-trace.js +39 -0
  38. package/dist/shell/interactive/interactive-mode-options.d.ts +1 -0
  39. package/dist/shell/interactive/interactive-mode.d.ts +7 -0
  40. package/dist/shell/interactive/interactive-mode.js +87 -13
  41. package/dist/shell/interactive/super-fight-ui.d.ts +3 -2
  42. package/dist/shell/interactive/super-fight-ui.js +7 -6
  43. package/dist/tui/index.d.ts +1 -0
  44. package/dist/tui/index.js +1 -1
  45. package/dist/tui/keys.d.ts +14 -0
  46. package/dist/tui/keys.js +78 -0
  47. package/dist/tui/render-trace.d.ts +32 -0
  48. package/dist/tui/render-trace.js +293 -0
  49. package/dist/tui/terminal.d.ts +11 -0
  50. package/dist/tui/terminal.js +43 -15
  51. package/dist/tui/tui.d.ts +34 -0
  52. package/dist/tui/tui.js +359 -99
  53. package/package.json +291 -290
  54. package/skills/advanced-mog-api/api-reference.json +9291 -9291
  55. package/user-docs/dist/shortcutxl-docs.pdf +0 -0
  56. package/xll/python/Lib/site-packages/httpx-0.28.1.dist-info/RECORD +1 -1
  57. package/xll/python/Lib/site-packages/pip-26.1.1.dist-info/RECORD +3 -3
  58. package/xll/python/Scripts/httpx.exe +0 -0
  59. package/xll/python/Scripts/pip.exe +0 -0
  60. package/xll/python/Scripts/pip3.12.exe +0 -0
  61. package/xll/python/Scripts/pip3.exe +0 -0
package/CHANGELOG.md CHANGED
@@ -1,14 +1,20 @@
1
- # Changelog
2
-
3
- ## [0.3.48]
4
-
5
- - **Background subagents** - Subagents can now work in the background, be steered during conversations, be revived for additional tasks once they are done, and have their statuses surfaced in the UI.
6
- - **Skill proposals** - ShortcutXL now automatically browses through past sessions and suggests new skills and skill modifications.
7
-
8
- ## [0.3.47]
9
-
10
- - **GPT-5.5** — Upgraded the OpenAI reasoning model from GPT-5.4 to GPT-5.5 (400K context window, stronger reasoning).
11
- - **Out-of-credits message** When your credit balance runs out, ShortcutXL now shows a clear message instead of silently failing.
1
+ # Changelog
2
+
3
+ ## [0.3.49]
4
+
5
+ - **Transcript scrolling & rendering** - Long conversations now scroll more cleanly with mouse wheel, PageUp/PageDown, and Ctrl+Home/Ctrl+End support while the editor and footer stay pinned.
6
+ - **Longer-running task agents** - Background task agents now get a 30-minute default timeout, reducing early timeouts on bigger jobs.
7
+ - **Clearer path-based skills** - Skills loaded from custom folders are grouped by their real root paths so the agent can find and use them more reliably.
8
+
9
+ ## [0.3.48]
10
+
11
+ - **Background subagents** - Subagents can now work in the background, be steered during conversations, be revived for additional tasks once they are done, and have their statuses surfaced in the UI.
12
+ - **Skill proposals** - ShortcutXL now automatically browses through past sessions and suggests new skills and skill modifications.
13
+
14
+ ## [0.3.47]
15
+
16
+ - **GPT-5.5** — Upgraded the OpenAI reasoning model from GPT-5.4 to GPT-5.5 (400K context window, stronger reasoning).
17
+ - **Out-of-credits message** — When your credit balance runs out, ShortcutXL now shows a clear message instead of silently failing.
12
18
 
13
19
  ## [0.3.46]
14
20
 
@@ -28,6 +28,8 @@ interface Component {
28
28
 
29
29
  The TUI appends a full SGR reset and OSC 8 reset at the end of each rendered line. Styles do not carry across lines. If you emit multi-line text with styling, reapply styles per line or use `wrapTextWithAnsi()` so styles are preserved for each wrapped line.
30
30
 
31
+ Shortcut's interactive shell configures `ProcessTerminal` to use the terminal alternate screen buffer. The main transcript is an app-owned scroll viewport, not native terminal scrollback. In that shell, PageUp/PageDown, Ctrl+Home/Ctrl+End, and mouse wheel input scroll the transcript while the editor/footer remain pinned. Fullscreen custom views should clear/redraw inside the existing alternate buffer instead of entering or leaving alternate-buffer mode themselves.
32
+
31
33
  ## Focusable Interface (IME Support)
32
34
 
33
35
  Components that display a text cursor and need IME (Input Method Editor) support should implement the `Focusable` interface:
@@ -445,12 +447,34 @@ interface MyTheme {
445
447
 
446
448
  ## Debug logging
447
449
 
450
+ `ProcessTerminal` only enters the alternate screen buffer (`CSI ? 1049 h`) when `useAlternateBuffer: true` is passed. Shortcut's interactive shell enables that mode; full-screen subviews should clear and redraw inside the existing TUI buffer instead of entering or leaving alternate buffer themselves.
451
+
452
+ Set `SHORTCUT_TUI_RENDER_TRACE=1` to capture a structured JSONL trace of TUI rendering decisions, input events, overlay/focus state, cursor movement, changed line hashes/previews, and ANSI write summaries. By default this writes to `~/.shortcut/agent/tui-render-traces/<timestamp>-<pid>.jsonl`. Set it to a file path to choose the destination. Add `SHORTCUT_TUI_RENDER_TRACE_FULL=1` to include full rendered lines and full write buffers; leave it off for smaller logs.
453
+
454
+ ```bash
455
+ SHORTCUT_TUI_RENDER_TRACE=1 shortcut
456
+ SHORTCUT_TUI_RENDER_TRACE=C:\temp\shortcut-tui.jsonl SHORTCUT_TUI_RENDER_TRACE_FULL=1 shortcut
457
+ ```
458
+
448
459
  Set `SHORTCUT_TUI_WRITE_LOG` to capture the raw ANSI stream written to stdout.
449
460
 
450
461
  ```bash
451
462
  SHORTCUT_TUI_WRITE_LOG=/tmp/tui-ansi.log npx tsx packages/tui/test/chat-simple.ts
452
463
  ```
453
464
 
465
+ Summarize a captured trace with:
466
+
467
+ ```bash
468
+ npm run analyze:tui-trace -- C:\temp\shortcut-tui.jsonl
469
+ npm run analyze:tui-trace -- C:\temp\shortcut-tui.jsonl --json
470
+ ```
471
+
472
+ For deterministic repro coverage, run the PTY render matrix:
473
+
474
+ ```bash
475
+ npm run test:pty -- tests/interactive/tui-render-matrix/tui-render-matrix.pty.test.ts
476
+ ```
477
+
454
478
  ## Performance
455
479
 
456
480
  Cache rendered output when possible:
@@ -274,7 +274,7 @@ async function main() {
274
274
 
275
275
  // -- TUI setup --
276
276
 
277
- const terminal = new ProcessTerminal();
277
+ const terminal = new ProcessTerminal({ useAlternateBuffer: true });
278
278
  const tui = new TUI(terminal);
279
279
 
280
280
  const outputLog = new OutputLog();
@@ -137,7 +137,7 @@ export interface PromptOptions {
137
137
  expandPromptTemplates?: boolean;
138
138
  /** Image attachments */
139
139
  images?: ImageContent[];
140
- /** When streaming, how to queue the message: "steer" (interrupt) or "followUp" (wait). Required if streaming. */
140
+ /** When streaming, how to queue the message: "steer" (interrupt) or "followUp" (wait). Defaults to "steer". */
141
141
  streamingBehavior?: 'steer' | 'followUp';
142
142
  /** Source of input for extension input event handlers. Defaults to "interactive". */
143
143
  source?: InputSource;
@@ -322,9 +322,8 @@ export declare class AgentSession {
322
322
  /**
323
323
  * Send a prompt to the agent.
324
324
  * - Expands file-based prompt templates by default
325
- * - During streaming, queues via steer() or followUp() based on streamingBehavior option
325
+ * - During streaming, queues via steer() by default, or followUp() when requested
326
326
  * - Validates model and API key before sending (when not streaming)
327
- * @throws Error if streaming and no streamingBehavior specified
328
327
  * @throws Error if no model selected or no API key available (when not streaming)
329
328
  */
330
329
  prompt(text: string, options?: PromptOptions): Promise<void>;
@@ -734,9 +734,8 @@ export class AgentSession {
734
734
  /**
735
735
  * Send a prompt to the agent.
736
736
  * - Expands file-based prompt templates by default
737
- * - During streaming, queues via steer() or followUp() based on streamingBehavior option
737
+ * - During streaming, queues via steer() by default, or followUp() when requested
738
738
  * - Validates model and API key before sending (when not streaming)
739
- * @throws Error if streaming and no streamingBehavior specified
740
739
  * @throws Error if no model selected or no API key available (when not streaming)
741
740
  */
742
741
  async prompt(text, options) {
@@ -756,12 +755,9 @@ export class AgentSession {
756
755
  currentText = parsedBudget.task;
757
756
  }
758
757
  const expandedText = currentText;
759
- // If streaming, queue via steer() or followUp() based on option
758
+ // If streaming, queue via steer() by default; follow-up is opt-in.
760
759
  if (this.isStreaming) {
761
- if (!options?.streamingBehavior) {
762
- throw new Error("AgentController is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
763
- }
764
- if (options.streamingBehavior === 'followUp') {
760
+ if (options?.streamingBehavior === 'followUp') {
765
761
  await this._queueFollowUp(expandedText, currentImages);
766
762
  }
767
763
  else {
@@ -1,146 +1,215 @@
1
- {
2
- "interfaces": {
3
- "Workbook": {
4
- "docstring": "Workbook wrapper.\nUsage:\n wb = Workbook(app.Workbooks(\"MyFile.xlsx\"))\n\nRaw COM access:\n wb._wb \u2014 the underlying COM Workbook object for direct platform API calls.\n Example: wb._wb.Worksheets(\"Sheet1\").Visible = False",
5
- "functions": {
6
- "getSheetNames": {
7
- "signature": "def getSheetNames() -> list[str]",
8
- "docstring": "Get the names of all sheets in the workbook.",
9
- "tags": ["action", "ask"]
10
- },
11
- "getWorkbookSummary": {
12
- "signature": "def getWorkbookSummary() -> str",
13
- "docstring": "Get sheet names and used ranges for this workbook.\nReturns lines like:\n Sheets and their used ranges:\n Sheet1: A1:D10 (active)\n Inputs: (empty)",
14
- "tags": ["action", "ask"]
15
- },
16
- "getSheet": {
17
- "signature": "def getSheet(name: str) -> 'Worksheet'",
18
- "docstring": "Get a sheet by name, returned as a wrapped Worksheet.",
19
- "tags": ["action", "ask"]
20
- },
21
- "addSheet": {
22
- "signature": "def addSheet(name: str, index: int | None = None) -> 'Worksheet'",
23
- "docstring": "Add a new sheet at 0-based index. index=0 inserts before the first sheet.\nOmit index for Excel's default position.\nExample: wb.addSheet(\"NewSheet\", 0) # insert as first sheet",
24
- "tags": ["action"]
25
- },
26
- "moveSheet": {
27
- "signature": "def moveSheet(name: str, index: int) -> None",
28
- "docstring": "Move a sheet to 0-based index. index=0 moves to first, index=Count-1 moves to last.\nExample: wb.moveSheet(\"Data\", 0) # move to first position",
29
- "tags": ["action"]
30
- },
31
- "calculate": {
32
- "signature": "def calculate() -> None",
33
- "docstring": "Recalculate the entire workbook.\nDependent formulas don't update until after code block completes \u2014 read in a follow-up block.",
34
- "tags": ["action"]
35
- },
36
- "errorCheck": {
37
- "signature": "def errorCheck(ranges: list[str] | None = None) -> str",
38
- "docstring": "Scan for errors (#REF!, #DIV/0!, #NAME?, #VALUE!, #N/A, #NULL!, #NUM!). Ranges MUST include a sheet name (\"Sheet1\" or \"Sheet1!A1:D50\") \u2014 bare ranges like \"A1:D50\" will fail.\n Args:\n ranges: Optional sheet names (\"Sheet1\") or ranges (\"Sheet1!A1:D50\"). Omit to check all.\n Returns:\n \"No issues found.\" or \"Errors (N):\nSheet1!A1: #REF!\n...\"",
39
- "tags": ["action", "ask"]
40
- },
41
- "copyPasteRange": {
42
- "signature": "def copyPasteRange(from_range: str, to_address: str, paste_type: str = 'all', ) -> None",
43
- "docstring": "Copy range within same workbook via range.Copy + PasteSpecial.\nAddresses must include sheet name. Do NOT use Sheet.Copy (broken via pywin32).\nExample: wb.copyPasteRange(\"Sheet1!A1:D10\", \"Sheet2!A1\", paste_type=\"values\")",
44
- "tags": ["action"]
45
- },
46
- "getNamedRangeInfo": {
47
- "signature": "def getNamedRangeInfo(max_count: int = 50) -> str",
48
- "docstring": "Get named ranges. Returns formatted string with name, reference, scope, and comment.\nExample output: \"Named Ranges (2):\\n Name: TaxRate | Ref: =Settings!$B$2 | Scope: workbook | Comment: ...\"\nReturns \"No named ranges found.\" if none exist.",
49
- "tags": ["action", "ask"]
50
- }
51
- }
52
- },
53
- "Worksheet": {
54
- "docstring": "Worksheet wrapper.\nUsage:\n sheet = wb.getSheet(\"Sheet1\")\n\nRaw COM access:\n sheet._ws \u2014 the underlying COM Worksheet object for direct platform API calls.\n Use for borders, text orientation, cell protection, and other properties not covered by the wrapper.\n Example: sheet._ws.Range(\"A1\").Borders(9).LineStyle = 1 # xlEdgeBottom, xlContinuous",
55
- "functions": {
56
- "getSheetSummary": {
57
- "signature": "def getSheetSummary() -> str",
58
- "docstring": "Overview: name, used range, tables (with style/banded/header/total props),\npivots (with range), conditional formats (type/range/priority/stopIfTrue),\nautofilter (with filtering status), charts (with type).",
59
- "tags": ["action", "ask"]
60
- },
61
- "getUsedRange": {
62
- "signature": "def getUsedRange() -> str",
63
- "docstring": "Get the used range address like \"A1:F20\", or \"\" if empty.",
64
- "tags": ["action", "ask"]
65
- },
66
- "getCell": {
67
- "signature": "def getCell(address: str, include_style: bool = True) -> str",
68
- "docstring": "Formatted cell string: \"value(=FORMULA) (style_json)\". Formula always included.\nZero with custom format appends [0]: \"$ - [0]\".\nExample:\n print(sheet.getCell(\"A1\"))\n print(sheet.getCell(\"A1\", include_style=False))",
69
- "tags": ["action", "ask"]
70
- },
71
- "getCellRange": {
72
- "signature": "def getCellRange(range_addr: str, include_style: bool = True) -> str",
73
- "docstring": "Markdown-like range: \"A1:Name | B1:Value\\nA2:Alice | B2:100\". Uses display text. Max 3000 cells; read larger areas in smaller chunks.\nAppends \"--- Style patterns ---\" section when include_style=True.",
74
- "tags": ["action", "ask"]
75
- },
76
- "getRawCellData": {
77
- "signature": "def getRawCellData(address: str, formula: bool = False) -> Any",
78
- "docstring": "Get raw data value from a cell, preserving data type. Set formula=True to get the formula string.",
79
- "tags": ["action", "ask"]
80
- },
81
- "getRawRangeData": {
82
- "signature": "def getRawRangeData(range_addr: str, formula: bool = False) -> list[list[Any]]",
83
- "docstring": "Get raw data for a range as 2D list. Always returns 2D list even for single row/column.",
84
- "tags": ["action", "ask"]
85
- },
86
- "regexSearch": {
87
- "signature": "def regexSearch(patterns: list[str], match_case: bool = False) -> list[dict]",
88
- "docstring": "Regex search across used range using display text. Returns [{\"address\": \"A1\", \"value\": \"display text\"}, ...].\nExample: sheet.regexSearch([\"revenue\", \"cost\"])",
89
- "tags": ["action", "ask"]
90
- },
91
- "setCell": {
92
- "signature": "def setCell(address: str, value: Any, number_format: str | None = None, note: str | None = None, ) -> None",
93
- "docstring": "Write value or formula. \"=\" prefix = formula. None or \"\" clears the cell.\nExamples:\n sheet.setCell(\"A1\", 8000)\n sheet.setCell(\"C1\", 0.15, number_format=\"0%\", note=\"Tax rate\")\n sheet.setCell(\"B1\", \"=SUM(A1:A10)\")",
94
- "tags": ["action"]
95
- },
96
- "setCellRange": {
97
- "signature": "def setCellRange(range_addr: str, values: list[list[Any]], number_format: str | None = None, ) -> None",
98
- "docstring": "Bulk write \u2014 ALWAYS use for >100 cells. \"=\" prefix = formula.\nExamples:\n sheet.setCellRange(\"A1:B2\", [[1, 2], [3, 4]])\n sheet.setCellRange(\"A1:B2\", [[\"=SUM(C1)\", \"=SUM(D1)\"], [5, 6]], number_format=\"$#,##0\")",
99
- "tags": ["action"]
100
- },
101
- "autoFill": {
102
- "signature": "def autoFill(source_range: str, target_range: str, fill_mode: str = 'auto', ) -> None",
103
- "docstring": "Drag-fill. Source must be contained within target. Default \"auto\" increments hardcoded numeric literals; use fill_mode=\"constant\" to copy literal values, then read back destination cells and check for empty/NaN values.\nUse fill_mode=\"constant\" when copying a single value without incrementing.\nWARNING: Single numeric value with \"auto\" creates incrementing sequence (0,1,2,3...).\nExample: sheet.autoFill(\"A1:A2\", \"A1:A10\")",
104
- "tags": ["action"]
105
- },
106
- "addPicture": {
107
- "signature": "def addPicture(name: str, base64_data: str, anchor_cell: str) -> None",
108
- "docstring": "Add a picture from base64-encoded PNG or JPEG data. No data URI prefix.\nExample: sheet.addPicture(\"chart1\", base64_string, \"F2\")",
109
- "tags": ["action"]
110
- },
111
- "setIBTextColors": {
112
- "signature": "def setIBTextColors(range_addr: str, ignored_constants: list[int] | None = None, colors: dict | None = None, ) -> None",
113
- "docstring": "IB text colors for numeric inputs only. Text strings and booleans are left untouched.\n- Blue/16711680: hard-coded numeric constants (int/float)\n- Black/0: formulas (same-sheet references)\n- Green/32768: formulas with cross-sheet references (contains '!')\nColors are BGR integers (native COM format).\nExample: sheet.setIBTextColors(\"A1:D10\", ignored_constants=[0])",
114
- "tags": ["action"]
115
- }
116
- }
117
- }
118
- },
119
- "helpers": {
120
- "hex_to_bgr": {
121
- "signature": "def hex_to_bgr(hex_str: str) -> int",
122
- "docstring": "Convert \"#RRGGBB\" hex string to BGR integer for Excel COM.\nExample: ws.Range(\"A1\").Font.Color = hex_to_bgr(\"#FF0000\") # red",
123
- "tags": ["action", "ask"]
124
- },
125
- "index_to_address": {
126
- "signature": "def index_to_address(row: int, col: int) -> str",
127
- "docstring": "Convert 0-based (row, col) to Excel address: index_to_address(0, 0) \u2192 \"A1\".",
128
- "tags": ["action", "ask"]
129
- },
130
- "address_to_index": {
131
- "signature": "def address_to_index(address: str) -> tuple[int, int]",
132
- "docstring": "Parse \"A1\" into (row, col) 0-based tuple: address_to_index(\"B3\") \u2192 (2, 1).",
133
- "tags": ["action", "ask"]
134
- },
135
- "col_letter": {
136
- "signature": "def col_letter(index: int) -> str",
137
- "docstring": "Convert 0-based column index to letter: col_letter(26) \u2192 \"AA\".",
138
- "tags": ["action", "ask"]
139
- },
140
- "col_index": {
141
- "signature": "def col_index(letter: str) -> int",
142
- "docstring": "Convert column letter to 0-based index: col_index(\"AA\") \u2192 26.",
143
- "tags": ["action", "ask"]
144
- }
145
- }
146
- }
1
+ {
2
+ "interfaces": {
3
+ "Workbook": {
4
+ "docstring": "Workbook wrapper.\nUsage:\n wb = Workbook(app.Workbooks(\"MyFile.xlsx\"))\n\nRaw COM access:\n wb._wb \u2014 the underlying COM Workbook object for direct platform API calls.\n Example: wb._wb.Worksheets(\"Sheet1\").Visible = False",
5
+ "functions": {
6
+ "getSheetNames": {
7
+ "signature": "def getSheetNames() -> list[str]",
8
+ "docstring": "Get the names of all sheets in the workbook.",
9
+ "tags": [
10
+ "action",
11
+ "ask"
12
+ ]
13
+ },
14
+ "getWorkbookSummary": {
15
+ "signature": "def getWorkbookSummary() -> str",
16
+ "docstring": "Get sheet names and used ranges for this workbook.\nReturns lines like:\n Sheets and their used ranges:\n Sheet1: A1:D10 (active)\n Inputs: (empty)",
17
+ "tags": [
18
+ "action",
19
+ "ask"
20
+ ]
21
+ },
22
+ "getSheet": {
23
+ "signature": "def getSheet(name: str) -> 'Worksheet'",
24
+ "docstring": "Get a sheet by name, returned as a wrapped Worksheet.",
25
+ "tags": [
26
+ "action",
27
+ "ask"
28
+ ]
29
+ },
30
+ "addSheet": {
31
+ "signature": "def addSheet(name: str, index: int | None = None) -> 'Worksheet'",
32
+ "docstring": "Add a new sheet at 0-based index. index=0 inserts before the first sheet.\nOmit index for Excel's default position.\nExample: wb.addSheet(\"NewSheet\", 0) # insert as first sheet",
33
+ "tags": [
34
+ "action"
35
+ ]
36
+ },
37
+ "moveSheet": {
38
+ "signature": "def moveSheet(name: str, index: int) -> None",
39
+ "docstring": "Move a sheet to 0-based index. index=0 moves to first, index=Count-1 moves to last.\nExample: wb.moveSheet(\"Data\", 0) # move to first position",
40
+ "tags": [
41
+ "action"
42
+ ]
43
+ },
44
+ "calculate": {
45
+ "signature": "def calculate() -> None",
46
+ "docstring": "Recalculate the entire workbook.\nDependent formulas don't update until after code block completes \u2014 read in a follow-up block.",
47
+ "tags": [
48
+ "action"
49
+ ]
50
+ },
51
+ "errorCheck": {
52
+ "signature": "def errorCheck(ranges: list[str] | None = None) -> str",
53
+ "docstring": "Scan for errors (#REF!, #DIV/0!, #NAME?, #VALUE!, #N/A, #NULL!, #NUM!). Ranges MUST include a sheet name (\"Sheet1\" or \"Sheet1!A1:D50\") \u2014 bare ranges like \"A1:D50\" will fail.\n Args:\n ranges: Optional sheet names (\"Sheet1\") or ranges (\"Sheet1!A1:D50\"). Omit to check all.\n Returns:\n \"No issues found.\" or \"Errors (N):\nSheet1!A1: #REF!\n...\"",
54
+ "tags": [
55
+ "action",
56
+ "ask"
57
+ ]
58
+ },
59
+ "copyPasteRange": {
60
+ "signature": "def copyPasteRange(from_range: str, to_address: str, paste_type: str = 'all', ) -> None",
61
+ "docstring": "Copy range within same workbook via range.Copy + PasteSpecial.\nAddresses must include sheet name. Do NOT use Sheet.Copy (broken via pywin32).\nExample: wb.copyPasteRange(\"Sheet1!A1:D10\", \"Sheet2!A1\", paste_type=\"values\")",
62
+ "tags": [
63
+ "action"
64
+ ]
65
+ },
66
+ "getNamedRangeInfo": {
67
+ "signature": "def getNamedRangeInfo(max_count: int = 50) -> str",
68
+ "docstring": "Get named ranges. Returns formatted string with name, reference, scope, and comment.\nExample output: \"Named Ranges (2):\\n Name: TaxRate | Ref: =Settings!$B$2 | Scope: workbook | Comment: ...\"\nReturns \"No named ranges found.\" if none exist.",
69
+ "tags": [
70
+ "action",
71
+ "ask"
72
+ ]
73
+ }
74
+ }
75
+ },
76
+ "Worksheet": {
77
+ "docstring": "Worksheet wrapper.\nUsage:\n sheet = wb.getSheet(\"Sheet1\")\n\nRaw COM access:\n sheet._ws \u2014 the underlying COM Worksheet object for direct platform API calls.\n Use for borders, text orientation, cell protection, and other properties not covered by the wrapper.\n Example: sheet._ws.Range(\"A1\").Borders(9).LineStyle = 1 # xlEdgeBottom, xlContinuous",
78
+ "functions": {
79
+ "getSheetSummary": {
80
+ "signature": "def getSheetSummary() -> str",
81
+ "docstring": "Overview: name, used range, tables (with style/banded/header/total props),\npivots (with range), conditional formats (type/range/priority/stopIfTrue),\nautofilter (with filtering status), charts (with type).",
82
+ "tags": [
83
+ "action",
84
+ "ask"
85
+ ]
86
+ },
87
+ "getUsedRange": {
88
+ "signature": "def getUsedRange() -> str",
89
+ "docstring": "Get the used range address like \"A1:F20\", or \"\" if empty.",
90
+ "tags": [
91
+ "action",
92
+ "ask"
93
+ ]
94
+ },
95
+ "getCell": {
96
+ "signature": "def getCell(address: str, include_style: bool = True) -> str",
97
+ "docstring": "Formatted cell string: \"value(=FORMULA) (style_json)\". Formula always included.\nZero with custom format appends [0]: \"$ - [0]\".\nExample:\n print(sheet.getCell(\"A1\"))\n print(sheet.getCell(\"A1\", include_style=False))",
98
+ "tags": [
99
+ "action",
100
+ "ask"
101
+ ]
102
+ },
103
+ "getCellRange": {
104
+ "signature": "def getCellRange(range_addr: str, include_style: bool = True) -> str",
105
+ "docstring": "Markdown-like range: \"A1:Name | B1:Value\\nA2:Alice | B2:100\". Uses display text. Max 3000 cells; read larger areas in smaller chunks.\nAppends \"--- Style patterns ---\" section when include_style=True.",
106
+ "tags": [
107
+ "action",
108
+ "ask"
109
+ ]
110
+ },
111
+ "getRawCellData": {
112
+ "signature": "def getRawCellData(address: str, formula: bool = False) -> Any",
113
+ "docstring": "Get raw data value from a cell, preserving data type. Set formula=True to get the formula string.",
114
+ "tags": [
115
+ "action",
116
+ "ask"
117
+ ]
118
+ },
119
+ "getRawRangeData": {
120
+ "signature": "def getRawRangeData(range_addr: str, formula: bool = False) -> list[list[Any]]",
121
+ "docstring": "Get raw data for a range as 2D list. Always returns 2D list even for single row/column.",
122
+ "tags": [
123
+ "action",
124
+ "ask"
125
+ ]
126
+ },
127
+ "regexSearch": {
128
+ "signature": "def regexSearch(patterns: list[str], match_case: bool = False) -> list[dict]",
129
+ "docstring": "Regex search across used range using display text. Returns [{\"address\": \"A1\", \"value\": \"display text\"}, ...].\nExample: sheet.regexSearch([\"revenue\", \"cost\"])",
130
+ "tags": [
131
+ "action",
132
+ "ask"
133
+ ]
134
+ },
135
+ "setCell": {
136
+ "signature": "def setCell(address: str, value: Any, number_format: str | None = None, note: str | None = None, ) -> None",
137
+ "docstring": "Write value or formula. \"=\" prefix = formula. None or \"\" clears the cell.\nExamples:\n sheet.setCell(\"A1\", 8000)\n sheet.setCell(\"C1\", 0.15, number_format=\"0%\", note=\"Tax rate\")\n sheet.setCell(\"B1\", \"=SUM(A1:A10)\")",
138
+ "tags": [
139
+ "action"
140
+ ]
141
+ },
142
+ "setCellRange": {
143
+ "signature": "def setCellRange(range_addr: str, values: list[list[Any]], number_format: str | None = None, ) -> None",
144
+ "docstring": "Bulk write \u2014 ALWAYS use for >100 cells. \"=\" prefix = formula.\nExamples:\n sheet.setCellRange(\"A1:B2\", [[1, 2], [3, 4]])\n sheet.setCellRange(\"A1:B2\", [[\"=SUM(C1)\", \"=SUM(D1)\"], [5, 6]], number_format=\"$#,##0\")",
145
+ "tags": [
146
+ "action"
147
+ ]
148
+ },
149
+ "autoFill": {
150
+ "signature": "def autoFill(source_range: str, target_range: str, fill_mode: str = 'auto', ) -> None",
151
+ "docstring": "Drag-fill. Source must be contained within target. Default \"auto\" increments hardcoded numeric literals; use fill_mode=\"constant\" to copy literal values, then read back destination cells and check for empty/NaN values.\nUse fill_mode=\"constant\" when copying a single value without incrementing.\nWARNING: Single numeric value with \"auto\" creates incrementing sequence (0,1,2,3...).\nExample: sheet.autoFill(\"A1:A2\", \"A1:A10\")",
152
+ "tags": [
153
+ "action"
154
+ ]
155
+ },
156
+ "addPicture": {
157
+ "signature": "def addPicture(name: str, base64_data: str, anchor_cell: str) -> None",
158
+ "docstring": "Add a picture from base64-encoded PNG or JPEG data. No data URI prefix.\nExample: sheet.addPicture(\"chart1\", base64_string, \"F2\")",
159
+ "tags": [
160
+ "action"
161
+ ]
162
+ },
163
+ "setIBTextColors": {
164
+ "signature": "def setIBTextColors(range_addr: str, ignored_constants: list[int] | None = None, colors: dict | None = None, ) -> None",
165
+ "docstring": "IB text colors for numeric inputs only. Text strings and booleans are left untouched.\n- Blue/16711680: hard-coded numeric constants (int/float)\n- Black/0: formulas (same-sheet references)\n- Green/32768: formulas with cross-sheet references (contains '!')\nColors are BGR integers (native COM format).\nExample: sheet.setIBTextColors(\"A1:D10\", ignored_constants=[0])",
166
+ "tags": [
167
+ "action"
168
+ ]
169
+ }
170
+ }
171
+ }
172
+ },
173
+ "helpers": {
174
+ "hex_to_bgr": {
175
+ "signature": "def hex_to_bgr(hex_str: str) -> int",
176
+ "docstring": "Convert \"#RRGGBB\" hex string to BGR integer for Excel COM.\nExample: ws.Range(\"A1\").Font.Color = hex_to_bgr(\"#FF0000\") # red",
177
+ "tags": [
178
+ "action",
179
+ "ask"
180
+ ]
181
+ },
182
+ "index_to_address": {
183
+ "signature": "def index_to_address(row: int, col: int) -> str",
184
+ "docstring": "Convert 0-based (row, col) to Excel address: index_to_address(0, 0) \u2192 \"A1\".",
185
+ "tags": [
186
+ "action",
187
+ "ask"
188
+ ]
189
+ },
190
+ "address_to_index": {
191
+ "signature": "def address_to_index(address: str) -> tuple[int, int]",
192
+ "docstring": "Parse \"A1\" into (row, col) 0-based tuple: address_to_index(\"B3\") \u2192 (2, 1).",
193
+ "tags": [
194
+ "action",
195
+ "ask"
196
+ ]
197
+ },
198
+ "col_letter": {
199
+ "signature": "def col_letter(index: int) -> str",
200
+ "docstring": "Convert 0-based column index to letter: col_letter(26) \u2192 \"AA\".",
201
+ "tags": [
202
+ "action",
203
+ "ask"
204
+ ]
205
+ },
206
+ "col_index": {
207
+ "signature": "def col_index(letter: str) -> int",
208
+ "docstring": "Convert column letter to 0-based index: col_index(\"AA\") \u2192 26.",
209
+ "tags": [
210
+ "action",
211
+ "ask"
212
+ ]
213
+ }
214
+ }
215
+ }
@@ -6,7 +6,7 @@ import { BASH, EDIT, EXECUTE_CODE, GREP, READ, SEND_MESSAGE, TASK, WRITE } from
6
6
  import { buildActionPrompt } from '../../modes/action/prompt.js';
7
7
  import { buildCurrentSkillsSection } from '../../prompts/shared-guidelines.js';
8
8
  import { assembleSystemPrompt } from '../../system-prompt.js';
9
- import { DEFAULT_SUBAGENT_MODEL } from '../defaults.js';
9
+ import { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS } from '../defaults.js';
10
10
  const NAME = 'clone';
11
11
  const DESCRIPTION = `\
12
12
  A full clone of the main agent with tools (read, bash, edit, write, grep, execute_code, task, send_message).
@@ -25,6 +25,6 @@ export const cloneAgent = {
25
25
  excludeSubagents: ['clone'],
26
26
  model: DEFAULT_SUBAGENT_MODEL,
27
27
  thinkingLevel: 'low',
28
- timeoutSeconds: 900
28
+ timeoutSeconds: DEFAULT_SUBAGENT_TIMEOUT_SECONDS
29
29
  };
30
30
  //# sourceMappingURL=agent.js.map
@@ -1,3 +1,4 @@
1
1
  export declare const DEFAULT_SUBAGENT_MODEL: "shortcut/claude-opus-4-7";
2
+ export declare const DEFAULT_SUBAGENT_TIMEOUT_SECONDS: number;
2
3
  export declare const TASK_MODEL_CHOICES: readonly ["shortcut/claude-opus-4-7", "shortcut/gpt-5.5-2026-04-23"];
3
4
  //# sourceMappingURL=defaults.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { SHORTCUT_MODEL_REF } from '../../model-ids.js';
2
2
  export const DEFAULT_SUBAGENT_MODEL = SHORTCUT_MODEL_REF.ClaudeOpus47;
3
+ export const DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 30 * 60;
3
4
  export const TASK_MODEL_CHOICES = [DEFAULT_SUBAGENT_MODEL, SHORTCUT_MODEL_REF.Gpt55];
4
5
  //# sourceMappingURL=defaults.js.map
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { getAgentTempDir } from '../../../config.js';
8
8
  import { BASH, LLM_ANALYSIS, WRITE } from '../../../tool-names.js';
9
- import { DEFAULT_SUBAGENT_MODEL } from '../defaults.js';
9
+ import { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS } from '../defaults.js';
10
10
  const NAME = 'document_reader';
11
11
  const DESCRIPTION = `\
12
12
  Extract structured data from PDFs, images, and documents with high accuracy.
@@ -87,6 +87,6 @@ export const documentReaderAgent = {
87
87
  tools: [WRITE, BASH, LLM_ANALYSIS],
88
88
  model: DEFAULT_SUBAGENT_MODEL,
89
89
  thinkingLevel: 'low',
90
- timeoutSeconds: 900
90
+ timeoutSeconds: DEFAULT_SUBAGENT_TIMEOUT_SECONDS
91
91
  };
92
92
  //# sourceMappingURL=agent.js.map
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { BASH, EXECUTE_CODE, LLM_ANALYSIS, WRITE } from '../../../tool-names.js';
8
8
  import { buildCurrentSkillsSection, getEnginePrompts, pushActionSharedGuidelines } from '../../prompts/shared-guidelines.js';
9
- import { DEFAULT_SUBAGENT_MODEL } from '../defaults.js';
9
+ import { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS } from '../defaults.js';
10
10
  const NAME = 'general';
11
11
  const DESCRIPTION = `\
12
12
  General-purpose agent for research, computation, and web tasks. Uses include:
@@ -71,7 +71,7 @@ export function generalAgent() {
71
71
  tools: [WRITE, BASH, EXECUTE_CODE, LLM_ANALYSIS],
72
72
  model: DEFAULT_SUBAGENT_MODEL,
73
73
  thinkingLevel: 'low',
74
- timeoutSeconds: 900
74
+ timeoutSeconds: DEFAULT_SUBAGENT_TIMEOUT_SECONDS
75
75
  };
76
76
  }
77
77
  //# sourceMappingURL=agent.js.map
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export type { AgentDefinition } from '../agent-definition.js';
8
8
  export { cloneAgent } from './clone/agent.js';
9
- export { DEFAULT_SUBAGENT_MODEL, TASK_MODEL_CHOICES } from './defaults.js';
9
+ export { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS, TASK_MODEL_CHOICES } from './defaults.js';
10
10
  export { documentReaderAgent } from './document-reader/agent.js';
11
11
  export { generalAgent } from './general/agent.js';
12
12
  export { verificationAgent } from './verification/agent.js';
@@ -5,7 +5,7 @@
5
5
  * catalog, even after test resets.
6
6
  */
7
7
  export { cloneAgent } from './clone/agent.js';
8
- export { DEFAULT_SUBAGENT_MODEL, TASK_MODEL_CHOICES } from './defaults.js';
8
+ export { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS, TASK_MODEL_CHOICES } from './defaults.js';
9
9
  export { documentReaderAgent } from './document-reader/agent.js';
10
10
  export { generalAgent } from './general/agent.js';
11
11
  export { verificationAgent } from './verification/agent.js';
@@ -7,7 +7,7 @@
7
7
  import { getAgentTempDir } from '../../../config.js';
8
8
  import { BASH, EXECUTE_CODE } from '../../../tool-names.js';
9
9
  import { getEnginePrompts, pushActionSharedGuidelines } from '../../prompts/shared-guidelines.js';
10
- import { DEFAULT_SUBAGENT_MODEL } from '../defaults.js';
10
+ import { DEFAULT_SUBAGENT_MODEL, DEFAULT_SUBAGENT_TIMEOUT_SECONDS } from '../defaults.js';
11
11
  const NAME = 'simulation_agent';
12
12
  const DESCRIPTION = `\
13
13
  Read/write workbook analysis worker for scenario analysis, sensitivity testing, auditing formula linkages, debugging, prototyping changes, and other workbook-heavy tasks.`;
@@ -67,6 +67,6 @@ export const simulationAgent = {
67
67
  tools: [EXECUTE_CODE, BASH],
68
68
  model: DEFAULT_SUBAGENT_MODEL,
69
69
  thinkingLevel: 'low',
70
- timeoutSeconds: 900
70
+ timeoutSeconds: DEFAULT_SUBAGENT_TIMEOUT_SECONDS
71
71
  };
72
72
  //# sourceMappingURL=agent.js.map