code-lc4ricode-lc4ri: Markdown + LC4RI for VS Code Tags
Demo
Do you often use "jupyter notebook" when choosing a documentation tool for your operations manual?
jupyter is very excellent tool, but I know more usefull for text edit. it's VSCode! AdvantagesThis extention, usually write markdown document. and additional commands can be executed.
Installationdownload vsix from release page. uninstalluse caserecommendationset keybindings.json, enable it's shortcut do.
formatsBasic. You can write markdown usually, but it's can run following. list format
note) If not exists code section after list, will create code section and output to it.
If "ls existsfile.txt" is success, next indent run. horizon lineIf you write horizon line, split commands.
note) In this case, run command to the horizon line. variablenumber list is create variable value.
create variable {1}.
variable {1} output.
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
v0.5: "config file" support!This extension easier use, support config file. sample settingjson format.
file createIf does not exist, it will be created in the following folder.
file loadWhen VSCode run, loading config. optionsoptions detail following. timeoutThis option is the timeout time when the command is executed. 10000 -> 10 seconds. templateThis option is default commands template, and can be defined on a per-OS.
"OS Type" is following. {COMMAND} included the original commands.
chageWordThis option is convert keywords list.
toutf8 (v0.91-)If set to false, force UTF-8 conversion process to be skipped (default is true) toterminal (v0.91-)If true, the command execution results are not returned to the markdown, but are executed directly on the open terminal. v0.6: executed time auto print.
It can be used as evidence of execution time. v1.0: major refactor — what's newThis release rewrites the core runner. All existing v0.x documents keep working (list / number list / 1. Asynchronous execution + progress + cancelThe old
New command: 2. Inline ▶ Run / Dry-run buttons (CodeLens)Every
You no longer need to move the cursor and trigger the global shortcut for a one-off line. Disable with 3. settings.json migration (backward-compatible)The extension now reads its configuration from VS Code settings first, then falls back to the legacy
Other hardening: 4. Workspace Trust + dangerous-command guard
5. Named variables, built-ins, output bindingPreviously variables were limited to
Example:
6. Assertions (
|
| 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.vscoderaised to^1.74.0;@types/vscodeand@types/nodeupdated;typescriptbumped to 5.x;eslintto 8.x; redundanticonv/iconv-lite/jschardetremoved.- Pure helpers (
regTab,horizonCheck,detectListCommand,detectNumbered,extractBinding,substituteVars,applyChangeWord,applyTemplate,checkSecurity,parseAssert) are nowexported. npm testruns a stand-alone Node test runner (src/test/runUnit.ts) over those helpers — 32 cases, novscodehost 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-runshows 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
runLinescompletes 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 matcheswith 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 typeapplyTemplate()exported (applyProfilekept 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:
- Computes the absolute destination locally from the tracked cwd.
- Sends an absolute
cdto 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





