Skip to content

feat(vscode): add workflow management and slash command support#6260

Closed
Githubguy132010 wants to merge 23 commits into
Kilo-Org:mainfrom
Githubguy132010:feat/vscode-workflows-and-slash-commands
Closed

feat(vscode): add workflow management and slash command support#6260
Githubguy132010 wants to merge 23 commits into
Kilo-Org:mainfrom
Githubguy132010:feat/vscode-workflows-and-slash-commands

Conversation

@Githubguy132010
Copy link
Copy Markdown
Contributor

@Githubguy132010 Githubguy132010 commented Feb 24, 2026

Fixes #6069

Context

Implements full workflow support in the VS Code extension, addressing #6069. Previously, the Workflows tab in Settings showed only a "Not yet implemented" placeholder. The backend already supported workflows (exposed as commands via GET /command), but the extension had no UI to view, manage, or invoke them.

Implementation

The implementation follows the established Extension ↔ Webview Feature Pattern documented in packages/kilo-vscode/AGENTS.md.

Workflow Viewing & Management (Settings > Agent Behaviour > Workflows)

  • Backend plumbing: Added CommandInfo type, listCommands() and executeCommand() methods to HttpClient, plus commandsLoaded/requestCommands message types
  • Commands context (context/commands.tsx): New SolidJS context provider that fetches commands from the CLI backend with retry logic, wired into both App.tsx and AgentManagerApp.tsx provider hierarchies
  • Workflows subtab: Replaced the placeholder with a full CRUD interface:
    • Text field + Add button to create new .md workflow files in .kilocode/workflows/
    • Edit button (pencil icon) opens the workflow file in VS Code editor
    • Delete button (X icon) removes the file and refreshes the list
    • Empty state with guidance on where to place workflow files
  • KiloProvider handlers: handleCreateWorkflowFile creates the directory + file with a template and opens it in the editor; handleOpenWorkflowFile opens an existing file; handleDeleteWorkflowFile removes the file — all refresh the command list afterward

Slash Command Support (Chat Input)

  • useSlashCommand hook (new file): Detects "/" at the start of chat input, filters the full command list (workflows, skills, MCP prompts) as the user types, supports keyboard navigation (ArrowUp/Down, Enter/Tab, Escape)
  • PromptInput integration: Shows a dropdown above the input with matching commands, styled consistently with the existing @ file mention dropdown. Each item shows the command name, description, and a source badge (skill/mcp). Selecting fills the input with /{name} for argument entry
  • Command routing: Messages starting with "/" are parsed and routed to session.sendCommand()POST /session/{id}/command instead of the normal message endpoint, matching how the desktop app handles slash commands

i18n

All new strings translated across 16 locales (ar, br, bs, da, de, en, es, fr, ja, ko, no, pl, ru, th, zh, zht).

Screenshots

before after
Workflows tab showed "Not yet implemented" placeholder Workflows tab shows create/edit/delete UI with workflow list
No slash command support in chat Typing "/" shows filterable command dropdown above input

How to Test

Workflow management:

  1. Open the Kilo sidebar → Settings (gear icon) → Agent Behaviour → Workflows tab
  2. Type a name (e.g. "deploy") and click Add — a new .md file should open in the editor
  3. Edit the workflow content, save, and return to the Workflows tab — it should appear in the list
  4. Click the pencil icon to re-open it in the editor
  5. Click the X icon to delete it

Slash commands:

  1. In the Kilo chat input, type "/" — a dropdown should appear showing all available commands
  2. Continue typing to filter (e.g. "/dep" to filter to "deploy")
  3. Use ArrowUp/Down to navigate, Enter/Tab to select, Escape to dismiss
  4. After selecting, the input fills with /{name} — type arguments and press Enter
  5. The command should execute in the session (visible as an assistant response)

Get in Touch

thomas07374

Implement full workflow support in the VS Code extension:

- View, create, edit, and delete workflows in Settings > Agent Behaviour > Workflows
- Type '/' in the chat input to see a filterable dropdown of all available commands
- Slash commands route to POST /session/{id}/command for proper backend execution
- New files: commands context, useSlashCommand hook, slash command CSS
- i18n strings added for all 16 locales

