osborn 0.8.4 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-auth.d.ts +0 -1
- package/dist/claude-auth.js +1 -1
- package/dist/claude-llm.js +12 -24
- package/dist/index.js +24 -4
- package/package.json +3 -2
package/dist/claude-auth.d.ts
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* On Linux/Docker, credentials go to ~/.claude/.credentials.json (file-based, no keyring).
|
|
14
14
|
* The Fly.io volume at /workspace/.claude is symlinked to ~/.claude for persistence.
|
|
15
15
|
*/
|
|
16
|
-
export declare function resolveClaudePath(): string;
|
|
17
16
|
export interface ClaudeAuthCallbacks {
|
|
18
17
|
onUrl: (url: string) => void;
|
|
19
18
|
onWaitingForCode: () => void;
|
package/dist/claude-auth.js
CHANGED
|
@@ -25,7 +25,7 @@ import { join } from 'path';
|
|
|
25
25
|
* Also checks Docker/Linux global npm paths for Fly.io/container deployments.
|
|
26
26
|
*/
|
|
27
27
|
let _cachedClaudePath = null;
|
|
28
|
-
|
|
28
|
+
function resolveClaudePath() {
|
|
29
29
|
if (_cachedClaudePath)
|
|
30
30
|
return _cachedClaudePath;
|
|
31
31
|
// 1. Shell-based resolution — picks up nvm, homebrew, etc.
|
package/dist/claude-llm.js
CHANGED
|
@@ -11,8 +11,7 @@ import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
|
11
11
|
import { EventEmitter } from 'events';
|
|
12
12
|
import { saveSessionMetadata, getSessionWorkspace } from './config.js';
|
|
13
13
|
import { getResearchSystemPrompt, getDirectModeResearchPrompt } from './prompts.js';
|
|
14
|
-
import {
|
|
15
|
-
import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
14
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
16
15
|
import { join } from 'node:path';
|
|
17
16
|
/**
|
|
18
17
|
* Strip markdown formatting for TTS (text-to-speech)
|
|
@@ -743,27 +742,6 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
743
742
|
? getSessionWorkspace(this.#opts.workingDirectory, sessionId)
|
|
744
743
|
: null;
|
|
745
744
|
const allowedTools = this.#opts.allowedTools || [];
|
|
746
|
-
// Resolve Claude Code CLI path. The SDK looks for cli.js in its OWN node_modules
|
|
747
|
-
// dir by default, but when osborn is installed as an npm dependency the bundled
|
|
748
|
-
// SDK's cli.js loses its executable bit (npm strips it). Use the standalone
|
|
749
|
-
// @anthropic-ai/claude-code package's cli.js — found via the same shell-based
|
|
750
|
-
// resolver that claude-auth.ts uses for the CLI binary, then resolved through
|
|
751
|
-
// the symlink to the actual cli.js path.
|
|
752
|
-
const resolvedClaudeCli = (() => {
|
|
753
|
-
try {
|
|
754
|
-
const claudeBin = resolveClaudePath(); // /usr/local/.../bin/claude (symlink) or /usr/local/.../bin/claude
|
|
755
|
-
if (!claudeBin || claudeBin === 'claude')
|
|
756
|
-
return undefined;
|
|
757
|
-
// claude binary is a symlink to cli.js — resolve it
|
|
758
|
-
const realPath = realpathSync(claudeBin);
|
|
759
|
-
if (realPath.endsWith('cli.js') && existsSync(realPath))
|
|
760
|
-
return realPath;
|
|
761
|
-
}
|
|
762
|
-
catch { }
|
|
763
|
-
return undefined;
|
|
764
|
-
})();
|
|
765
|
-
if (resolvedClaudeCli)
|
|
766
|
-
console.log(`🔧 Claude CLI: ${resolvedClaudeCli}`);
|
|
767
745
|
const sdkOptions = {
|
|
768
746
|
cwd: this.#opts.workingDirectory,
|
|
769
747
|
permissionMode: this.#opts.permissionMode,
|
|
@@ -771,7 +749,6 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
771
749
|
model: this.#opts.model || 'claude-sonnet-4-6', // Sonnet orchestrator with named sub-agents (Haiku tested but ignored delegation rules)
|
|
772
750
|
enableFileCheckpointing: true,
|
|
773
751
|
extraArgs: { 'replay-user-messages': null },
|
|
774
|
-
...(resolvedClaudeCli && { pathToClaudeCodeExecutable: resolvedClaudeCli }),
|
|
775
752
|
...(this.#abortController && { abortController: this.#abortController }),
|
|
776
753
|
...(resumeSessionId && { resume: resumeSessionId }),
|
|
777
754
|
...(continueSession && !resumeSessionId && { continue: true }),
|
|
@@ -804,6 +781,17 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
804
781
|
console.log(`✅ Auto-approved ${toolName} to workspace: ${filePath}`);
|
|
805
782
|
return { behavior: 'allow', updatedInput: input };
|
|
806
783
|
}
|
|
784
|
+
// Auto-approve writer sub-agent writes to skill installation directories.
|
|
785
|
+
// Pattern matches `.claude/skills/<skillname>/<file>` in any osborn install location
|
|
786
|
+
// (npm global, dev tree, cloud sandbox), so installing a multi-file skill via the
|
|
787
|
+
// writer agent doesn't blow up into a per-file permission cascade.
|
|
788
|
+
// Requires agent_type === 'writer' — main/researcher/reasoner are blocked by PreToolUse
|
|
789
|
+
// before they ever reach canUseTool, so this check is the only path that lets a
|
|
790
|
+
// skill install through silently.
|
|
791
|
+
if (agentType === 'writer' && /\/\.claude\/skills\/[^/]+\//.test(filePath)) {
|
|
792
|
+
console.log(`✅ Auto-approved writer ${toolName} to skill dir: ${filePath}`);
|
|
793
|
+
return { behavior: 'allow', updatedInput: input };
|
|
794
|
+
}
|
|
807
795
|
// if (toolUseId && this.#approvedWriterToolUseIds.has(toolUseId)) {
|
|
808
796
|
// this.#approvedWriterToolUseIds.delete(toolUseId)
|
|
809
797
|
// console.log(`✅ Writer pre-approved ${toolName}: ${filePath}`)
|
package/dist/index.js
CHANGED
|
@@ -322,13 +322,33 @@ async function main() {
|
|
|
322
322
|
// Always the Osborn agent install directory (where this process started).
|
|
323
323
|
// This ensures .osborn/sessions/ doesn't scatter across random directories.
|
|
324
324
|
const sessionBaseDir = process.cwd(); // Always the Osborn install dir
|
|
325
|
-
|
|
325
|
+
// Self-healing fallback: blindly trusting OSBORN_CWD without checking that the directory
|
|
326
|
+
// exists has bitten us in cloud sandboxes where the env var was set to a path that didn't
|
|
327
|
+
// exist (e.g. `/root/workspace` on a daytona/* user). The Claude SDK then fails its spawn
|
|
328
|
+
// call with ENOENT and reports the misleading "Claude Code executable not found" error.
|
|
329
|
+
// Walk the candidate list in priority order and pick the first one that ACTUALLY exists.
|
|
330
|
+
// process.cwd() is the ultimate safety net — it always exists by definition.
|
|
331
|
+
const cwdCandidates = [
|
|
332
|
+
{ source: 'OSBORN_CWD env var', value: process.env.OSBORN_CWD },
|
|
333
|
+
{ source: 'config.workingDirectory', value: config.workingDirectory },
|
|
334
|
+
{ source: 'process.cwd()', value: process.cwd() },
|
|
335
|
+
];
|
|
336
|
+
let defaultWorkingDir = process.cwd();
|
|
337
|
+
let cwdSource = 'process.cwd() (last-resort fallback)';
|
|
338
|
+
for (const c of cwdCandidates) {
|
|
339
|
+
if (c.value && existsSync(c.value)) {
|
|
340
|
+
defaultWorkingDir = c.value;
|
|
341
|
+
cwdSource = c.source;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
if (c.value) {
|
|
345
|
+
console.log(` ⚠️ ${c.source} = ${c.value} (does not exist, skipping)`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
326
348
|
let workingDir = defaultWorkingDir;
|
|
327
349
|
console.log(`📂 Working directory (cwd): ${workingDir}`);
|
|
328
350
|
console.log(`📂 Session base directory: ${sessionBaseDir}`);
|
|
329
|
-
|
|
330
|
-
console.log(` (cwd from OSBORN_CWD env var)`);
|
|
331
|
-
}
|
|
351
|
+
console.log(` (cwd from ${cwdSource})`);
|
|
332
352
|
console.log(`🔬 Mode: RESEARCH`);
|
|
333
353
|
// Determine voice mode
|
|
334
354
|
const voiceMode = getVoiceMode(config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osborn",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"dev": "tsx src/index.ts",
|
|
11
11
|
"start": "tsx src/index.ts",
|
|
12
12
|
"build": "tsc",
|
|
13
|
-
"room": "tsx src/index.ts --room"
|
|
13
|
+
"room": "tsx src/index.ts --room",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"voice",
|