Skip to content
Open
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
23 changes: 19 additions & 4 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -348,30 +348,45 @@ if (Get-Command codex -ErrorAction SilentlyContinue) {
# ── Inject buddy instructions into CLI prompt files ──

$BUDDY_INSTRUCTIONS = @"
<!-- buddy-companion v2 -->
<!-- buddy-companion v3 -->
## Buddy Companion

You have a coding companion available via the buddy MCP server.

**After completing any coding task** (writing code, fixing bugs, refactoring, deploying, running tests), **automatically call ``buddy_observe``** with a 1-sentence summary of what you did. This gives your companion XP and triggers a personality-flavored reaction. Do this every time — the user expects it.

**When insight mode is on**, also pass ``claims``, ``edges``, and ``cwd`` on every ``buddy_observe`` call:
- ``claims``: 1-4 substantive assertions from the turn that just ended. Each claim needs ``text`` (≤240 chars), ``basis`` (research/empirical/deduction/analogy/definition/llm_output/assumption/vibes), ``speaker`` (user/assistant), ``confidence`` (low/medium/high), and ``external_id`` (e.g. c1).
- ``edges``: relationships between claims — ``{ from, to, type }`` where type is supports/depends_on/contradicts/questions.
- ``cwd``: absolute path of the current project root for workspace isolation.
Skip claims/edges if the turn had no substantive structure. Check ``buddy_status`` or ``buddy_reasoning_status`` to see if insight mode is on.

At the start of each conversation, call ``buddy_status`` to check on your buddy.

If the user addresses the buddy by name, respond briefly in character before your normal response.

After calling buddy_observe, relay the buddy's reaction to the user. The first text content is an ASCII speech bubble — include it verbatim.
<!-- /buddy-companion v2 -->
<!-- /buddy-companion v3 -->
"@

function Inject-BuddyPrompt($filePath, $cliName) {
$dir = Split-Path $filePath -Parent
if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }

if ((Test-Path $filePath) -and (Select-String -Path $filePath -Pattern "buddy-companion" -Quiet)) {
Write-Host " ✓ $cliName prompt already has buddy instructions" -ForegroundColor Green
if ((Test-Path $filePath) -and (Select-String -Path $filePath -Pattern "buddy-companion v3" -Quiet)) {
Write-Host " ✓ $cliName prompt already has buddy instructions (v3)" -ForegroundColor Green
return
}

# Upgrade from older version: strip the old block before appending new one
if ((Test-Path $filePath) -and (Select-String -Path $filePath -Pattern "buddy-companion" -Quiet)) {
$content = Get-Content $filePath -Raw
$content = $content -replace '(?s)<!-- buddy-companion.*?<!-- /buddy-companion v\d+\s*-->', ''
$content = $content.Trim()
Set-Content -Path $filePath -Value $content -Encoding UTF8
Write-Host " ↑ $cliName prompt upgrading buddy instructions to v3" -ForegroundColor Green
}

Add-Content -Path $filePath -Value "`n$BUDDY_INSTRUCTIONS" -Encoding UTF8
Write-Host " ✓ $cliName prompt updated ($filePath)" -ForegroundColor Green
}
Expand Down
25 changes: 21 additions & 4 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -466,19 +466,25 @@ configure_codex_hooks

# ── Inject buddy instructions into CLI prompt files ──

BUDDY_INSTRUCTIONS='<!-- buddy-companion v2 -->
BUDDY_INSTRUCTIONS='<!-- buddy-companion v3 -->
## Buddy Companion

You have a coding companion available via the buddy MCP server.

**After completing any coding task** (writing code, fixing bugs, refactoring, deploying, running tests), **automatically call `buddy_observe`** with a 1-sentence summary of what you did. This gives your companion XP and triggers a personality-flavored reaction. Do this every time — the user expects it.

**When insight mode is on**, also pass `claims`, `edges`, and `cwd` on every `buddy_observe` call:
- `claims`: 1-4 substantive assertions from the turn that just ended. Each claim needs `text` (≤240 chars), `basis` (research/empirical/deduction/analogy/definition/llm_output/assumption/vibes), `speaker` (user/assistant), `confidence` (low/medium/high), and `external_id` (e.g. c1).
- `edges`: relationships between claims — `{ from, to, type }` where type is supports/depends_on/contradicts/questions.
- `cwd`: absolute path of the current project root for workspace isolation.
Skip claims/edges if the turn had no substantive structure. Check `buddy_status` or `buddy_reasoning_status` to see if insight mode is on.

At the start of each conversation, call `buddy_status` to check on your buddy.

If the user addresses the buddy by name, respond briefly in character before your normal response.

After calling buddy_observe, relay the buddy'\''s reaction to the user. The first text content is an ASCII speech bubble — include it verbatim.
<!-- /buddy-companion v2 -->'
<!-- /buddy-companion v3 -->'

inject_prompt() {
local file="$1"
Expand All @@ -488,11 +494,22 @@ inject_prompt() {

mkdir -p "$dir"

if [ -f "$file" ] && grep -q "buddy-companion" "$file" 2>/dev/null; then
echo -e " ${GREEN}✓${NC} $cli_name prompt already has buddy instructions"
if [ -f "$file" ] && grep -q "buddy-companion v3" "$file" 2>/dev/null; then
echo -e " ${GREEN}✓${NC} $cli_name prompt already has buddy instructions (v3)"
return 0
fi

# Upgrade from older version: strip the old block before appending new one
if [ -f "$file" ] && grep -q "buddy-companion" "$file" 2>/dev/null; then
if grep -q "<!-- /buddy-companion" "$file" 2>/dev/null; then
sed -i '/<!-- buddy-companion/,/<!-- \/buddy-companion/d' "$file"
else
# Malformed block (no closing marker) — remove just the opening line
sed -i '/<!-- buddy-companion/d' "$file"
fi
echo -e " ${GREEN}↑${NC} $cli_name prompt upgrading buddy instructions to v3"
fi

# Append to existing file or create new one
echo "" >> "$file"
echo "$BUDDY_INSTRUCTIONS" >> "$file"
Expand Down
15 changes: 8 additions & 7 deletions src/__tests__/doctor.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync } from 'fs';
import { describe, it, expect } from 'vitest';
import { runDiagnostics, formatReport, PROMPT_SENTINEL_V2 } from '../lib/doctor.js';
import { runDiagnostics, formatReport, PROMPT_SENTINEL_V2, PROMPT_SENTINEL_V3 } from '../lib/doctor.js';

describe('Doctor — runDiagnostics', () => {
it('returns an array of checks', () => {
Expand Down Expand Up @@ -110,18 +110,19 @@ describe('Doctor — formatReport', () => {
});

describe('Doctor — sentinel constant', () => {
it('exports the v2 sentinel string', () => {
it('exports the v2 and v3 sentinel strings', () => {
expect(PROMPT_SENTINEL_V2).toBe('buddy-companion v2');
expect(PROMPT_SENTINEL_V3).toBe('buddy-companion v3');
});

it('keeps installer prompt markers aligned with the v2 sentinel', () => {
it('keeps installer prompt markers aligned with the v3 sentinel', () => {
const installSh = readFileSync(new URL('../../install.sh', import.meta.url), 'utf-8');
const installPs1 = readFileSync(new URL('../../install.ps1', import.meta.url), 'utf-8');

expect(installSh).toContain('<!-- buddy-companion v2 -->');
expect(installSh).toContain('<!-- /buddy-companion v2 -->');
expect(installPs1).toContain('<!-- buddy-companion v2 -->');
expect(installPs1).toContain('<!-- /buddy-companion v2 -->');
expect(installSh).toContain('<!-- buddy-companion v3 -->');
expect(installSh).toContain('<!-- /buddy-companion v3 -->');
expect(installPs1).toContain('<!-- buddy-companion v3 -->');
expect(installPs1).toContain('<!-- /buddy-companion v3 -->');
});
});

Expand Down
5 changes: 3 additions & 2 deletions src/lib/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { levelProgress } from './leveling.js';
import { REASONING_CONFIG, telemetry } from './reasoning/index.js';
import { basisDistributionHealth } from './reasoning/telemetry.js';

// Shared sentinel — keep in sync with install.sh / install.ps1
// Shared sentinels — keep in sync with install.sh / install.ps1
export const PROMPT_SENTINEL_V2 = 'buddy-companion v2';
export const PROMPT_SENTINEL_V3 = 'buddy-companion v3';

/** Default clone/build root from install.sh (INSTALL_DIR) */
export function canonicalBuddyInstallDir(): string {
Expand Down Expand Up @@ -571,7 +572,7 @@ function checkPromptInjection(): DiagnosticCheck {
for (const file of hostPromptFiles()) {
const content = readTextSafe(file.path);
if (!content) continue;
if (content.includes(PROMPT_SENTINEL_V2)) found.push(`${file.host} (${file.path})`);
if (content.includes(PROMPT_SENTINEL_V3) || content.includes(PROMPT_SENTINEL_V2)) found.push(`${file.host} (${file.path})`);
else if (content.includes('buddy-companion')) legacy.push(`${file.host} (${file.path})`);
}

Expand Down