open-research 0.1.8 → 0.1.10

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.
Files changed (2) hide show
  1. package/dist/cli.js +295 -51
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
 
9
9
  // src/cli.ts
10
10
  import React4 from "react";
11
- import path19 from "path";
11
+ import path21 from "path";
12
12
  import { Command } from "commander";
13
13
  import { render } from "ink";
14
14
 
@@ -811,7 +811,7 @@ function formatDateTime(value) {
811
811
  }
812
812
 
813
813
  // src/lib/cli/version.ts
814
- var PACKAGE_VERSION = "0.1.8";
814
+ var PACKAGE_VERSION = "0.1.10";
815
815
  function getPackageVersion() {
816
816
  return PACKAGE_VERSION;
817
817
  }
@@ -860,7 +860,7 @@ async function ensureOpenResearchConfig(options) {
860
860
  }
861
861
 
862
862
  // src/tui/app.tsx
863
- import path18 from "path";
863
+ import path20 from "path";
864
864
  import {
865
865
  startTransition,
866
866
  useDeferredValue,
@@ -4929,6 +4929,72 @@ async function extractAndStoreMemories(input2) {
4929
4929
  return stored;
4930
4930
  }
4931
4931
 
4932
+ // src/lib/workspace/agents-md.ts
4933
+ import fs15 from "fs/promises";
4934
+ import path14 from "path";
4935
+ var AGENTS_MD_FILENAME = "AGENTS.md";
4936
+ async function readAgentsMd(workspaceDir) {
4937
+ try {
4938
+ return await fs15.readFile(path14.join(workspaceDir, AGENTS_MD_FILENAME), "utf8");
4939
+ } catch {
4940
+ return "";
4941
+ }
4942
+ }
4943
+ async function writeAgentsMd(workspaceDir, content) {
4944
+ await fs15.writeFile(path14.join(workspaceDir, AGENTS_MD_FILENAME), content, "utf8");
4945
+ }
4946
+ var UPDATE_SYSTEM_PROMPT = `You maintain an AGENTS.md file for a research workspace. This file gives future agent sessions instant context about the project \u2014 what it's about, what's been done, key files, and current direction.
4947
+
4948
+ You will receive:
4949
+ 1. The current AGENTS.md content (may be empty on first run)
4950
+ 2. A summary of what just happened in the latest conversation turn
4951
+
4952
+ Your job: decide if AGENTS.md should be updated based on the new information. If yes, output the FULL updated AGENTS.md content. If nothing meaningful changed, output exactly "NO_UPDATE".
4953
+
4954
+ Rules:
4955
+ - Keep it concise \u2014 under 2000 characters. This gets injected into every system prompt.
4956
+ - Structure: Project overview \u2192 Key files \u2192 Current state \u2192 Research direction
4957
+ - Only include information that helps a NEW agent session pick up where this one left off
4958
+ - Don't include conversation-specific details \u2014 only durable project knowledge
4959
+ - Update incrementally \u2014 preserve existing content, add/modify what changed
4960
+ - Use markdown with ## headings`;
4961
+ var UPDATE_USER_TEMPLATE = `Current AGENTS.md:
4962
+ ---
4963
+ {CURRENT_CONTENT}
4964
+ ---
4965
+
4966
+ Latest turn summary:
4967
+ User asked: {USER_MESSAGE}
4968
+ Agent did: {AGENT_SUMMARY}
4969
+
4970
+ Should AGENTS.md be updated? If yes, output the full updated content. If no meaningful project-level changes, output exactly "NO_UPDATE".`;
4971
+ async function maybeUpdateAgentsMd(input2) {
4972
+ if (input2.userMessage.length < 15) return false;
4973
+ if (input2.userMessage.startsWith("/")) return false;
4974
+ const currentContent = await readAgentsMd(input2.workspaceDir);
4975
+ const userPrompt = UPDATE_USER_TEMPLATE.replace("{CURRENT_CONTENT}", currentContent || "(empty \u2014 first time)").replace("{USER_MESSAGE}", input2.userMessage.slice(0, 500)).replace("{AGENT_SUMMARY}", input2.agentResponse.slice(0, 1500));
4976
+ try {
4977
+ const response = await input2.provider.callLLM({
4978
+ messages: [
4979
+ { role: "system", content: UPDATE_SYSTEM_PROMPT },
4980
+ { role: "user", content: userPrompt }
4981
+ ],
4982
+ model: input2.model ?? "gpt-5.4-mini",
4983
+ maxTokens: 2048,
4984
+ temperature: 0
4985
+ });
4986
+ const result = response.content.trim();
4987
+ if (result === "NO_UPDATE" || result.length < 20) {
4988
+ return false;
4989
+ }
4990
+ const cleaned = result.replace(/^```(?:markdown)?\n?/, "").replace(/\n?```$/, "").trim();
4991
+ await writeAgentsMd(input2.workspaceDir, cleaned);
4992
+ return true;
4993
+ } catch {
4994
+ return false;
4995
+ }
4996
+ }
4997
+
4932
4998
  // src/lib/agent/runtime.ts
4933
4999
  var TOOL_DESCRIPTIONS = {
4934
5000
  read_file: (a) => `Reading ${a.file_path ?? "file"}`,
@@ -5019,7 +5085,14 @@ async function runAgentTurn(input2) {
5019
5085
  const usage = input2.sessionUsage ?? createSessionUsage();
5020
5086
  const memories = await loadMemories({ homeDir: input2.homeDir });
5021
5087
  const memoryBlock = formatMemoriesForPrompt(memories);
5022
- const fullSystemPrompt = memoryBlock ? systemPrompt + "\n\n" + memoryBlock : systemPrompt;
5088
+ const agentsMd = input2.workspace.workspaceDir ? await readAgentsMd(input2.workspace.workspaceDir).catch(() => "") : "";
5089
+ const contextBlocks = [
5090
+ systemPrompt,
5091
+ memoryBlock ? memoryBlock : null,
5092
+ agentsMd ? `## Project Context (from AGENTS.md)
5093
+ ${agentsMd}` : null
5094
+ ].filter(Boolean).join("\n\n");
5095
+ const fullSystemPrompt = contextBlocks;
5023
5096
  let messages = [
5024
5097
  { role: "system", content: fullSystemPrompt },
5025
5098
  ...input2.history,
@@ -5086,6 +5159,18 @@ async function runAgentTurn(input2) {
5086
5159
  }
5087
5160
  }).catch(() => {
5088
5161
  });
5162
+ if (input2.workspace.workspaceDir) {
5163
+ maybeUpdateAgentsMd({
5164
+ workspaceDir: input2.workspace.workspaceDir,
5165
+ userMessage: input2.message,
5166
+ agentResponse: fullText,
5167
+ provider: input2.provider,
5168
+ model: "gpt-5.4-mini"
5169
+ }).then((updated) => {
5170
+ if (updated) input2.onAgentsMdUpdated?.();
5171
+ }).catch(() => {
5172
+ });
5173
+ }
5089
5174
  return {
5090
5175
  text: fullText,
5091
5176
  proposedUpdates,
@@ -5177,8 +5262,8 @@ function classifyUpdateRisk(update) {
5177
5262
  }
5178
5263
 
5179
5264
  // src/lib/workspace/apply-update.ts
5180
- import fs15 from "fs/promises";
5181
- import path14 from "path";
5265
+ import fs16 from "fs/promises";
5266
+ import path15 from "path";
5182
5267
  function resolveRelativePath(update) {
5183
5268
  if (update.key.startsWith("path:")) {
5184
5269
  return update.key.slice(5);
@@ -5199,20 +5284,20 @@ function resolveRelativePath(update) {
5199
5284
  }
5200
5285
  async function applyProposedUpdate(workspaceDir, update) {
5201
5286
  const relativePath = resolveRelativePath(update);
5202
- const absolutePath = path14.join(workspaceDir, relativePath);
5203
- await fs15.mkdir(path14.dirname(absolutePath), { recursive: true });
5204
- await fs15.writeFile(absolutePath, update.content, "utf8");
5287
+ const absolutePath = path15.join(workspaceDir, relativePath);
5288
+ await fs16.mkdir(path15.dirname(absolutePath), { recursive: true });
5289
+ await fs16.writeFile(absolutePath, update.content, "utf8");
5205
5290
  return absolutePath;
5206
5291
  }
5207
5292
 
5208
5293
  // src/lib/workspace/sessions.ts
5209
- import fs16 from "fs/promises";
5210
- import path15 from "path";
5294
+ import fs17 from "fs/promises";
5295
+ import path16 from "path";
5211
5296
  async function appendSessionEvent(workspaceDir, sessionId, event) {
5212
5297
  const sessionsDir = getWorkspaceSessionsDir(workspaceDir);
5213
- await fs16.mkdir(sessionsDir, { recursive: true });
5214
- const sessionFile = path15.join(sessionsDir, `${sessionId}.jsonl`);
5215
- await fs16.appendFile(sessionFile, `${JSON.stringify(event)}
5298
+ await fs17.mkdir(sessionsDir, { recursive: true });
5299
+ const sessionFile = path16.join(sessionsDir, `${sessionId}.jsonl`);
5300
+ await fs17.appendFile(sessionFile, `${JSON.stringify(event)}
5216
5301
  `, "utf8");
5217
5302
  }
5218
5303
  function parseEvents(raw) {
@@ -5228,7 +5313,7 @@ async function listSessions(workspaceDir) {
5228
5313
  const sessionsDir = getWorkspaceSessionsDir(workspaceDir);
5229
5314
  let files;
5230
5315
  try {
5231
- files = await fs16.readdir(sessionsDir);
5316
+ files = await fs17.readdir(sessionsDir);
5232
5317
  } catch {
5233
5318
  return [];
5234
5319
  }
@@ -5236,7 +5321,7 @@ async function listSessions(workspaceDir) {
5236
5321
  for (const file of files) {
5237
5322
  if (!file.endsWith(".jsonl")) continue;
5238
5323
  const id = file.replace(/\.jsonl$/, "");
5239
- const raw = await fs16.readFile(path15.join(sessionsDir, file), "utf8");
5324
+ const raw = await fs17.readFile(path16.join(sessionsDir, file), "utf8");
5240
5325
  const events = parseEvents(raw);
5241
5326
  if (events.length === 0) continue;
5242
5327
  const chatTurns = events.filter((e) => e.type === "chat.turn");
@@ -5257,8 +5342,8 @@ async function listSessions(workspaceDir) {
5257
5342
  }
5258
5343
  async function loadSessionHistory(workspaceDir, sessionId) {
5259
5344
  const sessionsDir = getWorkspaceSessionsDir(workspaceDir);
5260
- const sessionFile = path15.join(sessionsDir, `${sessionId}.jsonl`);
5261
- const raw = await fs16.readFile(sessionFile, "utf8");
5345
+ const sessionFile = path16.join(sessionsDir, `${sessionId}.jsonl`);
5346
+ const raw = await fs17.readFile(sessionFile, "utf8");
5262
5347
  const events = parseEvents(raw);
5263
5348
  const messages = [];
5264
5349
  const llmHistory = [];
@@ -5370,15 +5455,15 @@ function ConfigScreen({ items, onUpdate, onClose }) {
5370
5455
  }
5371
5456
 
5372
5457
  // src/lib/cli/update-check.ts
5373
- import fs17 from "fs/promises";
5374
- import path16 from "path";
5458
+ import fs18 from "fs/promises";
5459
+ import path17 from "path";
5375
5460
  import os4 from "os";
5376
5461
  var PACKAGE_NAME = "open-research";
5377
5462
  var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
5378
- var STATE_FILE = path16.join(os4.homedir(), ".open-research", "update-check.json");
5463
+ var STATE_FILE = path17.join(os4.homedir(), ".open-research", "update-check.json");
5379
5464
  async function readState() {
5380
5465
  try {
5381
- const raw = await fs17.readFile(STATE_FILE, "utf8");
5466
+ const raw = await fs18.readFile(STATE_FILE, "utf8");
5382
5467
  const parsed = JSON.parse(raw);
5383
5468
  return {
5384
5469
  lastCheck: typeof parsed.lastCheck === "number" ? parsed.lastCheck : 0,
@@ -5390,8 +5475,8 @@ async function readState() {
5390
5475
  }
5391
5476
  }
5392
5477
  async function writeState(state) {
5393
- await fs17.mkdir(path16.dirname(STATE_FILE), { recursive: true });
5394
- await fs17.writeFile(STATE_FILE, JSON.stringify(state), "utf8");
5478
+ await fs18.mkdir(path17.dirname(STATE_FILE), { recursive: true });
5479
+ await fs18.writeFile(STATE_FILE, JSON.stringify(state), "utf8");
5395
5480
  }
5396
5481
  function getCurrentVersion() {
5397
5482
  return getPackageVersion();
@@ -5443,10 +5528,158 @@ async function checkForUpdate() {
5443
5528
  }
5444
5529
  }
5445
5530
 
5531
+ // src/lib/workspace/init-agents-md.ts
5532
+ import fs19 from "fs/promises";
5533
+ import path18 from "path";
5534
+ var IGNORED_DIRS2 = /* @__PURE__ */ new Set([
5535
+ "node_modules",
5536
+ ".git",
5537
+ "dist",
5538
+ "build",
5539
+ ".next",
5540
+ "__pycache__",
5541
+ ".venv",
5542
+ "venv",
5543
+ ".cache",
5544
+ "target",
5545
+ ".open-research",
5546
+ "coverage"
5547
+ ]);
5548
+ var INTERESTING_FILES = /* @__PURE__ */ new Set([
5549
+ "package.json",
5550
+ "pyproject.toml",
5551
+ "Cargo.toml",
5552
+ "go.mod",
5553
+ "requirements.txt",
5554
+ "setup.py",
5555
+ "setup.cfg",
5556
+ "README.md",
5557
+ "README.txt",
5558
+ "readme.md",
5559
+ "Makefile",
5560
+ "Dockerfile",
5561
+ "docker-compose.yml",
5562
+ ".env.example",
5563
+ "tsconfig.json",
5564
+ "vitest.config.ts",
5565
+ "jest.config.js",
5566
+ "AGENTS.md"
5567
+ ]);
5568
+ async function scanDirectoryShallow(dir, maxDepth = 2, depth = 0) {
5569
+ const results = [];
5570
+ if (depth > maxDepth) return results;
5571
+ try {
5572
+ const entries = await fs19.readdir(dir, { withFileTypes: true });
5573
+ for (const entry of entries) {
5574
+ if (IGNORED_DIRS2.has(entry.name)) continue;
5575
+ if (entry.name.startsWith(".") && depth === 0 && entry.isDirectory()) continue;
5576
+ const fullPath = path18.join(dir, entry.name);
5577
+ const relativePath = path18.relative(dir, fullPath);
5578
+ if (entry.isDirectory()) {
5579
+ results.push({ path: relativePath + "/", size: 0, isDir: true });
5580
+ const children = await scanDirectoryShallow(fullPath, maxDepth, depth + 1);
5581
+ results.push(...children);
5582
+ } else {
5583
+ const stat = await fs19.stat(fullPath).catch(() => null);
5584
+ results.push({ path: relativePath, size: stat?.size ?? 0, isDir: false });
5585
+ }
5586
+ }
5587
+ } catch {
5588
+ }
5589
+ return results;
5590
+ }
5591
+ async function readKeyFiles(dir) {
5592
+ const contents = {};
5593
+ for (const name of INTERESTING_FILES) {
5594
+ try {
5595
+ const content = await fs19.readFile(path18.join(dir, name), "utf8");
5596
+ contents[name] = content.slice(0, 2e3);
5597
+ } catch {
5598
+ }
5599
+ }
5600
+ return contents;
5601
+ }
5602
+ var CREATE_PROMPT = `You are creating an AGENTS.md file for a research workspace. This file is injected into an AI research agent's system prompt every session to give it instant project context.
5603
+
5604
+ Write a concise AGENTS.md covering:
5605
+ ## Project Overview \u2014 What is this project? What research?
5606
+ ## Structure \u2014 Key directories and their purpose (only important ones)
5607
+ ## Key Files \u2014 Notable files and what they do
5608
+ ## Research Context \u2014 What research is in progress?
5609
+ ## Development \u2014 How to build/run/test (if applicable)
5610
+
5611
+ Rules:
5612
+ - Under 1500 characters. This goes into every system prompt.
5613
+ - Specific to THIS project. No generic advice.
5614
+ - Markdown with ## headings.`;
5615
+ var UPDATE_PROMPT = `You are updating an existing AGENTS.md file for a research workspace. This file is injected into an AI research agent's system prompt every session.
5616
+
5617
+ You have:
5618
+ 1. The CURRENT AGENTS.md content
5619
+ 2. A fresh scan of the workspace directory and key files
5620
+
5621
+ Your job: compare the current AGENTS.md against the actual workspace state. Update it to reflect reality:
5622
+ - Add new directories/files that appeared
5623
+ - Remove references to things that no longer exist
5624
+ - Update descriptions that are now outdated
5625
+ - Preserve any manually-added notes or context the user wrote
5626
+ - Keep the same ## heading structure
5627
+
5628
+ If AGENTS.md is already accurate, output it unchanged.
5629
+
5630
+ Rules:
5631
+ - Under 1500 characters. This goes into every system prompt.
5632
+ - Output the FULL updated AGENTS.md content, not a diff.
5633
+ - Markdown with ## headings.`;
5634
+ async function generateInitialAgentsMd(input2) {
5635
+ const dir = input2.workspaceDir;
5636
+ const files = await scanDirectoryShallow(dir);
5637
+ const tree = files.slice(0, 100).map((f) => `${f.isDir ? "d" : "f"} ${f.path}${f.size > 0 ? ` (${(f.size / 1024).toFixed(1)}KB)` : ""}`).join("\n");
5638
+ const keyFiles = await readKeyFiles(dir);
5639
+ const keyFileText = Object.entries(keyFiles).map(([name, content2]) => `### ${name}
5640
+ \`\`\`
5641
+ ${content2}
5642
+ \`\`\``).join("\n\n");
5643
+ const scanData = `Directory: ${dir}
5644
+
5645
+ File tree:
5646
+ ${tree}
5647
+
5648
+ ${keyFileText || "No recognizable key files found."}`;
5649
+ const existing = await readAgentsMd(dir);
5650
+ let systemPrompt;
5651
+ let userMessage;
5652
+ if (existing) {
5653
+ systemPrompt = UPDATE_PROMPT;
5654
+ userMessage = `Current AGENTS.md:
5655
+ ---
5656
+ ${existing}
5657
+ ---
5658
+
5659
+ Fresh workspace scan:
5660
+ ${scanData.slice(0, 25e3)}`;
5661
+ } else {
5662
+ systemPrompt = CREATE_PROMPT;
5663
+ userMessage = scanData.slice(0, 25e3);
5664
+ }
5665
+ const response = await input2.provider.callLLM({
5666
+ messages: [
5667
+ { role: "system", content: systemPrompt },
5668
+ { role: "user", content: userMessage }
5669
+ ],
5670
+ model: input2.model ?? "gpt-5.4-mini",
5671
+ maxTokens: 2048,
5672
+ temperature: 0
5673
+ });
5674
+ const content = response.content.replace(/^```(?:markdown)?\n?/, "").replace(/\n?```$/, "").trim();
5675
+ await writeAgentsMd(dir, content);
5676
+ return content;
5677
+ }
5678
+
5446
5679
  // src/lib/preview/server.ts
5447
5680
  import http2 from "http";
5448
- import fs18 from "fs";
5449
- import path17 from "path";
5681
+ import fs20 from "fs";
5682
+ import path19 from "path";
5450
5683
 
5451
5684
  // src/lib/preview/latex-to-html.ts
5452
5685
  function latexToHtml(latex) {
@@ -5713,11 +5946,11 @@ var HTML_TEMPLATE = `<!DOCTYPE html>
5713
5946
  </body>
5714
5947
  </html>`;
5715
5948
  function startPreviewServer(texPath) {
5716
- const resolved = path17.resolve(texPath);
5949
+ const resolved = path19.resolve(texPath);
5717
5950
  let currentHash = "";
5718
5951
  function getContentHash() {
5719
5952
  try {
5720
- const content = fs18.readFileSync(resolved, "utf8");
5953
+ const content = fs20.readFileSync(resolved, "utf8");
5721
5954
  return `${content.length}-${content.slice(0, 100)}-${content.slice(-100)}`;
5722
5955
  } catch {
5723
5956
  return "error";
@@ -5725,7 +5958,7 @@ function startPreviewServer(texPath) {
5725
5958
  }
5726
5959
  function renderPage() {
5727
5960
  try {
5728
- const latex = fs18.readFileSync(resolved, "utf8");
5961
+ const latex = fs20.readFileSync(resolved, "utf8");
5729
5962
  const htmlContent = latexToHtml(latex);
5730
5963
  currentHash = getContentHash();
5731
5964
  return HTML_TEMPLATE.replace("{{CONTENT}}", htmlContent);
@@ -6472,23 +6705,32 @@ function App({
6472
6705
  }
6473
6706
  case "init": {
6474
6707
  const target = process.cwd();
6475
- const existing = await loadWorkspaceProject(target);
6476
- if (existing) {
6477
- addSystemMessage(`Already a workspace: ${target}`);
6708
+ setBusy(true);
6709
+ try {
6710
+ const existing = await loadWorkspaceProject(target);
6711
+ if (!existing) {
6712
+ await initWorkspace({ workspaceDir: target });
6713
+ addSystemMessage(`Workspace initialized at ${target}`);
6714
+ }
6478
6715
  setWorkspacePath(target);
6479
- } else {
6480
- setBusy(true);
6481
- try {
6482
- const project = await initWorkspace({ workspaceDir: target });
6483
- setWorkspacePath(target);
6484
- addSystemMessage(`Initialized workspace "${project.title}" at ${target}`);
6485
- const scanned = await scanWorkspace(target);
6486
- startTransition(() => setWorkspaceFiles(scanned.files));
6487
- } catch (err) {
6488
- addSystemMessage(`Init failed: ${err instanceof Error ? err.message : String(err)}`);
6489
- } finally {
6490
- setBusy(false);
6716
+ if (!hasAuth) {
6717
+ addSystemMessage("Run /auth first \u2014 AGENTS.md generation requires auth.");
6718
+ break;
6491
6719
  }
6720
+ addSystemMessage("Scanning workspace and updating AGENTS.md...");
6721
+ const provider = await createProviderFromStoredAuth({ homeDir });
6722
+ const result = await generateInitialAgentsMd({
6723
+ workspaceDir: target,
6724
+ provider,
6725
+ model: "gpt-5.4-mini"
6726
+ });
6727
+ addSystemMessage("AGENTS.md ready. Project context will load on every session.");
6728
+ const scanned = await scanWorkspace(target);
6729
+ startTransition(() => setWorkspaceFiles(scanned.files));
6730
+ } catch (err) {
6731
+ addSystemMessage(`Init failed: ${err instanceof Error ? err.message : String(err)}`);
6732
+ } finally {
6733
+ setBusy(false);
6492
6734
  }
6493
6735
  break;
6494
6736
  }
@@ -7001,6 +7243,7 @@ ${msg.text}
7001
7243
  const provider = await createProviderFromStoredAuth({ homeDir });
7002
7244
  const workspace = await scanWorkspace(workspacePath);
7003
7245
  const workspaceContext = {
7246
+ workspaceDir: workspacePath,
7004
7247
  runId: sessionId,
7005
7248
  workspaceFiles: Object.fromEntries(workspace.files.map((f) => [f.key, f.content])),
7006
7249
  availableKeys: workspace.files.map((f) => f.key),
@@ -7133,6 +7376,7 @@ ${msg.text}
7133
7376
  const provider = await createProviderFromStoredAuth({ homeDir });
7134
7377
  const workspace = await scanWorkspace(workspacePath);
7135
7378
  const workspaceContext = {
7379
+ workspaceDir: workspacePath,
7136
7380
  runId: sessionId,
7137
7381
  workspaceFiles: Object.fromEntries(workspace.files.map((f) => [f.key, f.content])),
7138
7382
  availableKeys: workspace.files.map((f) => f.key),
@@ -7478,7 +7722,7 @@ ${msg.text}
7478
7722
  statusParts,
7479
7723
  statusColor,
7480
7724
  tokenDisplay,
7481
- workspaceName: hasWorkspace ? path18.basename(workspacePath) : process.cwd(),
7725
+ workspaceName: hasWorkspace ? path20.basename(workspacePath) : process.cwd(),
7482
7726
  mode: agentMode,
7483
7727
  planningStatus: planningState.status
7484
7728
  }
@@ -7490,7 +7734,7 @@ ${msg.text}
7490
7734
  var program = new Command();
7491
7735
  program.name("open-research").version(getPackageVersion()).description("Local-first research CLI powered by ChatGPT/Codex auth.").argument("[workspacePath]", "Optional workspace path to open").action(async (workspacePath) => {
7492
7736
  await ensureOpenResearchConfig();
7493
- const target = workspacePath ? path19.resolve(workspacePath) : process.cwd();
7737
+ const target = workspacePath ? path21.resolve(workspacePath) : process.cwd();
7494
7738
  const project = await loadWorkspaceProject(target);
7495
7739
  const auth2 = await loadStoredAuth();
7496
7740
  render(
@@ -7506,7 +7750,7 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
7506
7750
  });
7507
7751
  program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
7508
7752
  await ensureOpenResearchConfig();
7509
- const target = path19.resolve(workspacePath ?? process.cwd());
7753
+ const target = path21.resolve(workspacePath ?? process.cwd());
7510
7754
  const project = await initWorkspace({ workspaceDir: target });
7511
7755
  console.log(`Initialized workspace: ${target}`);
7512
7756
  console.log(`Title: ${project.title}`);
@@ -7575,8 +7819,8 @@ skills.command("create").argument("[name]").description("Scaffold a new user ski
7575
7819
  });
7576
7820
  skills.command("edit").argument("<name>").description("Open a user skill in $EDITOR.").action(async (name) => {
7577
7821
  await ensureOpenResearchConfig();
7578
- const skillDir = path19.join(getOpenResearchSkillsDir(), name);
7579
- openInEditor(path19.join(skillDir, "SKILL.md"));
7822
+ const skillDir = path21.join(getOpenResearchSkillsDir(), name);
7823
+ openInEditor(path21.join(skillDir, "SKILL.md"));
7580
7824
  const validation = await validateSkillDirectory({ skillDir });
7581
7825
  if (!validation.ok) {
7582
7826
  console.error(validation.errors.join("\n"));
@@ -7587,9 +7831,9 @@ skills.command("edit").argument("<name>").description("Open a user skill in $EDI
7587
7831
  });
7588
7832
  skills.command("validate").argument("[nameOrPath]").description("Validate one user skill.").action(async (nameOrPath) => {
7589
7833
  await ensureOpenResearchConfig();
7590
- const skillDir = nameOrPath ? path19.isAbsolute(nameOrPath) ? nameOrPath : path19.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
7834
+ const skillDir = nameOrPath ? path21.isAbsolute(nameOrPath) ? nameOrPath : path21.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
7591
7835
  const stat = await import("fs/promises").then(
7592
- (fs19) => fs19.stat(skillDir).catch(() => null)
7836
+ (fs21) => fs21.stat(skillDir).catch(() => null)
7593
7837
  );
7594
7838
  if (!stat) {
7595
7839
  throw new Error(`Skill path not found: ${skillDir}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-research",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Local-first research CLI agent — discover papers, synthesize notes, run analysis, and draft artifacts from your terminal.",
5
5
  "type": "module",
6
6
  "license": "MIT",