open-research 0.1.8 → 0.1.9
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/cli.js +263 -36
- 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
|
|
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.
|
|
814
|
+
var PACKAGE_VERSION = "0.1.9";
|
|
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
|
|
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
|
|
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
|
|
5181
|
-
import
|
|
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 =
|
|
5203
|
-
await
|
|
5204
|
-
await
|
|
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
|
|
5210
|
-
import
|
|
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
|
|
5214
|
-
const sessionFile =
|
|
5215
|
-
await
|
|
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
|
|
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
|
|
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 =
|
|
5261
|
-
const raw = await
|
|
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
|
|
5374
|
-
import
|
|
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 =
|
|
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
|
|
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
|
|
5394
|
-
await
|
|
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,136 @@ 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
|
+
]);
|
|
5567
|
+
async function scanDirectoryShallow(dir, maxDepth = 2, depth = 0) {
|
|
5568
|
+
const results = [];
|
|
5569
|
+
if (depth > maxDepth) return results;
|
|
5570
|
+
try {
|
|
5571
|
+
const entries = await fs19.readdir(dir, { withFileTypes: true });
|
|
5572
|
+
for (const entry of entries) {
|
|
5573
|
+
if (IGNORED_DIRS2.has(entry.name)) continue;
|
|
5574
|
+
if (entry.name.startsWith(".") && depth === 0 && entry.isDirectory()) continue;
|
|
5575
|
+
const fullPath = path18.join(dir, entry.name);
|
|
5576
|
+
const relativePath = path18.relative(process.cwd(), fullPath);
|
|
5577
|
+
if (entry.isDirectory()) {
|
|
5578
|
+
results.push({ path: relativePath + "/", size: 0, isDir: true });
|
|
5579
|
+
const children = await scanDirectoryShallow(fullPath, maxDepth, depth + 1);
|
|
5580
|
+
results.push(...children);
|
|
5581
|
+
} else {
|
|
5582
|
+
const stat = await fs19.stat(fullPath).catch(() => null);
|
|
5583
|
+
results.push({ path: relativePath, size: stat?.size ?? 0, isDir: false });
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
} catch {
|
|
5587
|
+
}
|
|
5588
|
+
return results;
|
|
5589
|
+
}
|
|
5590
|
+
async function readKeyFiles(dir) {
|
|
5591
|
+
const contents = {};
|
|
5592
|
+
for (const name of INTERESTING_FILES) {
|
|
5593
|
+
const filePath = path18.join(dir, name);
|
|
5594
|
+
try {
|
|
5595
|
+
const content = await fs19.readFile(filePath, "utf8");
|
|
5596
|
+
contents[name] = content.slice(0, 2e3);
|
|
5597
|
+
} catch {
|
|
5598
|
+
}
|
|
5599
|
+
}
|
|
5600
|
+
return contents;
|
|
5601
|
+
}
|
|
5602
|
+
var INIT_PROMPT = `You are creating an AGENTS.md file for a research workspace. This file will be injected into an AI research agent's system prompt every session to give it instant project context.
|
|
5603
|
+
|
|
5604
|
+
Based on the directory structure and key file contents below, write a concise AGENTS.md that covers:
|
|
5605
|
+
|
|
5606
|
+
## Project Overview
|
|
5607
|
+
What is this project about? What type of research?
|
|
5608
|
+
|
|
5609
|
+
## Structure
|
|
5610
|
+
Key directories and what they contain (only the important ones).
|
|
5611
|
+
|
|
5612
|
+
## Key Files
|
|
5613
|
+
Important files and what they do (only the notable ones).
|
|
5614
|
+
|
|
5615
|
+
## Research Context
|
|
5616
|
+
What research appears to be in progress based on the files?
|
|
5617
|
+
|
|
5618
|
+
## Development
|
|
5619
|
+
How to build/run/test (if applicable, based on package.json or similar).
|
|
5620
|
+
|
|
5621
|
+
Rules:
|
|
5622
|
+
- Keep it under 1500 characters total
|
|
5623
|
+
- Be specific to THIS project, not generic
|
|
5624
|
+
- If it's unclear what the project does, say so and note what you can see
|
|
5625
|
+
- Use markdown with ## headings
|
|
5626
|
+
- Don't include obvious things ("node_modules contains npm packages")`;
|
|
5627
|
+
async function generateInitialAgentsMd(input2) {
|
|
5628
|
+
const dir = input2.workspaceDir;
|
|
5629
|
+
const files = await scanDirectoryShallow(dir);
|
|
5630
|
+
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");
|
|
5631
|
+
const keyFiles = await readKeyFiles(dir);
|
|
5632
|
+
const keyFileText = Object.entries(keyFiles).map(([name, content2]) => `### ${name}
|
|
5633
|
+
\`\`\`
|
|
5634
|
+
${content2}
|
|
5635
|
+
\`\`\``).join("\n\n");
|
|
5636
|
+
const userMessage = `Directory: ${dir}
|
|
5637
|
+
|
|
5638
|
+
File tree:
|
|
5639
|
+
${tree}
|
|
5640
|
+
|
|
5641
|
+
${keyFileText ? `Key files:
|
|
5642
|
+
${keyFileText}` : "No recognizable key files found."}`;
|
|
5643
|
+
const response = await input2.provider.callLLM({
|
|
5644
|
+
messages: [
|
|
5645
|
+
{ role: "system", content: INIT_PROMPT },
|
|
5646
|
+
{ role: "user", content: userMessage.slice(0, 3e4) }
|
|
5647
|
+
],
|
|
5648
|
+
model: input2.model ?? "gpt-5.4-mini",
|
|
5649
|
+
maxTokens: 2048,
|
|
5650
|
+
temperature: 0
|
|
5651
|
+
});
|
|
5652
|
+
const content = response.content.replace(/^```(?:markdown)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
5653
|
+
await writeAgentsMd(dir, content);
|
|
5654
|
+
return content;
|
|
5655
|
+
}
|
|
5656
|
+
|
|
5446
5657
|
// src/lib/preview/server.ts
|
|
5447
5658
|
import http2 from "http";
|
|
5448
|
-
import
|
|
5449
|
-
import
|
|
5659
|
+
import fs20 from "fs";
|
|
5660
|
+
import path19 from "path";
|
|
5450
5661
|
|
|
5451
5662
|
// src/lib/preview/latex-to-html.ts
|
|
5452
5663
|
function latexToHtml(latex) {
|
|
@@ -5713,11 +5924,11 @@ var HTML_TEMPLATE = `<!DOCTYPE html>
|
|
|
5713
5924
|
</body>
|
|
5714
5925
|
</html>`;
|
|
5715
5926
|
function startPreviewServer(texPath) {
|
|
5716
|
-
const resolved =
|
|
5927
|
+
const resolved = path19.resolve(texPath);
|
|
5717
5928
|
let currentHash = "";
|
|
5718
5929
|
function getContentHash() {
|
|
5719
5930
|
try {
|
|
5720
|
-
const content =
|
|
5931
|
+
const content = fs20.readFileSync(resolved, "utf8");
|
|
5721
5932
|
return `${content.length}-${content.slice(0, 100)}-${content.slice(-100)}`;
|
|
5722
5933
|
} catch {
|
|
5723
5934
|
return "error";
|
|
@@ -5725,7 +5936,7 @@ function startPreviewServer(texPath) {
|
|
|
5725
5936
|
}
|
|
5726
5937
|
function renderPage() {
|
|
5727
5938
|
try {
|
|
5728
|
-
const latex =
|
|
5939
|
+
const latex = fs20.readFileSync(resolved, "utf8");
|
|
5729
5940
|
const htmlContent = latexToHtml(latex);
|
|
5730
5941
|
currentHash = getContentHash();
|
|
5731
5942
|
return HTML_TEMPLATE.replace("{{CONTENT}}", htmlContent);
|
|
@@ -6484,6 +6695,20 @@ function App({
|
|
|
6484
6695
|
addSystemMessage(`Initialized workspace "${project.title}" at ${target}`);
|
|
6485
6696
|
const scanned = await scanWorkspace(target);
|
|
6486
6697
|
startTransition(() => setWorkspaceFiles(scanned.files));
|
|
6698
|
+
if (hasAuth) {
|
|
6699
|
+
addSystemMessage("Generating AGENTS.md...");
|
|
6700
|
+
try {
|
|
6701
|
+
const provider = await createProviderFromStoredAuth({ homeDir });
|
|
6702
|
+
await generateInitialAgentsMd({
|
|
6703
|
+
workspaceDir: target,
|
|
6704
|
+
provider,
|
|
6705
|
+
model: "gpt-5.4-mini"
|
|
6706
|
+
});
|
|
6707
|
+
addSystemMessage("AGENTS.md created \u2014 project context will be loaded on every session.");
|
|
6708
|
+
} catch {
|
|
6709
|
+
addSystemMessage("AGENTS.md generation skipped (connect auth first).");
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6487
6712
|
} catch (err) {
|
|
6488
6713
|
addSystemMessage(`Init failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
6489
6714
|
} finally {
|
|
@@ -7001,6 +7226,7 @@ ${msg.text}
|
|
|
7001
7226
|
const provider = await createProviderFromStoredAuth({ homeDir });
|
|
7002
7227
|
const workspace = await scanWorkspace(workspacePath);
|
|
7003
7228
|
const workspaceContext = {
|
|
7229
|
+
workspaceDir: workspacePath,
|
|
7004
7230
|
runId: sessionId,
|
|
7005
7231
|
workspaceFiles: Object.fromEntries(workspace.files.map((f) => [f.key, f.content])),
|
|
7006
7232
|
availableKeys: workspace.files.map((f) => f.key),
|
|
@@ -7133,6 +7359,7 @@ ${msg.text}
|
|
|
7133
7359
|
const provider = await createProviderFromStoredAuth({ homeDir });
|
|
7134
7360
|
const workspace = await scanWorkspace(workspacePath);
|
|
7135
7361
|
const workspaceContext = {
|
|
7362
|
+
workspaceDir: workspacePath,
|
|
7136
7363
|
runId: sessionId,
|
|
7137
7364
|
workspaceFiles: Object.fromEntries(workspace.files.map((f) => [f.key, f.content])),
|
|
7138
7365
|
availableKeys: workspace.files.map((f) => f.key),
|
|
@@ -7478,7 +7705,7 @@ ${msg.text}
|
|
|
7478
7705
|
statusParts,
|
|
7479
7706
|
statusColor,
|
|
7480
7707
|
tokenDisplay,
|
|
7481
|
-
workspaceName: hasWorkspace ?
|
|
7708
|
+
workspaceName: hasWorkspace ? path20.basename(workspacePath) : process.cwd(),
|
|
7482
7709
|
mode: agentMode,
|
|
7483
7710
|
planningStatus: planningState.status
|
|
7484
7711
|
}
|
|
@@ -7490,7 +7717,7 @@ ${msg.text}
|
|
|
7490
7717
|
var program = new Command();
|
|
7491
7718
|
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
7719
|
await ensureOpenResearchConfig();
|
|
7493
|
-
const target = workspacePath ?
|
|
7720
|
+
const target = workspacePath ? path21.resolve(workspacePath) : process.cwd();
|
|
7494
7721
|
const project = await loadWorkspaceProject(target);
|
|
7495
7722
|
const auth2 = await loadStoredAuth();
|
|
7496
7723
|
render(
|
|
@@ -7506,7 +7733,7 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
7506
7733
|
});
|
|
7507
7734
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|
|
7508
7735
|
await ensureOpenResearchConfig();
|
|
7509
|
-
const target =
|
|
7736
|
+
const target = path21.resolve(workspacePath ?? process.cwd());
|
|
7510
7737
|
const project = await initWorkspace({ workspaceDir: target });
|
|
7511
7738
|
console.log(`Initialized workspace: ${target}`);
|
|
7512
7739
|
console.log(`Title: ${project.title}`);
|
|
@@ -7575,8 +7802,8 @@ skills.command("create").argument("[name]").description("Scaffold a new user ski
|
|
|
7575
7802
|
});
|
|
7576
7803
|
skills.command("edit").argument("<name>").description("Open a user skill in $EDITOR.").action(async (name) => {
|
|
7577
7804
|
await ensureOpenResearchConfig();
|
|
7578
|
-
const skillDir =
|
|
7579
|
-
openInEditor(
|
|
7805
|
+
const skillDir = path21.join(getOpenResearchSkillsDir(), name);
|
|
7806
|
+
openInEditor(path21.join(skillDir, "SKILL.md"));
|
|
7580
7807
|
const validation = await validateSkillDirectory({ skillDir });
|
|
7581
7808
|
if (!validation.ok) {
|
|
7582
7809
|
console.error(validation.errors.join("\n"));
|
|
@@ -7587,9 +7814,9 @@ skills.command("edit").argument("<name>").description("Open a user skill in $EDI
|
|
|
7587
7814
|
});
|
|
7588
7815
|
skills.command("validate").argument("[nameOrPath]").description("Validate one user skill.").action(async (nameOrPath) => {
|
|
7589
7816
|
await ensureOpenResearchConfig();
|
|
7590
|
-
const skillDir = nameOrPath ?
|
|
7817
|
+
const skillDir = nameOrPath ? path21.isAbsolute(nameOrPath) ? nameOrPath : path21.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
|
|
7591
7818
|
const stat = await import("fs/promises").then(
|
|
7592
|
-
(
|
|
7819
|
+
(fs21) => fs21.stat(skillDir).catch(() => null)
|
|
7593
7820
|
);
|
|
7594
7821
|
if (!stat) {
|
|
7595
7822
|
throw new Error(`Skill path not found: ${skillDir}`);
|
package/package.json
CHANGED