diff --git a/.gitignore b/.gitignore index f789b9be2..033401839 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,16 @@ CLAUDE.local.md .paseo/ .wrangler/ **/.wrangler/ + +# Local agent/tooling artifacts (do not commit) +PLAN.md +.valknut/ +valknut-report.html/ +valknut-report.json/ +**/.playwright-mcp/ +**/.paseo-provider-history/ +.claude/settings.local.json +**/.claude/settings.local.json +.plans/ +packages/server/src/server/fixtures/dictation/dictation-debug-largest.wav +packages/server/src/server/fixtures/dictation/dictation-debug-largest.transcript.txt diff --git a/packages/app/src/utils/tool-call-parsers.test.ts b/packages/app/src/utils/tool-call-parsers.test.ts index 285b5605c..9cf3f60be 100644 --- a/packages/app/src/utils/tool-call-parsers.test.ts +++ b/packages/app/src/utils/tool-call-parsers.test.ts @@ -68,7 +68,7 @@ describe("parseToolCallDisplay", () => { test("strips shell + cd wrapper from command (Codex exec_command style)", () => { const input = { command: - '/bin/zsh -lc "cd /Users/moboudra/dev/paseo && nl -ba packages/app/src/utils/tool-call-parsers.test.ts | sed -n \'150,260p\'"', + '/bin/zsh -lc "cd /Users/me/dev/paseo && nl -ba packages/app/src/utils/tool-call-parsers.test.ts | sed -n \'150,260p\'"', }; const display: ToolCallDisplay = parseToolCallDisplay("shell", input, undefined); @@ -206,7 +206,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { const input = { files: [ { - path: "/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md", + path: "/Users/me/dev/blankpage/editor/.tasks/578561c8.md", kind: "update", }, ], @@ -214,7 +214,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { const result = { files: [ { - path: "/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md", + path: "/Users/me/dev/blankpage/editor/.tasks/578561c8.md", patch: "@@ -15,3 +15,2 @@\n-This task defines the **design philosophy**\n+This task defines the **updated philosophy**", kind: "update", }, @@ -227,7 +227,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { expect(display.type).toBe("edit"); expect(display.toolName).toBe("Edit"); if (display.type === "edit") { - expect(display.filePath).toBe("/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md"); + expect(display.filePath).toBe("/Users/me/dev/blankpage/editor/.tasks/578561c8.md"); expect(display.unifiedDiff).toBe("@@ -15,3 +15,2 @@\n-This task defines the **design philosophy**\n+This task defines the **updated philosophy**"); expect(display.oldString).toBe(""); expect(display.newString).toBe(""); @@ -238,7 +238,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { const input = { files: [ { - path: "/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts", + path: "/Users/me/.paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts", kind: { type: "update", move_path: null }, }, ], @@ -246,7 +246,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { const result = { files: [ { - path: "/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts", + path: "/Users/me/.paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts", patch: "@@ -1,1 +1,1 @@\n-foo\n+bar", kind: { type: "update", move_path: null }, }, @@ -259,7 +259,7 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { expect(display.toolName).toBe("Edit"); if (display.type === "edit") { expect(display.filePath).toBe( - "/Users/moboudra/-paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts" + "/Users/me/.paseo/worktrees/paseo/naive-zebra/packages/server/src/server/daemon-keypair.ts" ); expect(display.unifiedDiff).toBe("@@ -1,1 +1,1 @@\n-foo\n+bar"); } @@ -339,11 +339,11 @@ describe("parseToolCallDisplay - apply_patch (Codex)", () => { describe("parseToolCallDisplay - read_file (Codex)", () => { test("parses Codex read_file into read type", () => { const input = { - path: "/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md", + path: "/Users/me/dev/blankpage/editor/.tasks/578561c8.md", }; const result = { type: "read_file", - path: "/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md", + path: "/Users/me/dev/blankpage/editor/.tasks/578561c8.md", content: "260 - Source: `**bold**|`\n261 - Action: `Shift+ArrowLeft`", }; @@ -351,7 +351,7 @@ describe("parseToolCallDisplay - read_file (Codex)", () => { expect(display.type).toBe("read"); expect(display.toolName).toBe("Read"); if (display.type === "read") { - expect(display.filePath).toBe("/Users/moboudra/dev/blankpage/editor/.tasks/578561c8.md"); + expect(display.filePath).toBe("/Users/me/dev/blankpage/editor/.tasks/578561c8.md"); expect(display.content).toBe("260 - Source: `**bold**|`\n261 - Action: `Shift+ArrowLeft`"); } }); diff --git a/packages/server/.env.example b/packages/server/.env.example index e2a088b38..14969a7fc 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -1,5 +1,5 @@ # OpenAI API Key (for GPT-4, Whisper STT, and TTS) -OPENAI_API_KEY=sk-... +OPENAI_API_KEY= # TTS Configuration (optional - defaults shown) TTS_VOICE=alloy diff --git a/packages/server/README.md b/packages/server/README.md index ac7c35a18..d75e67cee 100644 --- a/packages/server/README.md +++ b/packages/server/README.md @@ -70,8 +70,8 @@ See [IMPLEMENTATION_PLAN.md](./IMPLEMENTATION_PLAN.md) for complete details. ## Environment Variables ```bash -OPENAI_API_KEY=sk-... # GPT-4 and TTS -DEEPGRAM_API_KEY=... # Streaming STT +OPENAI_API_KEY=your-openai-key-here # GPT-4 and TTS +DEEPGRAM_API_KEY=your-deepgram-key-here # Streaming STT STT_MODEL=whisper-1 # Optional: override to gpt-4o-transcribe, etc. STT_CONFIDENCE_THRESHOLD=-3.0 # Optional: reject low-confidence clips STT_DEBUG_AUDIO_DIR=.stt-debug # Optional: persist raw dictation audio for debugging diff --git a/packages/server/scripts/dictation-generate-baseline.ts b/packages/server/scripts/dictation-generate-baseline.ts index d0af31afd..3fd595595 100644 --- a/packages/server/scripts/dictation-generate-baseline.ts +++ b/packages/server/scripts/dictation-generate-baseline.ts @@ -1,5 +1,5 @@ import "dotenv/config"; -import { readFile, writeFile, mkdir } from "node:fs/promises"; +import { writeFile, mkdir } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import OpenAI from "openai"; @@ -17,22 +17,20 @@ async function main(): Promise { const __dirname = path.dirname(__filename); const repoRoot = path.resolve(__dirname, ".."); - const fixturePath = path.resolve( - repoRoot, - "src", - "server", - "fixtures", - "dictation", - "dictation-debug-largest.wav" - ); - const outPath = path.resolve( - repoRoot, - "src", - "server", - "fixtures", - "dictation", - "dictation-debug-largest.transcript.txt" - ); + const defaultOutPath = path.resolve(repoRoot, "tmp", "dictation-baseline.transcript.txt"); + const audioPath = + process.env.DICTATION_AUDIO_PATH ?? + (process.argv[2] ? path.resolve(process.argv[2]) : null); + const outPath = path.resolve(process.env.DICTATION_OUT_PATH ?? process.argv[3] ?? defaultOutPath); + + if (!audioPath) { + // eslint-disable-next-line no-console + console.error( + "Usage: npx tsx packages/server/scripts/dictation-generate-baseline.ts [outPath]\n" + + " Or set DICTATION_AUDIO_PATH / DICTATION_OUT_PATH.\n" + ); + process.exit(2); + } const apiKey = requireEnv("OPENAI_API_KEY"); const transcriptionModel = @@ -43,10 +41,8 @@ async function main(): Promise { const openai = new OpenAI({ apiKey }); - // Use a temp file path for the SDK's file stream param. - // We already have a fixture file, so just stream it. const response = await openai.audio.transcriptions.create({ - file: await import("node:fs").then((fs) => fs.createReadStream(fixturePath)), + file: await import("node:fs").then((fs) => fs.createReadStream(audioPath)), language: "en", model: transcriptionModel, prompt, @@ -59,8 +55,7 @@ async function main(): Promise { await writeFile(outPath, `${response.text.trim()}\n`, "utf8"); // eslint-disable-next-line no-console - console.log(`Wrote baseline transcript to ${outPath}`); + console.log(`Wrote transcript baseline to ${outPath}`); } await main(); - diff --git a/packages/server/src/server/daemon-e2e/checkout-debug.ts b/packages/server/src/server/daemon-e2e/checkout-debug.ts index 1fd0230fa..a3afb1529 100644 --- a/packages/server/src/server/daemon-e2e/checkout-debug.ts +++ b/packages/server/src/server/daemon-e2e/checkout-debug.ts @@ -10,6 +10,7 @@ */ import { WebSocket } from "ws"; +import os from "node:os"; import { DaemonClient } from "../../client/daemon-client.js"; // Patch WebSocket to log all messages @@ -28,7 +29,7 @@ class LoggingWebSocket extends OriginalWebSocket { } } -const PASEO_HOME = process.env.PASEO_HOME ?? "/Users/moboudra/.paseo"; +const PASEO_HOME = process.env.PASEO_HOME ?? `${os.homedir()}/.paseo`; const PASEO_PORT = process.env.PASEO_PORT ?? "6767"; const DAEMON_URL = `ws://127.0.0.1:${PASEO_PORT}/ws`; diff --git a/packages/server/src/utils/tool-call-parsers.test.ts b/packages/server/src/utils/tool-call-parsers.test.ts index fd88a609a..446f113d8 100644 --- a/packages/server/src/utils/tool-call-parsers.test.ts +++ b/packages/server/src/utils/tool-call-parsers.test.ts @@ -7,12 +7,12 @@ import { describe("stripShellWrapperPrefix", () => { test("strips /bin/zsh -lc cd path && prefix", () => { - const command = "/bin/zsh -lc cd /Users/moboudra/dev/blankpage/editor && npm run format"; + const command = "/bin/zsh -lc cd /Users/me/dev/blankpage/editor && npm run format"; expect(stripShellWrapperPrefix(command)).toBe("npm run format"); }); test("strips /bin/zsh -lc \"cd path &&\" wrapper", () => { - const command = '/bin/zsh -lc "cd /Users/moboudra/dev/blankpage/editor && npm run format"'; + const command = '/bin/zsh -lc "cd /Users/me/dev/blankpage/editor && npm run format"'; expect(stripShellWrapperPrefix(command)).toBe("npm run format"); });