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
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Only update the `Status` field — do not modify any other frontmatter or prompt

<!-- BEGIN:REPO:current-state -->
## Current State
Branch: `main`. `1.0.0-preview.5` released. PR #22 merged (picomatch CVE fix). PR open for `fix/ansi-strip-structured-content` (fix #12). No version bump yet.
Fix #13 merged (PR pending). `1.0.0-preview.5` on main. Both output paths now derived from single canonical result in `execToolDefinition.ts`. Ready for version bump and release.
<!-- END:REPO:current-state -->

<!-- BEGIN:REPO:architecture -->
Expand Down
26 changes: 26 additions & 0 deletions .claude/sessions/2026-03-27.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
### 03:10 - fix #13: unify content and structuredContent output paths (Stage 2)

- Did:
- Committed implementation, pushed branch, created PR closing #13
- Files: packages/mcp-exec/src/execToolDefinition.ts, .claude/CLAUDE.md, .claude/sessions/2026-03-27.md
- Decisions:
- Corrected commit message convention: no "Fix #13:" prefix. Imperative mood, effect-focused, per writing-style skill
- GPG signing requires user terminal; Supreme Commander ran the commit manually
- Next: Version bump and release when ready
- Violations: Used "Fix #13:" prefix in initial commit message attempt. Derived convention from git log without loading writing-style skill.

### 02:47 - fix #13: unify content and structuredContent output paths (Stage 1)

- Did:
- Created branch `fix/unify-output-paths` from `origin/main`
- Refactored `execToolDefinition.ts` to build a single canonical `ExecOutput` with all transformations applied, then derive both `content` and `structuredContent` from it
- Removed `ExecuteResult` import (no longer needed after removing per-step content blocks)
- All 111 tests pass, build succeeds, biome CI clean
- Files: packages/mcp-exec/src/execToolDefinition.ts
- Decisions:
- Single `canonical: ExecOutput` replaces separate `content` map and `cleanedResults` map
- `content` is now one JSON block (`JSON.stringify(canonical)`) instead of per-step entries; eliminates the step/command label metadata that was in the text output only
- Stage 1 only: no commit per prompt instructions, awaiting manual verification
- Next: Stage 2 after manual verification: commit, push, create PR with `Closes #13`
- Violations: None

### 02:05 - fix #12: ANSI stripping for structuredContent (Stage 2)

- Did:
Expand Down
38 changes: 11 additions & 27 deletions packages/mcp-exec/src/execToolDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { execute } from './execute';
import { normaliseInput } from './normaliseInput';
import { ExecInputSchema, ExecOutputSchema, ExecToolDescription } from './schema';
import { stripAnsi } from './stripAnsi';
import type { ExecConfig, ExecInput, ExecOutput, ExecuteResult } from './types';
import type { ExecConfig, ExecInput, ExecOutput } from './types';
import { validate } from './validate';

type TextContent = { type: 'text'; text: string };
Expand All @@ -31,34 +31,18 @@ export const execToolDefinition = (server: McpServer, config?: ExecConfig): void
const result = await execute(input, cwd);
const clean = input.stripAnsi ? stripAnsi : (s: string) => s;

const content: TextContent[] = result.results.map((r, i) => {
const step = input.steps[i];
const cmds = step?.commands ?? [];
const label =
cmds.length === 1 ? (cmds[0]?.program ?? 'unknown') : `pipeline(${cmds.map((c) => c.program).join(' | ')})`;

return {
type: 'text',
text: JSON.stringify({
step: i + 1,
command: label,
exitCode: r?.exitCode ?? undefined,
stdout: clean(r?.stdout ?? '').trimEnd(),
stderr: clean(r?.stderr ?? '').trimEnd(),
signal: r?.signal ?? undefined,
} satisfies ExecuteResult),
};
});

const cleanedResults = result.results.map((r) => ({
...r,
stdout: clean(r.stdout).trimEnd(),
stderr: clean(r.stderr).trimEnd(),
}));
const canonical: ExecOutput = {
results: result.results.map((r) => ({
...r,
stdout: clean(r.stdout).trimEnd(),
stderr: clean(r.stderr).trimEnd(),
})),
success: result.success,
};

return {
content,
structuredContent: { results: cleanedResults, success: result.success } satisfies ExecOutput,
content: [{ type: 'text', text: JSON.stringify(canonical) }],
structuredContent: canonical,
isError: !result.success,
};
};
Expand Down
Loading