feat: add support for IBM Bob coding assistant#886
Conversation
- Add 7 tests covering toolId, file paths, formatting, and edge cases - Include Bob Shell adapter in cross-platform path handling tests - All 89 adapter tests now passing - Ensures Bob Shell adapter works correctly with all 11 workflows
- Implement Bob Shell command adapter with YAML frontmatter - Register adapter in CommandAdapterRegistry - Export adapter from adapters/index.ts - Add Bob Shell to AI_TOOLS configuration - Generates commands in .bob/commands/opsx-<id>.md format - Supports all 11 workflows via custom profile system
- Add Bob Shell to README.md supported tools list - Update docs/supported-tools.md with Bob Shell entry - Document .bob/commands/opsx-<id>.md command path pattern - Note that Bob Shell uses commands, not Agent Skills spec
- Add comprehensive proposal for Bob Shell integration - Document command structure and file format - Include implementation plan and success criteria - Preserve change documentation for future reference
- Update package-lock.json with latest dependencies - Add .bob/ to gitignore (test output directory)
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughAdds Bob Shell as a supported command-generation tool: new adapter implementation, re-export and registry registration, config and docs updates, tests, and Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as "CLI/Invoker"
participant Gen as "CommandGenerator"
participant Reg as "AdapterRegistry"
participant Adapter as "bobAdapter"
participant FS as "Filesystem"
CLI->>Gen: request generate command (toolId:'bob', id, content)
Gen->>Reg: resolve adapter for 'bob'
Reg-->>Gen: returns bobAdapter
Gen->>Adapter: getFilePath(commandId)
Adapter-->>Gen: ".bob/commands/opsx-<id>.md"
Gen->>Adapter: formatFile(content)
Adapter-->>Gen: formatted Markdown (YAML frontmatter + body)
Gen->>FS: write file at ".bob/commands/opsx-<id>.md"
FS-->>Gen: write success
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
README.md (1)
106-106: Prefer count-agnostic wording to avoid future drift.Line 106 hardcodes “25+ tools,” which can get out of sync with other README sections and docs. Consider wording that doesn’t require manual recounts.
📝 Suggested edit
-> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 25+ tools and growing. +> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support many tools and growing.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 106, Replace the hardcoded phrase "25+ tools" in the README line that reads "Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 25+ tools and growing." with count-agnostic wording such as "many tools," "a growing list of tools," or "dozens of tools" to avoid drift; update the text surrounding the link so it reads e.g. "Not sure if your tool is supported? View the full list — we support a growing roster of tools." and ensure the link target (docs/supported-tools.md) remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/command-generation/adapters/bob.ts`:
- Around line 15-21: The escapeYamlValue function currently replaces
backslashes, double quotes, and newlines but omits carriage returns; update
escapeYamlValue so it also escapes '\r' when serializing YAML (e.g., add a
replacement for /\r/g to produce '\\r' in the same escape chain used for
value.replace(...)). Ensure the function still wraps the escaped string in
double quotes and preserves the existing escapes for backslashes, quotes, and
newlines.
---
Nitpick comments:
In `@README.md`:
- Line 106: Replace the hardcoded phrase "25+ tools" in the README line that
reads "Not sure if your tool is supported? [View the full
list](docs/supported-tools.md) – we support 25+ tools and growing." with
count-agnostic wording such as "many tools," "a growing list of tools," or
"dozens of tools" to avoid drift; update the text surrounding the link so it
reads e.g. "Not sure if your tool is supported? View the full list — we support
a growing roster of tools." and ensure the link target (docs/supported-tools.md)
remains unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a0738528-ec68-436f-96bb-9f5c7832c974
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (8)
.gitignoreREADME.mddocs/supported-tools.mdsrc/core/command-generation/adapters/bob.tssrc/core/command-generation/adapters/index.tssrc/core/command-generation/registry.tssrc/core/config.tstest/core/command-generation/adapters.test.ts
| function escapeYamlValue(value: string): string { | ||
| // Check if value needs quoting (contains special YAML characters or starts/ends with whitespace) | ||
| const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value); | ||
| if (needsQuoting) { | ||
| // Use double quotes and escape internal double quotes and backslashes | ||
| const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n'); | ||
| return `"${escaped}"`; |
There was a problem hiding this comment.
Escape \r as well when serializing YAML description.
escapeYamlValue flags carriage returns at Line 17, but Line 20 doesn’t escape them. That can produce malformed or parser-dependent frontmatter on CRLF input.
🔧 Suggested fix
- const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
+ const escaped = value
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\r/g, '\\r')
+ .replace(/\n/g, '\\n');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function escapeYamlValue(value: string): string { | |
| // Check if value needs quoting (contains special YAML characters or starts/ends with whitespace) | |
| const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value); | |
| if (needsQuoting) { | |
| // Use double quotes and escape internal double quotes and backslashes | |
| const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n'); | |
| return `"${escaped}"`; | |
| function escapeYamlValue(value: string): string { | |
| // Check if value needs quoting (contains special YAML characters or starts/ends with whitespace) | |
| const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value); | |
| if (needsQuoting) { | |
| // Use double quotes and escape internal double quotes and backslashes | |
| const escaped = value | |
| .replace(/\\/g, '\\\\') | |
| .replace(/"/g, '\\"') | |
| .replace(/\r/g, '\\r') | |
| .replace(/\n/g, '\\n'); | |
| return `"${escaped}"`; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/core/command-generation/adapters/bob.ts` around lines 15 - 21, The
escapeYamlValue function currently replaces backslashes, double quotes, and
newlines but omits carriage returns; update escapeYamlValue so it also escapes
'\r' when serializing YAML (e.g., add a replacement for /\r/g to produce '\\r'
in the same escape chain used for value.replace(...)). Ensure the function still
wraps the escaped string in double quotes and preserves the existing escapes for
backslashes, quotes, and newlines.
Bob derives command names from filenames (opsx-apply.md → /opsx-apply), so body text referencing /opsx:apply is incorrect. Apply the same transformToHyphenCommands rewrite that opencode.ts uses. Also add argument-hint frontmatter to match peer adapters (auggie, codebuddy, etc).
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/core/command-generation/adapters/bob.ts (1)
16-24:⚠️ Potential issue | 🟡 MinorEscape
\rand preserve empty-string YAML semantics.At Line 21,
\ris not escaped, and at Line 24 an empty description serializes asdescription:(YAML null), not an empty string.🔧 Proposed fix
function escapeYamlValue(value: string): string { + if (value.length === 0) { + return '""'; + } // Check if value needs quoting (contains special YAML characters or starts/ends with whitespace) const needsQuoting = /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/.test(value); if (needsQuoting) { // Use double quotes and escape internal double quotes and backslashes - const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n'); + const escaped = value + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n'); return `"${escaped}"`; } return value; }#!/bin/bash # Verify current escape chain and empty-description expectation rg -n -C2 'function escapeYamlValue|replace\(/\\\\/g|replace\(/\\"/g|replace\(/\\n/g|replace\(/\\r/g|return value;' src/core/command-generation/adapters/bob.ts rg -n -C2 'empty description|description: \\n|description: ""|\\r' test/core/command-generation/adapters.test.ts🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/core/command-generation/adapters/bob.ts` around lines 16 - 24, The escapeYamlValue function currently doesn't escape carriage returns and allows empty strings to serialize as YAML null; update escapeYamlValue to include '\r' in the needsQuoting regex (add \r to /[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/) and add a replace for /\r/g to the escape chain (e.g., .replace(/\r/g, '\\r')) and ensure that when value === '' you return '""' (an explicit empty-string YAML value) instead of value so empty descriptions serialize as description: "".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/core/command-generation/adapters/bob.ts`:
- Around line 16-24: The escapeYamlValue function currently doesn't escape
carriage returns and allows empty strings to serialize as YAML null; update
escapeYamlValue to include '\r' in the needsQuoting regex (add \r to
/[:\n\r#{}[\],&*!|>'"%@`]|^\s|\s$/) and add a replace for /\r/g to the escape
chain (e.g., .replace(/\r/g, '\\r')) and ensure that when value === '' you
return '""' (an explicit empty-string YAML value) instead of value so empty
descriptions serialize as description: "".
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 04351423-41e4-493e-8847-2fda3a4ce665
📒 Files selected for processing (6)
docs/supported-tools.mdsrc/core/command-generation/adapters/bob.tssrc/core/command-generation/adapters/index.tssrc/core/command-generation/registry.tssrc/core/config.tstest/core/command-generation/adapters.test.ts
✅ Files skipped from review due to trivial changes (2)
- src/core/command-generation/registry.ts
- docs/supported-tools.md
🚧 Files skipped from review as they are similar to previous changes (2)
- src/core/command-generation/adapters/index.ts
- src/core/config.ts
Add support for IBM's AI coding assistant, Bob, to OpenSpec
Summary by CodeRabbit
New Features
Chores
Tests