Skip to content
| Marketplace
Sign in
Visual Studio Code>Notebooks>code-lc4riNew to Visual Studio Code? Get it now.
code-lc4ri

code-lc4ri

yasutakatou

|
56 installs
| (0) | Free
LC4RI for VS Code — Markdown driven reproducible operations
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

code-lc4ri

code-lc4ri: Markdown + LC4RI for VS Code

Github issues Github forks Github stars Github top language Github license

Tags

vscode vscode-extension typescript nodejs lc4ri markdown

Demo

lc4ri

Do you often use "jupyter notebook" when choosing a documentation tool for your operations manual?
But, this include problems

  • document used splited to like a card. So, when insert document, insert card every. I don't fit in this operation.
  • In case of operation of the order, I have to switch the cards up and down. I wish to edit like a text editer.
  • I wish to use ecosystem(lint tool, etc). But, not easy preparation.

jupyter is very excellent tool, but I know more usefull for text edit. it's VSCode!
My idea is, Markdown + LC4RI on VSCode's ecosystem is more better solution!

Advantages

This extention, usually write markdown document. and additional commands can be executed.

  • write document on markdown format.
  • list format on markdown is can run command.
  • command output to auto apply to document.
  • can use variable.

Installation

Visual Studio Marketplace

download vsix from release page.
save vsix file, install how to.

uninstall

uninstalld extension.

use case

recommendation

set keybindings.json, enable it's shortcut do.

[
	{
		"key": "ctrl+shift+a",
		"command": "extension.lc4ri",
		"args": "code-lc4ri: LC4RI for VS Code"
	}
]

formats

Basic. You can write markdown usually, but it's can run following.
run this extension, line search, if match rule line, run commands. start line is editor's cursor position.

list format

  • list strings can be run.
- ls

1

note) If not exists code section after list, will create code section and output to it.
note) Tab indents means, If command success is next indent run. (AND rule)

- ls existsfile.txt
	- rm existsfile.txt

If "ls existsfile.txt" is success, next indent run.

horizon line

If you write horizon line, split commands.

- ls

*** 

- uname

2

3

note) In this case, run command to the horizon line.

variable

number list is create variable value.

1. uname

create variable {1}.

- echo {1}

variable {1} output.

4

note) variable can use 1-9 integer.

file open (v0.91-)

To the top "!" at the beginning opens the specified file in a new tab

- ! \code.txt

image

v0.5: "config file" support!

This extension easier use, support config file.

sample setting

json format.

{
  "timeout": 10000,
  "template": {
    "linux": "ssh user@192.168.0.1 {COMMAND}"
  },
  "changeWord": {
    "#HOME#": "/home/user"
  },
  "toutf8": true,
  "toterminal": true
}

file create

If does not exist, it will be created in the following folder.

  • Windows
    • %USERPROFILE%/.code-lc4ri/config.json
      • ex) C:\Users(USER NAME).code-lc4ri\config.json
  • Other OS
    • $HOME/.code-lc4ri/config.json
      • ex) /home/user/.code-lc4ri/config.json

file load

When VSCode run, loading config.

options

options detail following.

timeout

This option is the timeout time when the command is executed.
Units are in milliseconds.

10000 -> 10 seconds.

template

This option is default commands template, and can be defined on a per-OS.
For example, you want to execute every commands on SSH destination.
In case of can set this option.

	"OS type":"template"

"OS Type" is following.

process.platform

{COMMAND} included the original commands.

	"linux": "ssh user@192.168.0.1 {COMMAND}"
  • normal
    • - ls
  • define
    • ssh user@192.168.0.1 "{COMMAND}"
  • execute commands
    • ssh user@192.168.0.1 ls

chageWord

This option is convert keywords list.
If server address changes often, If you don't want to use commands that are dangerous to execute.
In case of can set this option.
Defines a set of words before and after conversion.

	"pre word": "after word"
  • normal
    • - ls #HOME#
  • define
    • "#HOME#": "/home/user"
  • execute commands
    • ls /home/user

toutf8 (v0.91-)

If set to false, force UTF-8 conversion process to be skipped (default is true)
However, it is not working properly on my Windows...

toterminal (v0.91-)

If true, the command execution results are not returned to the markdown, but are executed directly on the open terminal.

image