Closes Kilo-Org#6069
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions
Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Feb 24, 2026

Code Review Summary

Status: No New Issues Found | Recommendation: Address remaining open comments, then merge

Overview

This PR adds slash command support (workflows, skills, MCP prompts) to the VS Code extension, including:

  • Backend command execution via handleSendCommand / handleImportAndSendCommand
  • Workflow file CRUD operations (handleOpenWorkflowFile, handleCreateWorkflowFile, handleDeleteWorkflowFile)
  • Frontend CommandsProvider context with retry logic
  • useSlashCommand hook for autocomplete in chat input
  • sendCommand in session context with optimistic message support
  • Workflows management UI in settings
  • i18n translations for 16 languages

The PR has gone through multiple review iterations and many previously flagged issues have been fixed in subsequent commits (path traversal validation, delete confirmation, error handling, optimistic messages, setLoading, etc.).

Previously Flagged Issues — Now Fixed ✅

Issue Fixed In
Path traversal in workflow file handlers 2de2bb3
writeFile overwriting existing workflows a569f1e
JSDoc mismatch on validateWorkflowName a569f1e
Redundant conditional in useSlashCommand a569f1e
Delete without user confirmation 8506487
importCloudSession outside try/catch Now wrapped in try/catch
sendCommand missing setLoading(true) Now calls setLoading(true)
No optimistic messages for sendCommand Now creates optimistic messages
handleSendCommand error missing sessionID Now includes sessionID
ArrowDown crash with empty filtered list Now guarded with list.length === 0 check
listCommands error not sent to webview Now sends commandsLoaded with error field
pendingSessionKey not reset on error Now reset via setPendingSessionKey(null)
clearTimeouts not called on commandsLoaded Now called in message handler
sessionID missing from CloudSessionImportFailedMessage type Now added to interface
Misleading cloudSessionImportFailed after successful import Now sends error type instead

Remaining Open Items from Previous Reviews

See inline comments for details. Key remaining items:

Severity Count
WARNING ~8
SUGGESTION ~4

Most remaining items are edge cases or minor improvements rather than blocking issues.

Files Reviewed (24 files)
  • packages/kilo-vscode/src/KiloProvider.ts — Command execution, workflow CRUD, validation
  • packages/kilo-vscode/webview-ui/src/context/commands.tsx — New: Commands context with retry
  • packages/kilo-vscode/webview-ui/src/context/session.tsxsendCommand, optimistic messages, pending session key
  • packages/kilo-vscode/webview-ui/src/hooks/useSlashCommand.ts — New: Slash command autocomplete hook
  • packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx — Slash command integration
  • packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx — Workflows UI
  • packages/kilo-vscode/webview-ui/src/types/messages.ts — Type definitions
  • packages/kilo-vscode/webview-ui/src/styles/chat.css — Slash command dropdown styles
  • packages/kilo-vscode/webview-ui/src/i18n/ar.ts — Arabic translations
  • packages/kilo-vscode/webview-ui/src/i18n/br.ts — Brazilian Portuguese translations
  • packages/kilo-vscode/webview-ui/src/i18n/bs.ts — Bosnian translations
  • packages/kilo-vscode/webview-ui/src/i18n/da.ts — Danish translations
  • packages/kilo-vscode/webview-ui/src/i18n/de.ts — German translations
  • packages/kilo-vscode/webview-ui/src/i18n/en.ts — English translations
  • packages/kilo-vscode/webview-ui/src/i18n/es.ts — Spanish translations
  • packages/kilo-vscode/webview-ui/src/i18n/fr.ts — French translations
  • packages/kilo-vscode/webview-ui/src/i18n/ja.ts — Japanese translations
  • packages/kilo-vscode/webview-ui/src/i18n/ko.ts — Korean translations
  • packages/kilo-vscode/webview-ui/src/i18n/no.ts — Norwegian translations
  • packages/kilo-vscode/webview-ui/src/i18n/pl.ts — Polish translations
  • packages/kilo-vscode/webview-ui/src/i18n/ru.ts — Russian translations
  • packages/kilo-vscode/webview-ui/src/i18n/th.ts — Thai translations
  • packages/kilo-vscode/webview-ui/src/i18n/zh.ts — Chinese Simplified translations
  • packages/kilo-vscode/webview-ui/src/i18n/zht.ts — Chinese Traditional translations

