Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions js/.changeset/visual-continuity-result-marker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
'start-command': patch
---

fix: Add empty line before result marker for visual continuity

- Added empty line before result marker (✓/✗) after command output
- Ensures consistent visual formatting: command → empty line → output → empty line → result marker
- Applied to both docker pull virtual commands and user commands
- Tests document the expected visual format

Expected format:

```
$ docker pull alpine:latest

latest: Pulling from library/alpine
...

$ echo hi

hi

```

Fixes #73
4 changes: 3 additions & 1 deletion js/src/lib/docker-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ function dockerPullImage(image) {
success = false;
}

// Print result marker and separator (no empty line needed - already printed after command)
// Print empty line before result marker for visual separation (issue #73)
// This ensures output is visually separated from the result marker
console.log();
console.log(createVirtualCommandResult(success));
console.log(createTimelineSeparator());

Expand Down
28 changes: 28 additions & 0 deletions js/test/output-blocks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,13 +533,41 @@ describe('output-blocks module', () => {
// $ docker pull alpine:latest
// <empty line>
// <docker output>
// <empty line>
// ✓
// │
// $ echo hi
// <empty line>
// hi
// <empty line>
// ✓
});

it('output formatting follows visual continuity pattern', () => {
// Issue #73: All commands should have consistent formatting:
// 1. Command line ($ ...)
// 2. Empty line (visual separation)
// 3. Command output
// 4. Empty line (visual separation)
// 5. Result marker (✓ or ✗)
//
// This test documents the expected output structure that
// dockerPullImage and runInDocker should produce.

// Verify createCommandLine produces the correct format
const commandLine = createCommandLine('docker pull alpine:latest');
expect(commandLine).toBe('$ docker pull alpine:latest');

// Verify createVirtualCommandBlock matches
const virtualCommandLine = createVirtualCommandBlock(
'docker pull alpine:latest'
);
expect(virtualCommandLine).toBe(commandLine);

// Verify result markers
expect(createVirtualCommandResult(true)).toBe('✓');
expect(createVirtualCommandResult(false)).toBe('✗');
});
});
});

Expand Down
22 changes: 11 additions & 11 deletions rust/changelog.d/73.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
fix: Fix visual continuity in docker isolation mode
fix: Complete visual continuity fix for docker isolation mode

- Fixed empty line placement in docker isolation output
- Empty line is now correctly placed AFTER the command (`$ docker pull alpine:latest`)
instead of BEFORE it
- Maintains consistent visual structure in timeline output
- Added tests for visual continuity behavior
- Added empty line BEFORE the result marker (`✓` or `✗`) for visual separation
- Ensures consistent visual formatting around all commands

Before:
Expected format:
```

$ docker pull alpine:latest

latest: Pulling from library/alpine
```
...

After:
```
$ docker pull alpine:latest
$ echo hi

latest: Pulling from library/alpine
hi

```

Fixes #73
4 changes: 3 additions & 1 deletion rust/src/lib/isolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,9 @@ pub fn docker_pull_image(image: &str) -> (bool, String) {

let success = child.wait().map(|s| s.success()).unwrap_or(false);

// Print result marker and separator (no empty line needed - already printed after command)
// Print empty line before result marker for visual separation (issue #73)
// This ensures output is visually separated from the result marker
println!();
println!(
"{}",
crate::output_blocks::create_virtual_command_result(success)
Expand Down
83 changes: 83 additions & 0 deletions rust/tests/output_blocks_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,86 @@ fn test_visual_continuity_start_block_for_docker_isolation() {
);
assert!(!block.contains("$ echo hi"), "Command should be deferred");
}

// Issue #73: Visual Continuity Tests
#[test]
fn test_visual_continuity_output_formatting() {
// Issue #73: All commands should have consistent formatting:
// 1. Command line ($ ...)
// 2. Empty line (visual separation)
// 3. Command output
// 4. Empty line (visual separation)
// 5. Result marker (✓ or ✗)
//
// This test documents the expected output structure.

use start_command::{
create_command_line, create_virtual_command_block, create_virtual_command_result,
};

// Verify createCommandLine produces the correct format
let command_line = create_command_line("docker pull alpine:latest");
assert_eq!(command_line, "$ docker pull alpine:latest");

// Verify createVirtualCommandBlock matches createCommandLine
let virtual_command_line = create_virtual_command_block("docker pull alpine:latest");
assert_eq!(virtual_command_line, command_line);

// Verify result markers
assert_eq!(create_virtual_command_result(true), "✓");
assert_eq!(create_virtual_command_result(false), "✗");
}

#[test]
fn test_visual_continuity_command_output_pattern() {
// Issue #73: The expected output pattern for docker isolation with virtual commands:
//
// │ session uuid-abc
// │ start 2026-01-08 12:00:00
// │
// │ isolation docker
// │ mode attached
// │ image alpine:latest
// │ container docker-1234
// │
// $ docker pull alpine:latest
//
// latest: Pulling from library/alpine
// ...
//
// ✓
// │
// $ echo hi
//
// hi
//
// ✓
//
// The key aspects tested here:
// 1. Start block ends with │ when defer_command is true
// 2. Virtual command and user command follow the same pattern:
// command -> empty line -> output -> empty line -> result marker

let extra = vec![
"[Isolation] Environment: docker, Mode: attached",
"[Isolation] Image: alpine:latest",
"[Isolation] Session: docker-1234",
];
let start_block = create_start_block(&StartBlockOptions {
session_id: "uuid-abc",
timestamp: "2026-01-08 12:00:00",
command: "echo hi",
extra_lines: Some(extra),
style: None,
width: None,
defer_command: true,
});

// When defer_command is true, start block should end with empty timeline line
let lines: Vec<&str> = start_block.lines().collect();
assert_eq!(
lines.last().unwrap(),
&"│",
"Start block with defer_command should end with │"
);
}