v0.6: executed time auto print.

5

It can be used as evidence of execution time.



v1.0: major refactor — what's new

This release rewrites the core runner. All existing v0.x documents keep working (list / number list / *** separator / ! file / template / changeWord / toutf8 / toterminal are unchanged). The new features are additive.

1. Asynchronous execution + progress + cancel

The old execSync loop is gone. Commands are now spawned and the UI no longer freezes.

  • A toast appears in the bottom-right showing the currently running command.
  • The toast has a Cancel button. Clicking it sends SIGTERM to every running child process.
  • Timeouts are still honoured (lc4ri.timeout), but a timeout now records [timeout after Nms] in the output instead of throwing.
  • Non-zero exits are recorded as [exit N].

New command: code-lc4ri: Cancel running commands (extension.lc4ri.cancel).

2. Inline ▶ Run / Dry-run buttons (CodeLens)

Every - command / 1. command line in a Markdown file gets an inline action:

▶ Run | Dry-run
- uname -a

You no longer need to move the cursor and trigger the global shortcut for a one-off line. Disable with "lc4ri.showCodeLens": false.

3. settings.json migration (backward-compatible)

The extension now reads its configuration from VS Code settings first, then falls back to the legacy ~/.code-lc4ri/config.json. Both work. Settings UI is auto-generated.

// settings.json
{
  "lc4ri.timeout": 15000,
  "lc4ri.profiles": {
    "prod-ssh": "ssh ops@prod.example.com {COMMAND}",
    "docker":   "docker exec -i app sh -c \"{COMMAND}\""
  },
  "lc4ri.changeWord": { "#HOME#": "/home/user" },
  "lc4ri.outputFormat": "collapsible",
  "lc4ri.confirmDangerous": true,
  "lc4ri.showCodeLens": true
}

Other hardening: JSON.parse failures no longer crash activation, workspaceFolders is null-checked, err.stderr is no longer assumed to be a string.

4. Workspace Trust + dangerous-command guard

  • The extension declares "untrustedWorkspaces": { "supported": "limited" } — in Restricted Mode, only dry-run is allowed. This blocks "open the doc → it runs rm -rf /" attacks.
  • Commands matching lc4ri.dangerousPatterns raise a modal confirmation. A reasonable default list ships out of the box (rm -rf /, dd if=, mkfs., fork bombs, curl | sh, raw block-device writes, etc.).
  • lc4ri.denyList flatly refuses matching commands; lc4ri.allowList, when non-empty, only lets matching commands run. Both accept JavaScript regex strings.
  • Every executed command is mirrored to the code-lc4ri Output channel for auditing.

5. Named variables, built-ins, output binding

Previously variables were limited to {1} … {9}. Now:

syntax meaning
1. cmd → {host} bind the output of the numbered command to both {1} and {host}
- cmd → {files} bind the output of a list command to {files}
{$PREV} stdout of the previous command
{$STATUS} exit code of the previous command
{$DATE} / {$CWD} / {$USER} / {$HOST} runtime values

Example:

1. hostname → {host}
- echo working on {host}
- false
- assert: status == 1

6. Assertions (- assert: ...)

Verify the previous command's output / exit code inside an indented chain:

- curl -s http://api.local/health
    - assert: contains "ok"
    - assert: status == 0
    - assert: regex /version: \d+/

Assertion outcomes are written into the output block (✓ pass / ✗ FAIL) and a failure breaks the AND-chain just like a failed command does.

7. Status-bar profile switcher

A lc4ri: <profile> item appears on the right side of the status bar. Click it to pick a profile defined in lc4ri.profiles. The active profile wraps each command with its {COMMAND} template — useful for SSH / Docker / kubectl context switching without editing the doc.

The legacy per-OS template still applies when no profile is selected.

8. Report export

Generate a timestamped execution report from this session:

  • code-lc4ri: Export execution report (HTML) → styled HTML with ✓/✗ markers per command.
  • code-lc4ri: Export execution report (Markdown) → plain Markdown.

The report contains every command executed since activation (including timestamps and exit codes) — useful as operational evidence or as a CI artefact.

9. CLI runner (headless / CI)

A code-lc4ri binary is shipped that re-uses the same parser:

