osborn 0.9.1 → 0.9.3

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.
@@ -866,7 +866,7 @@ export async function askHaiku(workingDir, sessionId, question, researchContext,
866
866
  initProvider();
867
867
  // workspace uses workingDir for spec.md (under ~/.claude/projects/{slug}/osb/)
868
868
  // workingDir is for JSONL access (matches Claude SDK cwd)
869
- const wsDir = sessionBaseDir || workingDir;
869
+ const wsDir = workingDir;
870
870
  const workspace = getSessionWorkspace(wsDir, sessionId);
871
871
  // Primary: Gemini Flash (~1-2s) with pre-loaded JSONL context
872
872
  // Fallback: Anthropic direct API or Agent SDK (slower but functional)
@@ -888,7 +888,7 @@ let researchTaskCounter = 0;
888
888
  */
889
889
  export async function askFastBrain(workingDir, sessionId, question, opts) {
890
890
  const { chatHistory, researchContext, callbacks } = opts;
891
- const wsDir = opts.sessionBaseDir || workingDir;
891
+ const wsDir = workingDir;
892
892
  // Detect document generation requests
893
893
  const docMatch = detectDocumentRequest(question);
894
894
  if (docMatch) {
@@ -1058,7 +1058,7 @@ export async function processResearchChunk(workingDir, sessionId, task, contentC
1058
1058
  return null;
1059
1059
  }
1060
1060
  specUpdateInProgress = true;
1061
- const wsDir = sessionBaseDir || workingDir;
1061
+ const wsDir = workingDir;
1062
1062
  try {
1063
1063
  const workspace = getSessionWorkspace(wsDir, sessionId);
1064
1064
  const specPath = `${workspace}/spec.md`;
@@ -1492,7 +1492,7 @@ export async function contextualizeResearchUpdate(workingDir, sessionId, task, b
1492
1492
  initProvider();
1493
1493
  if (provider === 'none')
1494
1494
  return null;
1495
- const wsDir = sessionBaseDir || workingDir;
1495
+ const wsDir = workingDir;
1496
1496
  try {
1497
1497
  const specContent = readSessionSpec(wsDir, sessionId);
1498
1498
  const specTruncated = specContent ? specContent.substring(0, 1500) : '';
@@ -1558,7 +1558,7 @@ export async function generateProactivePrompt(workingDir, sessionId, task, resea
1558
1558
  initProvider();
1559
1559
  if (provider === 'none')
1560
1560
  return null;
1561
- const wsDir = sessionBaseDir || workingDir;
1561
+ const wsDir = workingDir;
1562
1562
  try {
1563
1563
  const specContent = readSessionSpec(wsDir, sessionId);
1564
1564
  const specTruncated = specContent ? specContent.substring(0, 2000) : '';
@@ -1636,7 +1636,7 @@ export async function generateVisualDocument(workingDir, sessionId, request, doc
1636
1636
  initProvider();
1637
1637
  if (provider === 'none')
1638
1638
  return null;
1639
- const wsDir = sessionBaseDir || workingDir;
1639
+ const wsDir = workingDir;
1640
1640
  try {
1641
1641
  const workspace = getSessionWorkspace(wsDir, sessionId);
1642
1642
  const specContent = readSessionSpec(wsDir, sessionId) || '';
@@ -1726,7 +1726,7 @@ export async function processResearchCompletion(workingDir, sessionId, task, age
1726
1726
  initProvider();
1727
1727
  if (provider === 'none')
1728
1728
  return agentResult.substring(0, 500);
1729
- const wsDir = sessionBaseDir || workingDir;
1729
+ const wsDir = workingDir;
1730
1730
  try {
1731
1731
  // Read spec for context
1732
1732
  const specContent = readSessionSpec(wsDir, sessionId) || '';
package/dist/index.js CHANGED
@@ -300,6 +300,14 @@ function startApiServer(workingDir, port) {
300
300
  // GET /sessions/export — stream a gzipped tar of ~/.claude/projects/ to the client
301
301
  // Optional ?workDir= query param: if present, export only that project's slug folder.
302
302
  if (req.method === 'GET' && url.pathname === '/sessions/export') {
303
+ if (syncToken) {
304
+ const authHeader = req.headers['authorization'] ?? '';
305
+ if (authHeader !== `Bearer ${syncToken}`) {
306
+ res.writeHead(401, { 'Content-Type': 'application/json' });
307
+ res.end(JSON.stringify({ error: 'Unauthorized' }));
308
+ return;
309
+ }
310
+ }
303
311
  const projectsDir = join(homedir(), '.claude', 'projects');
304
312
  const workDir = url.searchParams.get('workDir');
305
313
  if (workDir) {
@@ -1837,7 +1845,6 @@ async function main() {
1837
1845
  chatHistory,
1838
1846
  researchContext,
1839
1847
  callbacks,
1840
- sessionBaseDir,
1841
1848
  });
1842
1849
  haikuInFlight = null;
1843
1850
  // Voice queue items may have been held while fast brain was in flight — retry now
@@ -2013,24 +2020,19 @@ async function main() {
2013
2020
  }
2014
2021
  // Read working directory override from frontend.
2015
2022
  //
2016
- // Must validate with existsSync before accepting: a broken reverse-slug in
2017
- // the frontend's session list (see `slugToPath` in config.ts the encoding
2018
- // is lossy), a deleted project, or a bad legacy client can all produce a
2019
- // non-existent path here. Passing a non-existent cwd to
2020
- // `child_process.spawn` in the Claude SDK errors with ENOENT, which the
2021
- // SDK then reports as the misleading "Claude Code executable not found at
2022
- // .../cli.js" error (see MEMORY bug fix #11). Fall back to defaultWorkingDir
2023
- // (which is itself existsSync-verified at startup).
2023
+ // If the path doesn't exist yet (new project on first use, or freshly
2024
+ // imported sessions on a new sprite), create it with mkdirSync so the
2025
+ // agent can accept it. This is safe: recursive mkdirSync is a no-op when
2026
+ // the directory already exists, and project paths always live under the
2027
+ // workspace root. The Claude SDK child_process.spawn requires the cwd to
2028
+ // exist mkdirSync satisfies that requirement without silently falling back.
2024
2029
  if (metadata.workingDirectory && typeof metadata.workingDirectory === 'string' && metadata.workingDirectory.length > 0) {
2025
- if (existsSync(metadata.workingDirectory)) {
2026
- workingDir = metadata.workingDirectory;
2027
- console.log(`📂 Working directory from frontend: ${workingDir}`);
2028
- }
2029
- else {
2030
- console.log(`⚠️ Frontend sent workingDirectory that does not exist: ${metadata.workingDirectory}`);
2031
- console.log(` Falling back to default: ${defaultWorkingDir}`);
2032
- workingDir = defaultWorkingDir;
2030
+ if (!existsSync(metadata.workingDirectory)) {
2031
+ mkdirSync(metadata.workingDirectory, { recursive: true });
2032
+ console.log(`📁 Created project directory: ${metadata.workingDirectory}`);
2033
2033
  }
2034
+ workingDir = metadata.workingDirectory;
2035
+ console.log(`📂 Working directory from frontend: ${workingDir}`);
2034
2036
  }
2035
2037
  else {
2036
2038
  // Reset to default for new connections (in case previous session changed it)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {