shortcutxl 0.3.48 → 0.3.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -11
- package/agent-docs/docs/tui.md +24 -0
- package/agent-docs/examples/rpc-extension-ui.ts +1 -1
- package/dist/app/agent-session.d.ts +2 -3
- package/dist/app/agent-session.js +3 -7
- package/dist/app/index.d.ts +1 -1
- package/dist/app/index.js +1 -1
- package/dist/app/modes/action/agent.js +6 -1
- package/dist/app/prompts/com-api-reference.json +146 -146
- package/dist/app/resources/package-manager.js +2 -41
- package/dist/app/settings-manager.d.ts +1 -1
- package/dist/app/settings-manager.js +1 -1
- package/dist/app/skill-proposals/catalog.d.ts +5 -1
- package/dist/app/skill-proposals/catalog.js +7 -1
- package/dist/app/skill-proposals/review.d.ts +1 -1
- package/dist/app/skill-proposals/review.js +2 -1
- package/dist/app/subagents/clone/agent.js +2 -2
- package/dist/app/subagents/defaults.d.ts +1 -0
- package/dist/app/subagents/defaults.js +1 -0
- package/dist/app/subagents/document-reader/agent.js +2 -2
- package/dist/app/subagents/general/agent.js +8 -6
- package/dist/app/subagents/index.d.ts +1 -1
- package/dist/app/subagents/index.js +2 -2
- package/dist/app/subagents/simulation/agent.js +2 -2
- package/dist/app/subagents/verification/agent.js +2 -2
- package/dist/app/subagents/workbook-reader/agent.js +2 -2
- package/dist/app/sync/skills-download.d.ts +3 -12
- package/dist/app/sync/skills-download.js +32 -57
- package/dist/app/sync/skills-upload.d.ts +4 -4
- package/dist/app/sync/skills-upload.js +15 -40
- package/dist/app/tools/task/task.js +5 -4
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/session-picker.js +1 -1
- package/dist/cli.js +1059 -1058
- package/dist/config.d.ts +0 -2
- package/dist/config.js +0 -4
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +17 -0
- package/dist/embedded-agent/host-tools/task/agent-definition.d.ts +1 -0
- package/dist/embedded-agent/host-tools/task/agent-definition.js +1 -1
- package/dist/embedded-agent/host-tools/task/agents/document-reader.d.ts +1 -1
- package/dist/embedded-agent/host-tools/task/agents/document-reader.js +2 -2
- package/dist/embedded-agent/host-tools/task/agents/general.d.ts +1 -1
- package/dist/embedded-agent/host-tools/task/agents/general.js +2 -2
- package/dist/embedded-agent/host-tools/task/agents/verification.d.ts +1 -1
- package/dist/embedded-agent/host-tools/task/agents/verification.js +2 -2
- package/dist/embedded-agent/host-tools/task/agents/workbook-reader.d.ts +1 -1
- package/dist/embedded-agent/host-tools/task/agents/workbook-reader.js +2 -2
- package/dist/main.js +1 -3
- package/dist/rpc/rpc-mode.js +1 -1
- package/dist/shell/approvals/file-access-approval.js +2 -2
- package/dist/shell/components/interactive-shell-layout.d.ts +16 -0
- package/dist/shell/components/interactive-shell-layout.js +90 -0
- package/dist/shell/dev/interactive-render-trace.d.ts +3 -0
- package/dist/shell/dev/interactive-render-trace.js +39 -0
- package/dist/shell/interactive/interactive-actions.js +0 -1
- package/dist/shell/interactive/interactive-mode-options.d.ts +1 -5
- package/dist/shell/interactive/interactive-mode.d.ts +7 -0
- package/dist/shell/interactive/interactive-mode.js +88 -17
- package/dist/shell/interactive/proposals-workflow.js +33 -13
- package/dist/shell/interactive/skills-workflow.d.ts +1 -5
- package/dist/shell/interactive/skills-workflow.js +25 -24
- package/dist/shell/interactive/super-fight-ui.d.ts +3 -2
- package/dist/shell/interactive/super-fight-ui.js +7 -6
- package/dist/shell/keybindings.d.ts +1 -1
- package/dist/shell/keybindings.js +0 -2
- package/dist/startup/interactive-commands.js +0 -2
- package/dist/tui/index.d.ts +1 -0
- package/dist/tui/index.js +1 -1
- package/dist/tui/keys.d.ts +14 -0
- package/dist/tui/keys.js +78 -0
- package/dist/tui/render-trace.d.ts +32 -0
- package/dist/tui/render-trace.js +293 -0
- package/dist/tui/terminal.d.ts +11 -0
- package/dist/tui/terminal.js +43 -15
- package/dist/tui/tui.d.ts +34 -0
- package/dist/tui/tui.js +359 -99
- package/package.json +291 -290
- package/skills/advanced-mog-api/api-reference.json +9291 -9291
- package/user-docs/dist/index.html +1 -1
- package/user-docs/dist/shortcutxl-docs.pdf +0 -0
- package/dist/app/sync/skills-sync-state.d.ts +0 -14
- package/dist/app/sync/skills-sync-state.js +0 -46
- package/dist/startup/skills-sync.d.ts +0 -10
- package/dist/startup/skills-sync.js +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [0.3.
|
|
4
|
-
|
|
5
|
-
- **
|
|
6
|
-
- **
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.50]
|
|
4
|
+
|
|
5
|
+
- **MCP-enabled task agents** - General task agents can now use connected MCP servers, giving delegated work access to the same external tools and resources as the main CLI.
|
|
6
|
+
- **Safer skill uploads** - Uploading skills no longer treats missing local skills as cloud deletions, so remote-only skills stay untouched unless explicitly replaced.
|
|
7
|
+
- **Misc bug fixes** - Shift+A for agent panel, wording, clarity.
|
|
8
|
+
|
|
9
|
+
## [0.3.49]
|
|
10
|
+
|
|
11
|
+
- **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.
|
|
12
|
+
- **Longer-running task agents** - Background task agents now get a 30-minute default timeout, reducing early timeouts on bigger jobs.
|
|
13
|
+
- **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.
|
|
14
|
+
|
|
15
|
+
## [0.3.48]
|
|
16
|
+
|
|
17
|
+
- **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.
|
|
18
|
+
- **Skill proposals** - ShortcutXL now automatically browses through past sessions and suggests new skills and skill modifications.
|
|
19
|
+
|
|
20
|
+
## [0.3.47]
|
|
21
|
+
|
|
22
|
+
- **GPT-5.5** — Upgraded the OpenAI reasoning model from GPT-5.4 to GPT-5.5 (400K context window, stronger reasoning).
|
|
23
|
+
- **Out-of-credits message** — When your credit balance runs out, ShortcutXL now shows a clear message instead of silently failing.
|
|
12
24
|
|
|
13
25
|
## [0.3.46]
|
|
14
26
|
|
package/agent-docs/docs/tui.md
CHANGED
|
@@ -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:
|
|
@@ -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).
|
|
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()
|
|
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()
|
|
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()
|
|
758
|
+
// If streaming, queue via steer() by default; follow-up is opt-in.
|
|
760
759
|
if (this.isStreaming) {
|
|
761
|
-
if (
|
|
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 {
|
package/dist/app/index.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export { default as skillProposalsExtension } from './skill-proposals/extension.
|
|
|
46
46
|
export { getSkillProposalRoots, type ProposalRoots } from './skill-proposals/proposal-fs.js';
|
|
47
47
|
export { readSkillProposalReviewSnapshot, type SkillProposalReviewSnapshot } from './skill-proposals/review.js';
|
|
48
48
|
export type { StartupInfoEntry } from './startup-info.js';
|
|
49
|
-
export { downloadSkillsWithApproval
|
|
49
|
+
export { downloadSkillsWithApproval } from './sync/skills-download.js';
|
|
50
50
|
export type { SkillDownloadApprovalHandler, SkillDownloadApprovalRequest, SkillsDownloadResult } from './sync/skills-download.js';
|
|
51
51
|
export { uploadSkills } from './sync/skills-upload.js';
|
|
52
52
|
export type { SkillUploadApprovalRequest, SkillsUploadResult } from './sync/skills-upload.js';
|
package/dist/app/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export { countSkillProposals, listSkillProposals } from './skill-proposals/catal
|
|
|
36
36
|
export { default as skillProposalsExtension } from './skill-proposals/extension.js';
|
|
37
37
|
export { getSkillProposalRoots } from './skill-proposals/proposal-fs.js';
|
|
38
38
|
export { readSkillProposalReviewSnapshot } from './skill-proposals/review.js';
|
|
39
|
-
export { downloadSkillsWithApproval
|
|
39
|
+
export { downloadSkillsWithApproval } from './sync/skills-download.js';
|
|
40
40
|
export { uploadSkills } from './sync/skills-upload.js';
|
|
41
41
|
export * from './tools/index.js';
|
|
42
42
|
export { buildWorkbookPromptContext, fetchWorkbookConnectionState, formatWorkbookScopePromptContext } from './workbook-context/workbook-summary.js';
|
|
@@ -5,12 +5,17 @@
|
|
|
5
5
|
* for making changes to the spreadsheet. Can switch to plan or installation mode.
|
|
6
6
|
*/
|
|
7
7
|
import { MODE } from '../../../mode-names.js';
|
|
8
|
-
import { ACTION_SWITCH_MODE, BASH, EXECUTE_CODE, EXECUTE_TOOL, GET_TOOL_INFO, MCP_TOOL_NAMES, SEND_MESSAGE, TASK, TODO_LIST, WRITE } from '../../../tool-names.js';
|
|
8
|
+
import { ACTION_SWITCH_MODE, BASH, EDIT, EXECUTE_CODE, EXECUTE_TOOL, FIND, GET_TOOL_INFO, GREP, LS, MCP_TOOL_NAMES, READ, SEND_MESSAGE, TASK, TODO_LIST, WRITE } from '../../../tool-names.js';
|
|
9
9
|
import { buildActionPrompt } from './prompt.js';
|
|
10
10
|
const DESCRIPTION = 'Execute changes to the spreadsheet.';
|
|
11
11
|
const TOOLS = [
|
|
12
|
+
READ,
|
|
12
13
|
BASH,
|
|
14
|
+
EDIT,
|
|
13
15
|
WRITE,
|
|
16
|
+
GREP,
|
|
17
|
+
FIND,
|
|
18
|
+
LS,
|
|
14
19
|
EXECUTE_CODE,
|
|
15
20
|
TASK,
|
|
16
21
|
SEND_MESSAGE,
|
|
@@ -1,146 +1,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": ["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": ["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
|
+
}
|
|
@@ -191,37 +191,6 @@ function collectSkillEntries(dir, includeRootFiles = true, ignoreMatcher, rootDi
|
|
|
191
191
|
function collectAutoSkillEntries(dir, includeRootFiles = true) {
|
|
192
192
|
return collectSkillEntries(dir, includeRootFiles);
|
|
193
193
|
}
|
|
194
|
-
function findGitRepoRoot(startDir) {
|
|
195
|
-
let dir = resolve(startDir);
|
|
196
|
-
while (true) {
|
|
197
|
-
if (existsSync(join(dir, '.git'))) {
|
|
198
|
-
return dir;
|
|
199
|
-
}
|
|
200
|
-
const parent = dirname(dir);
|
|
201
|
-
if (parent === dir) {
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
dir = parent;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function collectAncestorAgentsSkillDirs(startDir) {
|
|
208
|
-
const skillDirs = [];
|
|
209
|
-
const resolvedStartDir = resolve(startDir);
|
|
210
|
-
const gitRepoRoot = findGitRepoRoot(resolvedStartDir);
|
|
211
|
-
let dir = resolvedStartDir;
|
|
212
|
-
while (true) {
|
|
213
|
-
skillDirs.push(join(dir, '.agents', 'skills'));
|
|
214
|
-
if (gitRepoRoot && dir === gitRepoRoot) {
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
const parent = dirname(dir);
|
|
218
|
-
if (parent === dir) {
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
dir = parent;
|
|
222
|
-
}
|
|
223
|
-
return skillDirs;
|
|
224
|
-
}
|
|
225
194
|
function collectAutoPromptEntries(dir) {
|
|
226
195
|
const entries = [];
|
|
227
196
|
if (!existsSync(dir))
|
|
@@ -1370,8 +1339,6 @@ export class DefaultPackageManager {
|
|
|
1370
1339
|
prompts: join(projectBaseDir, 'prompts'),
|
|
1371
1340
|
themes: join(projectBaseDir, 'themes')
|
|
1372
1341
|
};
|
|
1373
|
-
const userAgentsSkillsDir = join(homedir(), '.agents', 'skills');
|
|
1374
|
-
const projectAgentsSkillDirs = collectAncestorAgentsSkillDirs(this.cwd);
|
|
1375
1342
|
const addResources = (resourceType, paths, metadata, overrides, baseDir) => {
|
|
1376
1343
|
const target = this.getTargetMap(accumulator, resourceType);
|
|
1377
1344
|
for (const path of paths) {
|
|
@@ -1380,17 +1347,11 @@ export class DefaultPackageManager {
|
|
|
1380
1347
|
}
|
|
1381
1348
|
};
|
|
1382
1349
|
addResources('extensions', collectAutoExtensionEntries(projectDirs.extensions), projectMetadata, projectOverrides.extensions, projectBaseDir);
|
|
1383
|
-
addResources('skills',
|
|
1384
|
-
...collectAutoSkillEntries(projectDirs.skills),
|
|
1385
|
-
...projectAgentsSkillDirs.flatMap((dir) => collectAutoSkillEntries(dir))
|
|
1386
|
-
], projectMetadata, projectOverrides.skills, projectBaseDir);
|
|
1350
|
+
addResources('skills', collectAutoSkillEntries(projectDirs.skills), projectMetadata, projectOverrides.skills, projectBaseDir);
|
|
1387
1351
|
addResources('prompts', collectAutoPromptEntries(projectDirs.prompts), projectMetadata, projectOverrides.prompts, projectBaseDir);
|
|
1388
1352
|
addResources('themes', collectAutoThemeEntries(projectDirs.themes), projectMetadata, projectOverrides.themes, projectBaseDir);
|
|
1389
1353
|
addResources('extensions', collectAutoExtensionEntries(userDirs.extensions), userMetadata, userOverrides.extensions, globalBaseDir);
|
|
1390
|
-
addResources('skills',
|
|
1391
|
-
...collectAutoSkillEntries(userDirs.skills),
|
|
1392
|
-
...collectAutoSkillEntries(userAgentsSkillsDir)
|
|
1393
|
-
], userMetadata, userOverrides.skills, globalBaseDir);
|
|
1354
|
+
addResources('skills', collectAutoSkillEntries(userDirs.skills), userMetadata, userOverrides.skills, globalBaseDir);
|
|
1394
1355
|
// Bundled default skills shipped with the package
|
|
1395
1356
|
const bundledMetadata = {
|
|
1396
1357
|
source: 'auto',
|
|
@@ -336,7 +336,7 @@ export declare class SettingsManager {
|
|
|
336
336
|
/** Whether session traces and ClickHouse logs are uploaded. Default: true. */
|
|
337
337
|
getTelemetry(): boolean;
|
|
338
338
|
setTelemetry(enabled: boolean): void;
|
|
339
|
-
/** Whether dev mode is enabled (
|
|
339
|
+
/** Whether dev mode is enabled (AGENTS.md, dev resources, verbose logging). Default: false. */
|
|
340
340
|
getDevMode(): boolean;
|
|
341
341
|
setDevMode(enabled: boolean): void;
|
|
342
342
|
/** Get all connection metadata (names, types, field names — no secrets). */
|
|
@@ -955,7 +955,7 @@ export class SettingsManager {
|
|
|
955
955
|
this.markModified('telemetry');
|
|
956
956
|
this.save();
|
|
957
957
|
}
|
|
958
|
-
/** Whether dev mode is enabled (
|
|
958
|
+
/** Whether dev mode is enabled (AGENTS.md, dev resources, verbose logging). Default: false. */
|
|
959
959
|
getDevMode() {
|
|
960
960
|
return this.settings.devMode ?? false;
|
|
961
961
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type ProposalRoots } from './proposal-fs.js';
|
|
2
|
-
export
|
|
2
|
+
export declare const PROPOSAL_KIND: {
|
|
3
|
+
readonly CREATE: "create";
|
|
4
|
+
readonly UPDATE: "update";
|
|
5
|
+
};
|
|
6
|
+
export type ProposalKind = (typeof PROPOSAL_KIND)[keyof typeof PROPOSAL_KIND];
|
|
3
7
|
export interface SkillProposalSummary {
|
|
4
8
|
name: string;
|
|
5
9
|
proposalDir: string;
|
|
@@ -8,6 +8,10 @@ import { lstatSync, readdirSync } from 'node:fs';
|
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
import { initializeSkillProposalRoots, liveSkillDir, proposalDir } from './proposal-fs.js';
|
|
10
10
|
const SKILL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
11
|
+
export const PROPOSAL_KIND = {
|
|
12
|
+
CREATE: 'create',
|
|
13
|
+
UPDATE: 'update'
|
|
14
|
+
};
|
|
11
15
|
/** Passive discovery for status/prompt/reviewer; it must not mutate proposal folders. */
|
|
12
16
|
export function listSkillProposals(roots) {
|
|
13
17
|
initializeSkillProposalRoots(roots);
|
|
@@ -15,7 +19,9 @@ export function listSkillProposals(roots) {
|
|
|
15
19
|
.filter((entry) => isValidProposalDirectoryEntry(roots, entry))
|
|
16
20
|
.map((entry) => {
|
|
17
21
|
const targetLiveSkillDir = liveSkillDir(roots, entry.name);
|
|
18
|
-
const kind = pathExistsForLstat(targetLiveSkillDir)
|
|
22
|
+
const kind = pathExistsForLstat(targetLiveSkillDir)
|
|
23
|
+
? PROPOSAL_KIND.UPDATE
|
|
24
|
+
: PROPOSAL_KIND.CREATE;
|
|
19
25
|
return {
|
|
20
26
|
name: entry.name,
|
|
21
27
|
proposalDir: proposalDir(roots, entry.name),
|