npx code-lc4ri run runbook.md
npx code-lc4ri run runbook.md --dry-run
npx code-lc4ri run runbook.md --profile prod-ssh --report report.html

Exit code is non-zero if any command failed or any assert: failed, so it slots into CI directly. Run npm run compile once before using the CLI from source.

10. New commands cheatsheet

Command What it does
extension.lc4ri Run from cursor (the original behaviour)
extension.lc4ri.dryRun Run from cursor, but only show the resolved commands
extension.lc4ri.runLine Run a single line (used by CodeLens)
extension.lc4ri.cancel Cancel every running child process
extension.lc4ri.switchProfile Pick an execution profile
extension.lc4ri.clearOutput Empty the nearest ``` block below the cursor
extension.lc4ri.exportReport Export an HTML report
extension.lc4ri.exportReportMd Export a Markdown report

11. New settings cheatsheet

Key Default Description
lc4ri.timeout 10000 Per-command timeout in ms
lc4ri.template {} Legacy per-OS template ({ "linux": "ssh u@h {COMMAND}" })
lc4ri.profiles {} Named profiles selectable from the status bar
lc4ri.changeWord {} Pre→post substitution map
lc4ri.toUtf8 true Auto-detect encoding and convert to UTF-8
lc4ri.toTerminal false Send to active terminal instead of capturing
lc4ri.outputFormat codeblock codeblock or collapsible (uses <details>)
lc4ri.dangerousPatterns (see below) Regex patterns that prompt a confirmation
lc4ri.allowList [] If non-empty, only matching commands run
lc4ri.denyList [] Matching commands never run
lc4ri.confirmDangerous true Show a modal for dangerous matches
lc4ri.showCodeLens true Show ▶ Run / Dry-run on list lines
lc4ri.shell null Shell binary (null = system default)

Default dangerous patterns: rm -rf /, dd if=, mkfs., shutdown, reboot, fork bombs, curl|sh, wget|sh, > /dev/sd*.

12. Developer-side changes

  • engines.vscode raised to ^1.74.0; @types/vscode and @types/node updated; typescript bumped to 5.x; eslint to 8.x; redundant iconv / iconv-lite / jschardet removed.
  • Pure helpers (regTab, horizonCheck, detectListCommand, detectNumbered, extractBinding, substituteVars, applyChangeWord, applyTemplate, checkSecurity, parseAssert) are now exported.
  • npm test runs a stand-alone Node test runner (src/test/runUnit.ts) over those helpers — 32 cases, no vscode host required.

13. Migration notes

Nothing to do — your existing documents and ~/.code-lc4ri/config.json keep working as before. To opt into the new features, add the relevant lc4ri.* keys to your settings.json. To migrate off the legacy file entirely, copy its contents under the matching lc4ri.* keys and delete the file.



v1.1: New features

1. Command execution prefix

Prefix your prompt to control how Bash calls are dispatched in the current turn:

Prefix Behavior
& <message> All Bash calls in this turn run in background
! <command> Run directly in the user's terminal (Claude Code built-in)
(none) Normal foreground execution (default)

2. .env file loading

Write the following anywhere in a runbook to load environment variables from a file:

# env: .env.prod
- echo {DB_HOST}

parseEnvFile() is exported and usable from the CLI as well.

3. Runbook include

Inline-execute another Markdown file. Variable bindings set inside the included file propagate back to the parent scope:

- include: setup.md
- echo setup complete

Circular references are detected and blocked by the CLI.

4. Parallel execution

Lines prefixed with [parallel] are grouped and executed with Promise.all:

- [parallel] ssh server1 uptime
- [parallel] ssh server2 uptime
- [parallel] ssh server3 uptime

All commands must succeed for the AND-chain to continue; one failure resets it.

5. File open and terminal send directives

Runbook syntax Behavior
- ! path.md / - open: path.md Open the file in a new VS Code tab
- ! command Send to the active terminal (no output capture)

Terminal send uses vscode.window.activeTerminal?.sendText(). In CLI mode - ! command runs as a normal shell command.

6. AND-chain indent fix (tabWidth default changed to 2)

DEFAULT_INDENT_SPACES was changed from 4 to 2 so that standard 2-space Markdown indentation maps correctly to AND-chain depth:

Spaces Old (tabWidth=4) New (tabWidth=2)
2 spaces depth 1 depth 1
4 spaces depth 1 ← bug depth 2 ✓
6 spaces depth 2 depth 3

Example:

- echo a       ← depth 0: always runs
  - echo b     ← depth 1: runs only if a succeeds
    - echo c   ← depth 2: runs only if b succeeds
- echo d       ← depth 0: always runs

Users who prefer 4-space indentation can restore the previous behaviour with "lc4ri.tabWidth": 4.

7. write: directive

Write the contents of a fenced code block to a file directly from a runbook:

- write: output/config.yaml
  ```yaml
  database:
    host: localhost
    port: 5432
  ```
  • The fenced block (``` or ~~~) content is written verbatim to the specified file.
  • Variable substitution ({varName}, {$PREV}, etc.) is supported in the file path.
  • Missing parent directories are created automatically.
  • Participates in AND-chain — an indented write: only runs if the parent command succeeded.
  • --dry-run shows the resolved path and content without writing.