Fix these issues in Kilo Cloud

Add validateWorkflowName() guard to all three workflow file handlers.
Rejects names containing path separators or directory traversal patterns
(e.g. '../../etc/something') with an early return and error message.
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/webview-ui/src/hooks/useSlashCommand.ts Outdated
…lify slash input

- Enforce strict alphanumeric/hyphen/underscore allowlist in validateWorkflowName
- Use write-exclusive flag (wx) in createWorkflowFile to prevent silent overwrite
- Remove redundant dead code in useSlashCommand onInput
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Show a native VS Code modal warning before deleting a workflow file
to prevent accidental data loss from misclicks.
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/webview-ui/src/context/commands.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Catch cloud session import failures and emit
`cloudSessionImportFailed` with a useful error message instead of
failing silently.

Also only return a project workflow path when the file exists, so
missing project-scoped workflows correctly fall back to other
resolution paths.
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts
Comment thread packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx Outdated
Propagate command-loading errors to the webview and surface them to users,
while keeping command requests retried with bounded exponential backoff.

Relax local slash-command validation to format checks so command execution
is not blocked by backend command-list fetch issues.

Improve cloud import failure handling by emitting a dedicated failure message,
cleaning up optimistic preview messages, and only clearing the active session
when the failed import matches the current preview context.
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx
Comment thread packages/kilo-vscode/webview-ui/src/hooks/useSlashCommand.ts Outdated
Comment thread packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx Outdated
Githubguy132010 and others added 2 commits February 27, 2026 18:22
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/context/commands.tsx Outdated
Githubguy132010 and others added 2 commits February 27, 2026 19:03
- useSlashCommand.ts: guard ArrowDown against empty filtered list to
  prevent Math.min producing -1 index
- commands.tsx: re-request commands on backend reconnect (ready/connected)
  so slow startup doesn't permanently miss command loading; refactor retry
  logic into startRetry() helper
- session.tsx: create optimistic message in sendCommand even when no
  session exists yet, using a temporary pending session key that is
  transferred to the real session ID in handleSessionCreated
// chat without waiting for the server. When there is no session yet, use a
// temporary pending key; handleSessionCreated will transfer the messages once
// the real session ID is known.
const targetSid = sid ?? `pending:${crypto.randomUUID()}`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Race condition when sendCommand is called twice before the first session is created

On the first call, sid is undefined, so a pending:* key is generated and set as currentSessionID (line 935). On a second call (before sessionCreated arrives), currentSessionID() returns the pending:* string, so sid is now truthy. The code skips the pending-key branch and sends sessionID: sid (line 956) — which is the pending:uuid string — to the backend. The backend will fail because pending:uuid is not a valid session ID.

While the UI's isBusy() guard in handleSend makes this unlikely in normal usage, it's still possible if the session status SSE event hasn't arrived yet or if sendCommand is called programmatically.

Consider either:

  • Checking if sid starts with pending: and treating it as no-session (send sessionID: undefined)
  • Queuing commands while a pending session creation is in flight

case "error":
// Only clear loading if the error is for the current session
// (or has no sessionID for backwards compatibility)
clearOptimisticMessages(message.sessionID ?? currentSessionID()) // kilocode_change
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: pendingSessionKey is not reset on the error path

When an error arrives, clearOptimisticMessages removes the optimistic messages from the pending key, but setPendingSessionKey(null) is never called. If a subsequent unrelated sessionCreated event arrives (e.g., from a different flow), handleSessionCreated (line 458) will check pendingSessionKey(), find the stale key, and attempt to transfer messages from it — which will be an empty array but still triggers unnecessary store updates.

Consider adding setPendingSessionKey(null) in the error handler when the cleared session matches the pending key.

if (message.type === "commandsLoaded") {
setCommands(message.commands)
setError(message.error)
setLoading(false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: clearTimeouts() should be called when commandsLoaded is received

When the commands load successfully, setLoading(false) stops future retries from sending new requests (via the if (!loading()) return guard in tick), but the pending setTimeout callbacks remain allocated. They'll fire, check loading(), and return — but in the meantime they hold references and send one extra requestCommands message each before the guard kicks in.

Adding clearTimeouts() here would cancel pending retries immediately:

if (message.type === "commandsLoaded") {
  clearTimeouts()
  setCommands(message.commands)
  ...
}

- commands.tsx: call clearTimeouts() immediately when commandsLoaded is
  received to cancel pending retry callbacks
- session.tsx: fix race condition where a second sendCommand call before
  session creation would send a pending:* key as sessionID to the backend;
  reuse the existing pending key and pass undefined to the backend
- session.tsx: reset pendingSessionKey on the error path to prevent stale
  state from causing unnecessary store updates on the next sessionCreated
if (pendingKey) {
const pendingMessages = store.messages[pendingKey] ?? []
if (pendingMessages.length > 0) {
setStore("messages", session.id, pendingMessages)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Memory leak — stale pending messages are never cleaned up from the store

When messages are transferred from pendingKey to session.id, the old store.messages[pendingKey] entry (keyed by e.g. pending:uuid) is never deleted. The store.parts entries for the optimistic message IDs also remain under the old key. Over time (e.g., if the user sends many commands that each create a new pending key), these orphaned entries accumulate.

Consider deleting the stale entries after transfer:

if (pendingKey) {
  const pendingMessages = store.messages[pendingKey] ?? []
  if (pendingMessages.length > 0) {
    setStore("messages", session.id, pendingMessages)
  }
  // Clean up stale pending entries
  setStore("messages", pendingKey, undefined)
  setPendingSessionKey(null)
}

})
} catch (err) {
console.error("[Kilo New] Failed to execute command after cloud import:", err)
this.postMessage({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Misleading error type — cloudSessionImportFailed sent after a successful import

At this point, the cloud session has already been successfully imported and cloudSessionImported was sent to the webview (line 1492). If only the command execution fails, sending cloudSessionImportFailed is semantically incorrect. The webview handler for this message type:

  1. Shows a toast saying "Failed to import cloud session" — misleading since the import succeeded
  2. Calls clearOptimisticMessages(key) using the cloud key, which won't match the real session ID
  3. May call setCurrentSessionID(undefined), discarding the successfully imported session

The sessionID field (line 1510) partially mitigates issue #3, but the toast message and optimistic message cleanup are still wrong. Consider posting a regular error message with the session ID instead:

this.postMessage({
  type: "error",
  message: err instanceof Error ? err.message : "Failed to execute command after import",
  sessionID: session.id,
})

- KiloProvider.ts: after a successful cloud session import, if executeCommand
  fails send a regular error message instead of cloudSessionImportFailed so
  the webview keeps the imported session rather than discarding it
- session.tsx: clean up stale pending session messages from the store after
  transferring them to the real session ID to prevent a memory leak
this.postMessage({
type: "error",
message: session ? `[sessionID:${session}] ${base}` : base,
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: handleSendCommand error response is missing the sessionID property, unlike handleImportAndSendCommand (line 1512)

The webview's error handler in session.tsx (line 399–403) checks message.sessionID to decide whether to clear loading state and reset pendingSessionKey. Without sessionID on this error message, the !message.sessionID fallback always evaluates to true, which means:

  1. Loading state is cleared even if the error is for a different session than the one currently displayed.
  2. pendingSessionKey is always reset, even when the error belongs to a background session.

This is inconsistent with handleImportAndSendCommand at line 1509–1513 which correctly includes sessionID: session.id.

Suggested change
})
this.postMessage({
type: "error",
message: session ? `[sessionID:${session}] ${base}` : base,
sessionID: session,
})

Without the sessionID property on the error message, the webview error
handler always matched the current session (falling back to currentSessionID()),
potentially clearing loading state for the wrong session when multiple
sessions are active.
@Githubguy132010 Githubguy132010 deleted the feat/vscode-workflows-and-slash-commands branch February 27, 2026 20:48
@Githubguy132010
Copy link
Copy Markdown
Contributor Author

Redoing this PR tomorrow because bugs keep coming in

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Rules / Workflows

1 participant