open-research 0.1.22 → 0.1.24
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 +185 -44
- 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 React5 from "react";
|
|
11
|
-
import
|
|
11
|
+
import path22 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.24";
|
|
815
815
|
function getPackageVersion() {
|
|
816
816
|
return PACKAGE_VERSION;
|
|
817
817
|
}
|
|
@@ -871,7 +871,7 @@ async function ensureOpenResearchConfig(options) {
|
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
// src/tui/app.tsx
|
|
874
|
-
import
|
|
874
|
+
import path21 from "path";
|
|
875
875
|
import {
|
|
876
876
|
startTransition,
|
|
877
877
|
useDeferredValue,
|
|
@@ -1502,7 +1502,7 @@ function TextInput({
|
|
|
1502
1502
|
}
|
|
1503
1503
|
const renderedPlaceholder = showCursor && focus && placeholder.length > 0 ? source_default.inverse(placeholder[0]) + source_default.grey(placeholder.slice(1)) : placeholder ? source_default.grey(placeholder) : void 0;
|
|
1504
1504
|
function sanitizeInput(raw) {
|
|
1505
|
-
return raw.replace(/\x1b\[[?>=!]*[0-9;]*[a-zA-Z~]/g, "").replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?/g, "").replace(/\[20[01]~/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, "");
|
|
1505
|
+
return raw.replace(/\x1b\[[?>=!]*[0-9;]*[a-zA-Z~]/g, "").replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?/g, "").replace(/\[20[01]~/g, "").replace(/\d+;\d+;\d+[~u]/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, "");
|
|
1506
1506
|
}
|
|
1507
1507
|
function insertCleanText(raw, currentValue, currentCursor) {
|
|
1508
1508
|
const clean = sanitizeInput(raw);
|
|
@@ -1542,7 +1542,7 @@ function TextInput({
|
|
|
1542
1542
|
onTab?.();
|
|
1543
1543
|
return;
|
|
1544
1544
|
}
|
|
1545
|
-
if (key.return && key.shift || key.return && key.meta) {
|
|
1545
|
+
if (key.return && key.shift || key.return && key.meta || input2 === "27;2;13~" || input2.includes("27;2;13")) {
|
|
1546
1546
|
const inserted = currentValue.slice(0, currentCursor) + "\n" + currentValue.slice(currentCursor);
|
|
1547
1547
|
cursorOffsetRef.current = currentCursor + 1;
|
|
1548
1548
|
valueRef.current = inserted;
|
|
@@ -5414,6 +5414,7 @@ ${skill.prompt}`).join("\n\n");
|
|
|
5414
5414
|
"- Be transparent. Show the user what you're doing and why.",
|
|
5415
5415
|
"- When unsure, ask. Use ask_user rather than guessing.",
|
|
5416
5416
|
"- For large outputs, redirect to a file and read selectively.",
|
|
5417
|
+
"- Always wrap file paths in backticks: `notes/brief.md`, `experiments/analysis.py`. Include line references as `src/file.ts:42`. This makes them clickable.",
|
|
5417
5418
|
"",
|
|
5418
5419
|
`## Workspace
|
|
5419
5420
|
Root: ${process.cwd()}
|
|
@@ -6616,9 +6617,88 @@ function truncate3(value, max = 96) {
|
|
|
6616
6617
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
6617
6618
|
|
|
6618
6619
|
// src/tui/markdown.ts
|
|
6619
|
-
|
|
6620
|
+
import path20 from "path";
|
|
6621
|
+
import fs21 from "fs";
|
|
6622
|
+
import { pathToFileURL } from "url";
|
|
6623
|
+
var FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6624
|
+
".py",
|
|
6625
|
+
".ts",
|
|
6626
|
+
".tsx",
|
|
6627
|
+
".js",
|
|
6628
|
+
".jsx",
|
|
6629
|
+
".r",
|
|
6630
|
+
".R",
|
|
6631
|
+
".tex",
|
|
6632
|
+
".bib",
|
|
6633
|
+
".md",
|
|
6634
|
+
".txt",
|
|
6635
|
+
".json",
|
|
6636
|
+
".yaml",
|
|
6637
|
+
".yml",
|
|
6638
|
+
".toml",
|
|
6639
|
+
".csv",
|
|
6640
|
+
".tsv",
|
|
6641
|
+
".sh",
|
|
6642
|
+
".bash",
|
|
6643
|
+
".zsh",
|
|
6644
|
+
".sql",
|
|
6645
|
+
".html",
|
|
6646
|
+
".css",
|
|
6647
|
+
".xml",
|
|
6648
|
+
".pdf",
|
|
6649
|
+
".png",
|
|
6650
|
+
".jpg",
|
|
6651
|
+
".svg",
|
|
6652
|
+
".gif",
|
|
6653
|
+
".cfg",
|
|
6654
|
+
".ini",
|
|
6655
|
+
".env",
|
|
6656
|
+
".lock",
|
|
6657
|
+
".log"
|
|
6658
|
+
]);
|
|
6659
|
+
var linkCache = /* @__PURE__ */ new Map();
|
|
6660
|
+
var LOCATION_SUFFIX_RE = /^(.*?)(:\d+(?::\d+)?)$/;
|
|
6661
|
+
function splitLocation(text) {
|
|
6662
|
+
const trimmed = text.trim();
|
|
6663
|
+
const match = trimmed.match(LOCATION_SUFFIX_RE);
|
|
6664
|
+
if (match && match[1]) {
|
|
6665
|
+
return { filePath: match[1], location: match[2] };
|
|
6666
|
+
}
|
|
6667
|
+
return { filePath: trimmed, location: "" };
|
|
6668
|
+
}
|
|
6669
|
+
function looksLikeFilePath(text) {
|
|
6670
|
+
const { filePath } = splitLocation(text);
|
|
6671
|
+
if (filePath.length < 3 || filePath.length > 260) return false;
|
|
6672
|
+
if (filePath.includes("\n")) return false;
|
|
6673
|
+
if (/^[a-z]+:\/\//i.test(filePath)) return false;
|
|
6674
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
6675
|
+
if (FILE_EXTENSIONS.has(ext)) return true;
|
|
6676
|
+
if (filePath.includes("/") || filePath.includes("\\")) return true;
|
|
6677
|
+
return false;
|
|
6678
|
+
}
|
|
6679
|
+
function fileLink(displayText, rawText, baseDir) {
|
|
6680
|
+
const { filePath } = splitLocation(rawText);
|
|
6681
|
+
const candidate = path20.isAbsolute(filePath) ? filePath : path20.resolve(baseDir, filePath);
|
|
6682
|
+
let resolved = linkCache.get(candidate);
|
|
6683
|
+
if (resolved === void 0) {
|
|
6684
|
+
try {
|
|
6685
|
+
resolved = fs21.realpathSync(candidate);
|
|
6686
|
+
} catch {
|
|
6687
|
+
resolved = null;
|
|
6688
|
+
}
|
|
6689
|
+
linkCache.set(candidate, resolved);
|
|
6690
|
+
}
|
|
6691
|
+
if (!resolved) return displayText;
|
|
6692
|
+
const uri = pathToFileURL(resolved).href;
|
|
6693
|
+
return `\x1B]8;;${uri}\x1B\\${displayText}\x1B]8;;\x1B\\`;
|
|
6694
|
+
}
|
|
6695
|
+
var BARE_PATH_RE = /((?:\.{1,2}\/|\/)[^\s`),;\]]+\.[a-zA-Z0-9]{1,6})/g;
|
|
6696
|
+
function renderMarkdown(text, options = {}) {
|
|
6620
6697
|
if (!text || !text.trim()) return text;
|
|
6621
|
-
|
|
6698
|
+
const baseDir = options.baseDir ?? process.cwd();
|
|
6699
|
+
if (!/[*_`#\[\]>~\-]/.test(text) && !text.includes("```") && !BARE_PATH_RE.test(text)) {
|
|
6700
|
+
return text;
|
|
6701
|
+
}
|
|
6622
6702
|
const lines = text.split("\n");
|
|
6623
6703
|
const output2 = [];
|
|
6624
6704
|
let inCodeBlock = false;
|
|
@@ -6651,14 +6731,10 @@ function renderMarkdown(text) {
|
|
|
6651
6731
|
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
6652
6732
|
if (headingMatch) {
|
|
6653
6733
|
const level = headingMatch[1].length;
|
|
6654
|
-
const content = renderInline(headingMatch[2]);
|
|
6655
|
-
if (level === 1)
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
output2.push(source_default.bold.white(content));
|
|
6659
|
-
} else {
|
|
6660
|
-
output2.push(source_default.bold(content));
|
|
6661
|
-
}
|
|
6734
|
+
const content = renderInline(headingMatch[2], baseDir);
|
|
6735
|
+
if (level === 1) output2.push(source_default.bold.cyan(content));
|
|
6736
|
+
else if (level === 2) output2.push(source_default.bold.white(content));
|
|
6737
|
+
else output2.push(source_default.bold(content));
|
|
6662
6738
|
continue;
|
|
6663
6739
|
}
|
|
6664
6740
|
if (/^[-*_]{3,}\s*$/.test(line.trim())) {
|
|
@@ -6666,26 +6742,21 @@ function renderMarkdown(text) {
|
|
|
6666
6742
|
continue;
|
|
6667
6743
|
}
|
|
6668
6744
|
if (line.trimStart().startsWith("> ")) {
|
|
6669
|
-
const content = renderInline(line.replace(/^\s*>\s?/, ""));
|
|
6745
|
+
const content = renderInline(line.replace(/^\s*>\s?/, ""), baseDir);
|
|
6670
6746
|
output2.push(source_default.gray("\u2502 ") + source_default.italic(content));
|
|
6671
6747
|
continue;
|
|
6672
6748
|
}
|
|
6673
6749
|
const ulMatch = line.match(/^(\s*)[*+-]\s+(.+)$/);
|
|
6674
6750
|
if (ulMatch) {
|
|
6675
|
-
|
|
6676
|
-
const content = renderInline(ulMatch[2]);
|
|
6677
|
-
output2.push(`${indent}${source_default.gray("\u2022")} ${content}`);
|
|
6751
|
+
output2.push(`${ulMatch[1]}${source_default.gray("\u2022")} ${renderInline(ulMatch[2], baseDir)}`);
|
|
6678
6752
|
continue;
|
|
6679
6753
|
}
|
|
6680
6754
|
const olMatch = line.match(/^(\s*)(\d+)[.)]\s+(.+)$/);
|
|
6681
6755
|
if (olMatch) {
|
|
6682
|
-
|
|
6683
|
-
const num = olMatch[2];
|
|
6684
|
-
const content = renderInline(olMatch[3]);
|
|
6685
|
-
output2.push(`${indent}${source_default.gray(num + ".")} ${content}`);
|
|
6756
|
+
output2.push(`${olMatch[1]}${source_default.gray(olMatch[2] + ".")} ${renderInline(olMatch[3], baseDir)}`);
|
|
6686
6757
|
continue;
|
|
6687
6758
|
}
|
|
6688
|
-
output2.push(renderInline(line));
|
|
6759
|
+
output2.push(renderInline(line, baseDir));
|
|
6689
6760
|
}
|
|
6690
6761
|
if (inCodeBlock && codeBlockLines.length > 0) {
|
|
6691
6762
|
output2.push(source_default.gray("\u250C" + "\u2500".repeat(40)));
|
|
@@ -6696,9 +6767,14 @@ function renderMarkdown(text) {
|
|
|
6696
6767
|
}
|
|
6697
6768
|
return output2.join("\n");
|
|
6698
6769
|
}
|
|
6699
|
-
function renderInline(text) {
|
|
6770
|
+
function renderInline(text, baseDir) {
|
|
6700
6771
|
let result = text;
|
|
6701
|
-
result = result.replace(/`([^`]+)`/g, (_, code) =>
|
|
6772
|
+
result = result.replace(/`([^`]+)`/g, (_, code) => {
|
|
6773
|
+
if (looksLikeFilePath(code)) {
|
|
6774
|
+
return fileLink(source_default.cyan.underline(code), code, baseDir);
|
|
6775
|
+
}
|
|
6776
|
+
return source_default.cyan(code);
|
|
6777
|
+
});
|
|
6702
6778
|
result = result.replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => source_default.bold.italic(t));
|
|
6703
6779
|
result = result.replace(/___(.+?)___/g, (_, t) => source_default.bold.italic(t));
|
|
6704
6780
|
result = result.replace(/\*\*(.+?)\*\*/g, (_, t) => source_default.bold(t));
|
|
@@ -6710,6 +6786,12 @@ function renderInline(text) {
|
|
|
6710
6786
|
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
6711
6787
|
(_, label, url) => source_default.blue(label) + source_default.gray.dim(` (${url})`)
|
|
6712
6788
|
);
|
|
6789
|
+
result = result.replace(BARE_PATH_RE, (match) => {
|
|
6790
|
+
if (looksLikeFilePath(match)) {
|
|
6791
|
+
return fileLink(source_default.cyan.underline(match), match, baseDir);
|
|
6792
|
+
}
|
|
6793
|
+
return match;
|
|
6794
|
+
});
|
|
6713
6795
|
return result;
|
|
6714
6796
|
}
|
|
6715
6797
|
|
|
@@ -6738,8 +6820,8 @@ function UserMessage({ text }) {
|
|
|
6738
6820
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { children: text }) })
|
|
6739
6821
|
] });
|
|
6740
6822
|
}
|
|
6741
|
-
function AgentMessage({ text }) {
|
|
6742
|
-
const rendered = renderMarkdown(text);
|
|
6823
|
+
function AgentMessage({ text, workspaceDir }) {
|
|
6824
|
+
const rendered = renderMarkdown(text, { baseDir: workspaceDir });
|
|
6743
6825
|
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginBottom: 1, children: [
|
|
6744
6826
|
/* @__PURE__ */ jsxs3(Box4, { children: [
|
|
6745
6827
|
/* @__PURE__ */ jsxs3(Text4, { color: "green", bold: true, children: [
|
|
@@ -7078,12 +7160,14 @@ function App({
|
|
|
7078
7160
|
const [cursorToEnd, setCursorToEnd] = useState4(0);
|
|
7079
7161
|
const [screen, setScreen] = useState4("main");
|
|
7080
7162
|
const [resumeSessions, setResumeSessions] = useState4([]);
|
|
7163
|
+
const [ctrlCPending, setCtrlCPending] = useState4(false);
|
|
7081
7164
|
const sessionId = useMemo3(() => crypto.randomUUID(), []);
|
|
7082
7165
|
const deferredMessages = useDeferredValue(messages);
|
|
7083
7166
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
7084
7167
|
const activityFrame = useAnimatedFrame(busy);
|
|
7085
7168
|
const [agentQuestion, setAgentQuestion] = useState4(null);
|
|
7086
7169
|
const previewRef = useRef2(null);
|
|
7170
|
+
const ctrlCTimerRef = useRef2(null);
|
|
7087
7171
|
const isHome = deferredMessages.length === 0 && !busy;
|
|
7088
7172
|
const hasWorkspace = workspacePath !== null;
|
|
7089
7173
|
const hasAuth = authStatus === "connected";
|
|
@@ -7136,6 +7220,13 @@ function App({
|
|
|
7136
7220
|
cancelled = true;
|
|
7137
7221
|
};
|
|
7138
7222
|
}, [homeDir]);
|
|
7223
|
+
useEffect2(() => {
|
|
7224
|
+
return () => {
|
|
7225
|
+
if (ctrlCTimerRef.current) {
|
|
7226
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
7227
|
+
}
|
|
7228
|
+
};
|
|
7229
|
+
}, []);
|
|
7139
7230
|
const [selectedSuggestion, setSelectedSuggestion] = useState4(-1);
|
|
7140
7231
|
const atMention = useMemo3(() => extractAtMention(input2), [input2]);
|
|
7141
7232
|
const suggestions = useMemo3(() => {
|
|
@@ -7667,7 +7758,58 @@ ${msg.text}
|
|
|
7667
7758
|
addSystemMessage(`Rejected: ${next.summary}`);
|
|
7668
7759
|
});
|
|
7669
7760
|
}
|
|
7761
|
+
function clearCtrlCPending() {
|
|
7762
|
+
if (ctrlCTimerRef.current) {
|
|
7763
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
7764
|
+
ctrlCTimerRef.current = null;
|
|
7765
|
+
}
|
|
7766
|
+
setCtrlCPending(false);
|
|
7767
|
+
}
|
|
7768
|
+
function armCtrlCExitWindow() {
|
|
7769
|
+
if (ctrlCTimerRef.current) {
|
|
7770
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
7771
|
+
}
|
|
7772
|
+
setCtrlCPending(true);
|
|
7773
|
+
ctrlCTimerRef.current = setTimeout(() => {
|
|
7774
|
+
ctrlCTimerRef.current = null;
|
|
7775
|
+
setCtrlCPending(false);
|
|
7776
|
+
}, 3e3);
|
|
7777
|
+
}
|
|
7778
|
+
function returnToMainScreen() {
|
|
7779
|
+
setScreen("main");
|
|
7780
|
+
setComposerFocused(true);
|
|
7781
|
+
}
|
|
7670
7782
|
useInput4((key, inputKey) => {
|
|
7783
|
+
if (inputKey.ctrl && key === "c") {
|
|
7784
|
+
if (busy) {
|
|
7785
|
+
clearCtrlCPending();
|
|
7786
|
+
if (abortRef.current) {
|
|
7787
|
+
abortRef.current.abort();
|
|
7788
|
+
addSystemMessage("Interrupting agent...");
|
|
7789
|
+
}
|
|
7790
|
+
return;
|
|
7791
|
+
}
|
|
7792
|
+
if (screen !== "main") {
|
|
7793
|
+
clearCtrlCPending();
|
|
7794
|
+
returnToMainScreen();
|
|
7795
|
+
return;
|
|
7796
|
+
}
|
|
7797
|
+
if (planningState.status === "charter-review") {
|
|
7798
|
+
clearCtrlCPending();
|
|
7799
|
+
rejectCharter();
|
|
7800
|
+
return;
|
|
7801
|
+
}
|
|
7802
|
+
if (ctrlCPending) {
|
|
7803
|
+
clearCtrlCPending();
|
|
7804
|
+
app.exit();
|
|
7805
|
+
return;
|
|
7806
|
+
}
|
|
7807
|
+
armCtrlCExitWindow();
|
|
7808
|
+
return;
|
|
7809
|
+
}
|
|
7810
|
+
if (ctrlCPending) {
|
|
7811
|
+
clearCtrlCPending();
|
|
7812
|
+
}
|
|
7671
7813
|
if (inputKey.shift && inputKey.tab) {
|
|
7672
7814
|
setAgentMode((prev) => {
|
|
7673
7815
|
const modes = ["manual-review", "auto-approve", "auto-research"];
|
|
@@ -8066,6 +8208,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8066
8208
|
addSystemMessage("Charter cancelled. Planning reset.");
|
|
8067
8209
|
}
|
|
8068
8210
|
const statusParts = [];
|
|
8211
|
+
if (ctrlCPending) statusParts.push("Press Ctrl+C again to exit.");
|
|
8069
8212
|
if (hasAuth) statusParts.push("connected");
|
|
8070
8213
|
else statusParts.push("no auth");
|
|
8071
8214
|
if (hasWorkspace) statusParts.push(`${workspaceFiles.length} files`);
|
|
@@ -8073,7 +8216,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8073
8216
|
if (skills2.length > 0) statusParts.push(`${skills2.length} skills`);
|
|
8074
8217
|
statusParts.push(agentMode);
|
|
8075
8218
|
if (deferredPendingUpdates.length > 0) statusParts.push(`${deferredPendingUpdates.length} pending`);
|
|
8076
|
-
const statusColor = busy ? "yellow" : !hasAuth ? "red" : deferredPendingUpdates.length > 0 ? "magenta" : "green";
|
|
8219
|
+
const statusColor = busy ? "yellow" : ctrlCPending ? "yellow" : !hasAuth ? "red" : deferredPendingUpdates.length > 0 ? "magenta" : "green";
|
|
8077
8220
|
const configItems = useMemo3(() => [
|
|
8078
8221
|
{
|
|
8079
8222
|
key: "defaults.model",
|
|
@@ -8128,8 +8271,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8128
8271
|
await saveOpenResearchConfig(updated, { homeDir });
|
|
8129
8272
|
}
|
|
8130
8273
|
function handleConfigClose() {
|
|
8131
|
-
|
|
8132
|
-
setComposerFocused(true);
|
|
8274
|
+
returnToMainScreen();
|
|
8133
8275
|
}
|
|
8134
8276
|
if (screen === "resume") {
|
|
8135
8277
|
return /* @__PURE__ */ jsx5(
|
|
@@ -8147,12 +8289,10 @@ ${error.stack}` : String(error)}` }
|
|
|
8147
8289
|
} catch (err) {
|
|
8148
8290
|
addSystemMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8149
8291
|
}
|
|
8150
|
-
|
|
8151
|
-
setComposerFocused(true);
|
|
8292
|
+
returnToMainScreen();
|
|
8152
8293
|
},
|
|
8153
8294
|
onCancel: () => {
|
|
8154
|
-
|
|
8155
|
-
setComposerFocused(true);
|
|
8295
|
+
returnToMainScreen();
|
|
8156
8296
|
}
|
|
8157
8297
|
}
|
|
8158
8298
|
);
|
|
@@ -8184,7 +8324,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8184
8324
|
if (msg.role === "user") {
|
|
8185
8325
|
return /* @__PURE__ */ jsx5(UserMessage, { text: msg.text }, `msg-${idx}`);
|
|
8186
8326
|
}
|
|
8187
|
-
return /* @__PURE__ */ jsx5(AgentMessage, { text: msg.text }, `msg-${idx}`);
|
|
8327
|
+
return /* @__PURE__ */ jsx5(AgentMessage, { text: msg.text, workspaceDir: workspacePath ?? void 0 }, `msg-${idx}`);
|
|
8188
8328
|
}) }),
|
|
8189
8329
|
deferredPendingUpdates.length > 0 && /* @__PURE__ */ jsx5(
|
|
8190
8330
|
PendingUpdateCard,
|
|
@@ -8305,7 +8445,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8305
8445
|
statusParts,
|
|
8306
8446
|
statusColor,
|
|
8307
8447
|
tokenDisplay,
|
|
8308
|
-
workspaceName: hasWorkspace ?
|
|
8448
|
+
workspaceName: hasWorkspace ? path21.basename(workspacePath) : process.cwd(),
|
|
8309
8449
|
mode: agentMode,
|
|
8310
8450
|
planningStatus: planningState.status
|
|
8311
8451
|
}
|
|
@@ -8317,7 +8457,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8317
8457
|
var program = new Command();
|
|
8318
8458
|
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) => {
|
|
8319
8459
|
await ensureOpenResearchConfig();
|
|
8320
|
-
const target = workspacePath ?
|
|
8460
|
+
const target = workspacePath ? path22.resolve(workspacePath) : process.cwd();
|
|
8321
8461
|
const project = await loadWorkspaceProject(target);
|
|
8322
8462
|
const auth2 = await loadStoredAuth();
|
|
8323
8463
|
render(
|
|
@@ -8328,12 +8468,13 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
8328
8468
|
screen: "home",
|
|
8329
8469
|
pendingUpdates: []
|
|
8330
8470
|
}
|
|
8331
|
-
})
|
|
8471
|
+
}),
|
|
8472
|
+
{ exitOnCtrlC: false }
|
|
8332
8473
|
);
|
|
8333
8474
|
});
|
|
8334
8475
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|
|
8335
8476
|
await ensureOpenResearchConfig();
|
|
8336
|
-
const target =
|
|
8477
|
+
const target = path22.resolve(workspacePath ?? process.cwd());
|
|
8337
8478
|
const project = await initWorkspace({ workspaceDir: target });
|
|
8338
8479
|
console.log(`Initialized workspace: ${target}`);
|
|
8339
8480
|
console.log(`Title: ${project.title}`);
|
|
@@ -8402,8 +8543,8 @@ skills.command("create").argument("[name]").description("Scaffold a new user ski
|
|
|
8402
8543
|
});
|
|
8403
8544
|
skills.command("edit").argument("<name>").description("Open a user skill in $EDITOR.").action(async (name) => {
|
|
8404
8545
|
await ensureOpenResearchConfig();
|
|
8405
|
-
const skillDir =
|
|
8406
|
-
openInEditor(
|
|
8546
|
+
const skillDir = path22.join(getOpenResearchSkillsDir(), name);
|
|
8547
|
+
openInEditor(path22.join(skillDir, "SKILL.md"));
|
|
8407
8548
|
const validation = await validateSkillDirectory({ skillDir });
|
|
8408
8549
|
if (!validation.ok) {
|
|
8409
8550
|
console.error(validation.errors.join("\n"));
|
|
@@ -8414,9 +8555,9 @@ skills.command("edit").argument("<name>").description("Open a user skill in $EDI
|
|
|
8414
8555
|
});
|
|
8415
8556
|
skills.command("validate").argument("[nameOrPath]").description("Validate one user skill.").action(async (nameOrPath) => {
|
|
8416
8557
|
await ensureOpenResearchConfig();
|
|
8417
|
-
const skillDir = nameOrPath ?
|
|
8558
|
+
const skillDir = nameOrPath ? path22.isAbsolute(nameOrPath) ? nameOrPath : path22.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
|
|
8418
8559
|
const stat = await import("fs/promises").then(
|
|
8419
|
-
(
|
|
8560
|
+
(fs22) => fs22.stat(skillDir).catch(() => null)
|
|
8420
8561
|
);
|
|
8421
8562
|
if (!stat) {
|
|
8422
8563
|
throw new Error(`Skill path not found: ${skillDir}`);
|
package/package.json
CHANGED