v1.2: New features

1. Input / Prompt Directive

Pause execution and ask the user to type a value, storing the answer in a named variable.

- prompt: {TARGET_HOST} Enter the hostname to connect to
- ssh {TARGET_HOST} uptime

The cursor-position AND-chain rules apply — a prompt: at an indented level only fires when the parent command succeeded.

Syntax

- prompt: {VARIABLE_NAME} <message shown to the user>
Option Example Description
(none) - prompt: {NAME} Enter name Shows an input box; typed text is stored in {NAME}
secret - prompt: secret {PASS} Enter password Input is masked (password field)

If the user dismisses the dialog without entering a value, the AND-chain is broken and (cancelled by user) is recorded in the output block.

Dry-run behaviour

In dry-run mode no dialog appears. The output block records [dry-run] would prompt: <message> so you can verify the variable name and prompt text without side effects.

Example

1. hostname → {host}
- prompt: {DEPLOY_ENV} Deploy to which environment? (staging/prod)
- echo deploying {host} → {DEPLOY_ENV}

2. Retry / Wait Directive

Prefix any list command with [retry: N] to re-run it up to N additional times if it exits with a non-zero code.

Syntax

- [retry: <count>] command
- [retry: <count>, <interval>] command
- [retry: <count>, interval: <interval>] command
Part Example Description
count [retry: 5] Maximum number of retries (total attempts = count + 1)
interval (ms) [retry: 3, 500] Wait 500 ms between each retry
interval (s) [retry: 3, 2s] Wait 2 seconds between each retry

The interval unit suffix is optional — a bare number is treated as milliseconds.

Behaviour

  • If the command succeeds (exit 0) on any attempt, retrying stops immediately and the AND-chain continues normally.
  • If all attempts fail, the AND-chain is broken as usual.
  • Each wait period is recorded in the output block as [retry N/M wait Xms...] so the log is self-explanatory.
  • The progress toast shows command (try N) during retries.
  • Combining with [parallel] is supported — add both prefixes in any order.

Examples

- [retry: 3] curl -sf http://api.local/health
    - echo service is up

- [retry: 5, 2s] kubectl rollout status deployment/app

Retry until a health-check passes, with a 2-second pause between attempts:

- [retry: 10, interval: 2s] curl -sf http://db:5432/ready
    - echo database is ready
    - [retry: 3, 500] psql -c "SELECT 1"

3. Real-time Output Streaming

Command output is written into the Markdown document as it arrives, rather than after the command finishes. This is especially useful for long-running commands like log tails, build scripts, or test runners.

How it works

  • A 200 ms interval timer flushes accumulated stdout/stderr chunks into the nearest output code block below the command.
  • The output block is created on the first flush if it does not already exist.
  • Subsequent flushes replace the existing block in-place rather than appending, so the document stays tidy.
  • A final sync runs after runLines completes to ensure the last chunk is always written.
  • [stderr] lines are prefixed so they are visually distinguishable from stdout.

No configuration required

Streaming is always active. There are no extra settings to enable.

Interaction with other features

Feature Behaviour with streaming
Retry Each attempt's output is appended live; the [retry N/M wait Xms...] marker appears in real-time before the next attempt starts
Cancel Clicking Cancel in the progress toast stops the child process; whatever has already been streamed remains in the document
collapsible output format The <details> wrapper is written on the first flush and updated in-place on subsequent flushes
toterminal Output is sent to the terminal and also streamed back into the document

