From e272b559721accc58ad9a678c96356adb07af059 Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 9 Sep 2025 21:07:17 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #36 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/link-foundation/command-stream/issues/36 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8dd97eb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/link-foundation/command-stream/issues/36 +Your prepared branch: issue-36-52b7c0a5 +Your prepared working directory: /tmp/gh-issue-solver-1757441232094 + +Proceed. \ No newline at end of file From 1d8850b09611e04c9bf03536045dff4a14e41563 Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 9 Sep 2025 21:07:33 +0300 Subject: [PATCH 2/3] Remove CLAUDE.md - PR created successfully --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 8dd97eb..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/link-foundation/command-stream/issues/36 -Your prepared branch: issue-36-52b7c0a5 -Your prepared working directory: /tmp/gh-issue-solver-1757441232094 - -Proceed. \ No newline at end of file From df083de41a81b2b32eeb77a2fc95db382cab39fe Mon Sep 17 00:00:00 2001 From: konard Date: Tue, 9 Sep 2025 21:19:05 +0300 Subject: [PATCH 3/3] Add exitCode alias for code property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added exitCode as an alias for the code property in all result objects - Updated createResult function to include exitCode property - Modified all direct object creations with code property to include exitCode - Updated virtual command execution path to include exitCode - Added comprehensive tests for exitCode alias functionality - Ensures backward compatibility while providing the requested alias Fixes #36 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/$.mjs | 13 +++++++-- tests/exitcode-alias.test.mjs | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/exitcode-alias.test.mjs diff --git a/src/$.mjs b/src/$.mjs index 46c7258..aa9aa75 100755 --- a/src/$.mjs +++ b/src/$.mjs @@ -641,6 +641,7 @@ let globalShellSettings = { function createResult({ code, stdout = '', stderr = '', stdin = '' }) { return { code, + exitCode: code, stdout, stderr, stdin, @@ -2053,6 +2054,7 @@ class ProcessRunner extends StreamEmitter { const resultData = { code: finalExitCode, + exitCode: finalExitCode, stdout: this.options.capture ? (this.outChunks && this.outChunks.length > 0 ? Buffer.concat(this.outChunks).toString('utf8') : '') : undefined, stderr: this.options.capture ? (this.errChunks && this.errChunks.length > 0 ? Buffer.concat(this.errChunks).toString('utf8') : '') : undefined, stdin: this.options.capture && this.inChunks ? Buffer.concat(this.inChunks).toString('utf8') : undefined, @@ -2443,6 +2445,7 @@ class ProcessRunner extends StreamEmitter { result = { code: 0, + exitCode: 0, stdout: this.options.capture ? Buffer.concat(chunks).toString('utf8') : undefined, stderr: this.options.capture ? '' : undefined, stdin: this.options.capture ? stdinData : undefined @@ -2494,6 +2497,7 @@ class ProcessRunner extends StreamEmitter { trace('ProcessRunner', () => `Virtual command cancelled with signal ${this._cancellationSignal}, exit code: ${exitCode}`); result = { code: exitCode, + exitCode: exitCode, stdout: '', stderr: '' }; @@ -2505,6 +2509,7 @@ class ProcessRunner extends StreamEmitter { result = { ...result, code: result.code ?? 0, + exitCode: result.code ?? 0, stdout: this.options.capture ? (result.stdout ?? '') : undefined, stderr: this.options.capture ? (result.stderr ?? '') : undefined, stdin: this.options.capture ? stdinData : undefined @@ -2553,6 +2558,7 @@ class ProcessRunner extends StreamEmitter { const result = { code: exitCode, + exitCode: exitCode, stdout: error.stdout ?? '', stderr: error.stderr ?? error.message, stdin: '' @@ -3217,6 +3223,7 @@ class ProcessRunner extends StreamEmitter { } result = { code: 0, + exitCode: 0, stdout: this.options.capture ? Buffer.concat(chunks).toString('utf8') : undefined, stderr: this.options.capture ? '' : undefined, stdin: this.options.capture ? currentInput : undefined @@ -3472,6 +3479,7 @@ class ProcessRunner extends StreamEmitter { let result = { code: proc.status || 0, + exitCode: proc.status || 0, stdout: proc.stdout || '', stderr: proc.stderr || '', stdin: currentInput @@ -3647,7 +3655,7 @@ class ProcessRunner extends StreamEmitter { operators: sequence.operators }, null, 2)}`); - let lastResult = { code: 0, stdout: '', stderr: '' }; + let lastResult = { code: 0, exitCode: 0, stdout: '', stderr: '' }; let combinedStdout = ''; let combinedStderr = ''; @@ -3689,6 +3697,7 @@ class ProcessRunner extends StreamEmitter { return { code: lastResult.code, + exitCode: lastResult.code, stdout: combinedStdout, stderr: combinedStderr, async text() { @@ -3715,7 +3724,7 @@ class ProcessRunner extends StreamEmitter { } else if (subshell.command.type === 'simple') { result = await this._runSimpleCommand(subshell.command); } else { - result = { code: 0, stdout: '', stderr: '' }; + result = { code: 0, exitCode: 0, stdout: '', stderr: '' }; } return result; diff --git a/tests/exitcode-alias.test.mjs b/tests/exitcode-alias.test.mjs new file mode 100644 index 0000000..771eed8 --- /dev/null +++ b/tests/exitcode-alias.test.mjs @@ -0,0 +1,50 @@ +import { test, expect, describe, beforeEach } from 'bun:test'; +import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup +import { $, shell } from '../src/$.mjs'; + +describe('exitCode alias for code', () => { + beforeEach(() => { + // Reset all shell settings before each test + shell.errexit(false); + shell.verbose(false); + shell.xtrace(false); + shell.pipefail(false); + shell.nounset(false); + }); + + test('should provide exitCode as alias for code property', async () => { + const result = await $`exit 0`; + expect(result.code).toBe(0); + expect(result.exitCode).toBe(0); + expect(result.code).toBe(result.exitCode); + }); + + test('should have matching exitCode for non-zero exit codes', async () => { + const result = await $`exit 42`; + expect(result.code).toBe(42); + expect(result.exitCode).toBe(42); + expect(result.code).toBe(result.exitCode); + }); + + test('should have matching exitCode for successful commands', async () => { + const result = await $`echo "hello"`; + expect(result.code).toBe(0); + expect(result.exitCode).toBe(0); + expect(result.code).toBe(result.exitCode); + expect(result.stdout.trim()).toBe('hello'); + }); + + test('should maintain exitCode alias in pipeline operations', async () => { + const result = await $`echo "test" | grep "test"`; + expect(result.code).toBe(0); + expect(result.exitCode).toBe(0); + expect(result.code).toBe(result.exitCode); + }); + + test('should maintain exitCode alias for failed commands', async () => { + const result = await $`exit 42`; + expect(result.code).toBe(42); + expect(result.exitCode).toBe(42); + expect(result.code).toBe(result.exitCode); + }); +}); \ No newline at end of file