v1.3: Code Block Execution and Auto-Write

1. Execute bash/sh/zsh blocks sequentially

You can directly execute the contents of a fenced code block without needing to prefix each line with - . This is extremely convenient for longer shell scripts.

Variables ({VAR_NAME}) inside the block are resolved, and line-continuations () are automatically supported. Execution stops immediately if any command within the block fails.

Markdown

echo "Installing dependencies..."
curl -sL [http://api.local/tarball.gz](http://api.local/tarball.gz) | tar -xz \
    -C /opt/app \
    --strip-components=1
echo "Finished!"

2. Auto-write yaml/conf/json blocks

Fenced code blocks for configuration files (yaml, conf, json) are automatically detected and saved to disk.

Markdown

database:
  host: {DB_HOST}
  port: 5432

If you omit the filename from the fence definition, code-lc4ri will automatically generate a unique alphabetic filename (e.g. gHJkLmNa.yaml) and write the output block so you can trace what file was generated.

Markdown

{
  "status": "ready",
  "enabled": true
}

v1.4: New features

Four new panels and tooling features have been added for visibility and debuggability of runbook execution. All existing documents and settings continue to work without any changes.

1. Variable Inspector Panel

Open a live side panel that shows every variable in the current session at a glance.

How to open: Command Palette → code-lc4ri: Show Variable Inspector (extension.lc4ri.showVarInspector), or set a keybinding.

The panel opens beside the active editor and stays in sync as commands run. It is divided into four sections:

Section Contents
Numbered variables {1} – {9} and their current values
Named variables Every {name} bound via → {name} or prompt:
Built-in values {$PREV}, {$STATUS}, {$CWD} updated in real-time
Environment (session) Variables injected via export: or .env loading

The filter box at the top narrows the list by name instantly. Long values are truncated with a more / less toggle. The timestamp in the top-right corner shows when the panel was last refreshed.

The panel refreshes automatically after every command execution and after every prompt: input, so you never need to reopen it.

2. Execution History Browser

Browse, search, and re-examine past execution sessions without leaving VS Code.

How to open: Command Palette → code-lc4ri: Show Execution History (extension.lc4ri.showHistory).

What is recorded

Every time Run from cursor or ▶ Run (CodeLens) is triggered, a new session is created. When execution finishes, the session is saved to .lc4ri-history.json in the workspace root (or $HOME if no workspace is open). Up to 50 sessions are retained; older sessions are dropped automatically.

Each session records:

  • Runbook filename, start/end timestamps, active profile
  • Per-command: command text, exit code, duration, OK/fail flag

Using the panel

  • Expand / collapse a session row to see its individual commands.
  • Use the search box to filter by command text across all sessions.
  • Use the status filter (All / ✅ OK only / ❌ Failed only) to narrow by result.
  • Click Timeline on any session row to open the waterfall view for that session (see feature 4).
  • Click Clear All to wipe the history file and reset the list.

Commands

Command Description
extension.lc4ri.showHistory Open the history browser panel
extension.lc4ri.clearHistory Clear all saved history

3. Output Block Search

Search inside the output code block that follows a command, with inline highlight and next/previous navigation — without leaving the Markdown file.

How to use:

  • Click the 🔍 Search output CodeLens that appears above every output code block (``` … ```), or
  • Run code-lc4ri: Search Output Block (extension.lc4ri.searchOutput) from the Command Palette with the cursor inside or above an output block.

An input box appears. Type a keyword and press Enter.

Behaviour

  • All matches are highlighted using VS Code's standard find-match colours.
  • The current match is shown in a brighter colour; the others are dimmed.
  • An information toast shows "keyword" — N/M matches with Next ↓ and Prev ↑ buttons to step through each match.
  • Clicking Clear (or dismissing the toast) removes all decorations.
  • If the keyword is not found, a warning message is shown and no decorations are applied.

CodeLens integration

The 🔍 Search output and 🗑 Clear lenses appear on the opening fence line of every output block. They are shown alongside the existing ▶ Run and Dry-run lenses and can be disabled globally with "lc4ri.showCodeLens": false.

🔍 Search output  🗑 Clear
[ ls -la ] Mon Jun 01 14:32:00 2026
total 48
drwxr-xr-x 12 user user 4096 ...

4. Execution Timeline (Waterfall)

Visualise the duration and sequence of every command in a session as an interactive waterfall chart.

How to open:

  • Command Palette → code-lc4ri: Show Execution Timeline (extension.lc4ri.showTimeline) to see the current session.
  • Click Timeline on any row in the History Browser to see a past session.

Reading the chart

Each command is drawn as a horizontal bar. The bar starts at the command's wall-clock start time and ends at its finish time, relative to the beginning of the session.

Colour Meaning
🟢 Teal Sequential command, exit 0
🔵 Blue Parallel command ([parallel]), exit 0
🔴 Red Failed command (any exit code ≠ 0)
Grey background Parallel group — commands that ran with Promise.all

Parallel groups are indicated with a translucent box spanning all commands in the group. A group number is shown in the tooltip.

Tooltip

Hover over any bar to see a tooltip with:

  • Command text
  • OK / Failed status and exit code
  • Duration in ms or seconds
  • Parallel group number (if applicable)
  • Up to 200 characters of the command's output

Summary bar

The header area shows the total number of commands, the wall-clock duration of the whole session, and the ✅ / ❌ counts.

Duration labels (e.g. 1.23s, 450ms) are printed inside bars that are wide enough to accommodate them.

5. New commands summary (v1.4)

Command Description
extension.lc4ri.showVarInspector Open the Variable Inspector side panel
extension.lc4ri.showHistory Open the Execution History browser
extension.lc4ri.clearHistory Clear all saved execution history
extension.lc4ri.searchOutput Search inside the nearest output block
extension.lc4ri.showTimeline Open the Timeline waterfall for the current session

6. Changes in v1.5.0 — Terminal-first execution

v1.5.0 fully commits to running all commands through the visible VS Code terminal. Background shell execution (spawn) has been removed entirely.

What changed

Area v1.4 and earlier v1.5.0
Command execution Background spawn (default) or terminal (opt-in via toTerminal) Always the active terminal
Output capture stdout/stderr pipes for background mode onDidWriteTerminalData + sentinel markers
Remote support Background mode did not work in AWS CloudShell Sentinel mode works in any terminal including CloudShell custom PTY
Removed settings lc4ri.toTerminal, lc4ri.shell, lc4ri.template, lc4ri.toUtf8 —
Kept settings lc4ri.profiles, lc4ri.changeWord, lc4ri.timeout, security settings All kept

New behaviour for cd and export

Both commands now run in the active terminal (via execViaTerminal) instead of a hidden subprocess.
The extension still tracks the working directory and exported variables for variable substitution.

AWS CloudShell support

The sentinel capture strategy (onDidWriteTerminalData proposed API) is required for custom PTY terminals like AWS CloudShell.
Launch VS Code with the flag below to enable it:

code --enable-proposed-api yasutakatou.code-lc4ri

Without the flag the extension falls back to the temp-file polling strategy (works for local and Remote SSH but not CloudShell).

Removed dependencies

encoding-japanese has been removed from the runtime dependencies.

v1.5.1: Improved timeout behaviour

1. Activity-based timeout

Prior to v1.5.0 a fixed timer started at command launch and killed the process after lc4ri.timeout ms regardless of whether output was still arriving.
v1.5.1 changes this to an inactivity timeout — the timer resets every time new output is received.

Mode Timer reset condition
Shell Integration mode Every time a non-empty chunk is received from execution.read()
Temp-file fallback mode Every time the output file size increases

Behaviour comparison

Situation v1.5.0 (fixed) v1.5.1 (inactivity)
Long-running command streaming logs Killed after lc4ri.timeout Runs as long as output keeps arriving
Command that freezes mid-run Killed after lc4ri.timeout Killed lc4ri.timeout ms after the last output
Silent long-running command (build, etc.) May time out early Still may time out early — increase lc4ri.timeout

Note

The meaning of lc4ri.timeout has changed. Previously it was the maximum wall-clock time from command start. From v1.5.1 onward it is the maximum idle time between consecutive output chunks. For completely silent long-running batch jobs, set lc4ri.timeout larger than the expected run time.


v1.5.2: Windows / PowerShell support

v1.5.2 is a compatibility release focused on making every feature work on Windows (PowerShell / CMD). Existing Linux / macOS documents and settings continue to work without any changes.

1. Temp-file fallback: Windows support

The fallback execution path used when the Shell Integration API is unavailable has been updated for Windows.

Item v1.5.1 v1.5.2
Temp file location Hardcoded /tmp os.tmpdir() (%TEMP% on Windows)
Path construction folder.uri.path (URI format) folder.uri.fsPath (OS-native separators)
Shell wrapper syntax POSIX sh only Auto-switches between PowerShell and POSIX sh

The PowerShell wrapper uses Out-File -Encoding utf8 and $LASTEXITCODE.

2. cd tracking: PowerShell support

The method for obtaining the new working directory after a cd command has been updated for PowerShell.

# bash / zsh (unchanged)
cd <path> && pwd

# PowerShell (new)
try { cd <path> } catch { exit 1 }; (Get-Location).Path

&& is not supported in PowerShell 5.1, so try/catch is used instead. A failed cd exits with code 1 immediately.

3. export / env capture: PowerShell support

The command used to dump environment variables after export VAR=val has been updated for PowerShell.

# bash / zsh (unchanged)
export VAR=val && env

# PowerShell (new)
$env:VAR = 'val'; Get-ChildItem Env: | ForEach-Object { "$($_.Name)=$($_.Value)" }

The output format is consistent (NAME=VALUE) so the variable capture parsing logic is unchanged.

4. Native tracking of PowerShell $env: assignments

The PowerShell $env:VARNAME = value syntax is now tracked natively, just like export VAR=val.

- $env:KUBECONFIG = 'C:\Users\me\.kube\config'
    - kubectl get nodes

isPurePsEnvCommand() detects the assignment; resolvePsEnv() captures the value and stores it in the extension's internal env table. Compound statements containing ;, |, or & are excluded and run as regular commands.

5. New lc4ri.shell setting

A new setting lets you explicitly specify the shell type used by the active terminal.

Value Behaviour
null (default) Auto-detect from OS (Windows → PowerShell, others → bash)
"powershell" Use PowerShell syntax on any OS
"bash" Use bash syntax on Windows (Git Bash / WSL)
"cmd" Use CMD (reserved for future use)
// Using Git Bash on Windows
{ "lc4ri.shell": "bash" }

// Using PowerShell Core on macOS
{ "lc4ri.shell": "powershell" }

6. lc4ri.template restored

The per-OS command wrapper setting lc4ri.template, removed in v1.5.0, has been restored. It is looked up by process.platform when no profile is selected.

{
  "lc4ri.template": {
    "win32":  "wsl -e {COMMAND}",
    "linux":  "ssh ops@prod {COMMAND}",
    "darwin": "ssh ops@prod {COMMAND}"
  }
}

When a profile is selected it takes precedence (applyTemplate priority: profile → OS template → passthrough).

7. Windows dangerous patterns added

Windows-specific dangerous commands have been added to the default lc4ri.dangerousPatterns set.

Pattern Example command
rd /s /q rd /s /q C:\Windows
format <drive>: format D:
del /f /s /q del /f /s /q C:\tmp\*
Remove-Item -Recurse -Force Remove-Item ./critical -Recurse -Force

8. Platform support matrix

Environment With Shell Integration Without Shell Integration (fallback)
Linux / macOS — bash / zsh ✅ Full support ✅ Full support
Windows — PowerShell ✅ Full support ✅ Added in v1.5.2
Windows — Git Bash / WSL ✅ Full support (set lc4ri.shell: "bash") ✅ Works in bash mode
Windows — CMD ✅ Runs commands ⚠ cd/export tracking not supported

9. Developer-side changes

  • isWindowsShell(cfg) exported — helper that returns the active shell type
  • applyTemplate() exported (applyProfile kept as a deprecated alias)
  • isPurePsEnvCommand() exported — detects PowerShell $env: assignments
  • Test cases: 147 → 164

v1.5.3: Output block separators and blank-line stop

1. --- separator between command outputs

When multiple commands run in one session, their outputs inside the code block are now separated by ---.

Runbook:

- ls
- pwd

Resulting output block:

[ ls ] Mon Jun 09 ...
file1  file2
---
[ pwd ] Mon Jun 09 ...
/home/user

Commands run with [parallel] are separated the same way.

2. Blank line stops execution

After at least one command has run, reaching a blank line (a line with no commands) stops execution and writes the results at that point.

- ls
- pwd
          ← execution stops here; results for ls and pwd are written

- date    ← move cursor here and run again

Blank lines now act as execution boundaries, just like *** and --- (3+ characters).

Stop trigger Behaviour
*** / --- (3+ chars) Stops as before (horizon line)
``` (closing output fence) Stops as before
Blank line (after commands have run) New in v1.5.3

3. No breaking changes for existing documents

All existing runbooks and settings continue to work. If you need a blank line to be transparent (i.e., commands on both sides should run together), remove the blank line between them and use *** only where you want an explicit section boundary.


v1.5.5: Output placement fix

1. Correct output block placement during streaming

syncOutput runs on a 200 ms interval while a command is executing. In v1.5.3, the first sync fired before the stop position (horizon line or blank-line boundary) had been determined, causing the output block to be inserted at the wrong location.

v1.5.5 pre-scans the remaining lines at the start of runLines to record the horizonFlag / blankStopFlag positions before any sync can fire. The output block is now placed correctly even on the very first flush.

Scenario v1.5.3 behaviour v1.5.5 behaviour
Command before a *** separator Output occasionally placed after the separator Always placed before the separator
Command before a blank-line boundary Output occasionally placed past the blank line Always placed in the right code block

No settings or document changes are required.


v1.5.6: Runbook-relative paths and cd tracking improvement

1. write: directive resolves relative to the runbook file

Previously, if currentCwd had not been set by an earlier cd command, relative paths in write: resolved against the workspace root folder. From v1.5.6, the initial working directory is set to the directory that contains the runbook file the moment execution starts.

- write: output/config.yaml
  ```yaml
  host: localhost
  ```
Scenario v1.5.5 and earlier v1.5.6
No cd executed yet, runbook is /docs/deploy.md Writes to <workspace root>/output/config.yaml Writes to /docs/output/config.yaml
After - cd subdir Writes to subdir/output/config.yaml relative to whatever the previous cwd was Same — cd tracking is unchanged
Absolute path (write: /tmp/out.yaml) Absolute — always correct Same

Variable substitution, dry-run preview, and AND-chain depth rules are unchanged.

2. cd tracking: locally-resolved absolute paths

For cd <path> commands where the target is resolvable without querying the shell (i.e., any target other than cd - or bare cd), the extension now:

  1. Computes the absolute destination locally from the tracked cwd.
  2. Sends an absolute cd to the terminal instead of the original relative form.

This prevents the terminal's own working directory from drifting relative to the extension's tracked cwd across multiple document runs or after Reload Window.

Command v1.5.5 terminal receives v1.5.6 terminal receives
- cd subdir cd subdir cd '/abs/path/to/subdir'
- cd /opt/app cd /opt/app cd '/opt/app' (unchanged)
- cd - cd - && pwd cd - && pwd (unchanged — shell must resolve)

3. getCurrentCwd() robustness

The internal getCurrentCwd() helper no longer calls fs.existsSync() on the cached path. The cached value is trusted as-is once set, removing an unnecessary filesystem round-trip and eliminating a subtle edge case where a valid but newly-created directory was rejected on first access.


v1.5.7: Directory state fix on abnormal termination

1. Directory state reset on abnormal termination

In previous versions, if execution was interrupted abnormally (e.g., by killing VS Code, a terminal crash, or a forced window reload), the extension's internal currentCwd could be left pointing to a stale or nonexistent path. Subsequent runs would then resolve relative paths incorrectly or fail silently.

v1.5.7 fixes this by resetting currentCwd to the runbook file's directory at the start of every execution, regardless of what the cached value was from a previous session.

Scenario v1.5.6 behaviour v1.5.7 behaviour
Normal restart after completing a runbook cwd reset correctly Same
Reload Window / extension host crash mid-run cwd retained stale path from previous run cwd reset to runbook directory on next run
Terminal killed while cd was in progress Tracked cwd may not match actual terminal cwd cwd reset to runbook directory on next run

No settings or document changes are required.


LICENSE

MIT License

Contributors

  • yasutakatou
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft