open-research 0.1.23 → 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 +124 -49
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -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
|
}
|
|
@@ -5414,7 +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
|
|
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.",
|
|
5418
5418
|
"",
|
|
5419
5419
|
`## Workspace
|
|
5420
5420
|
Root: ${process.cwd()}
|
|
@@ -6619,6 +6619,7 @@ import { Box as Box4, Text as Text4 } from "ink";
|
|
|
6619
6619
|
// src/tui/markdown.ts
|
|
6620
6620
|
import path20 from "path";
|
|
6621
6621
|
import fs21 from "fs";
|
|
6622
|
+
import { pathToFileURL } from "url";
|
|
6622
6623
|
var FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6623
6624
|
".py",
|
|
6624
6625
|
".ts",
|
|
@@ -6655,31 +6656,49 @@ var FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
6655
6656
|
".lock",
|
|
6656
6657
|
".log"
|
|
6657
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
|
+
}
|
|
6658
6669
|
function looksLikeFilePath(text) {
|
|
6659
|
-
|
|
6660
|
-
if (
|
|
6661
|
-
|
|
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();
|
|
6662
6675
|
if (FILE_EXTENSIONS.has(ext)) return true;
|
|
6663
|
-
if (
|
|
6676
|
+
if (filePath.includes("/") || filePath.includes("\\")) return true;
|
|
6664
6677
|
return false;
|
|
6665
6678
|
}
|
|
6666
|
-
function
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
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);
|
|
6676
6690
|
}
|
|
6677
|
-
|
|
6691
|
+
if (!resolved) return displayText;
|
|
6692
|
+
const uri = pathToFileURL(resolved).href;
|
|
6678
6693
|
return `\x1B]8;;${uri}\x1B\\${displayText}\x1B]8;;\x1B\\`;
|
|
6679
6694
|
}
|
|
6680
|
-
|
|
6695
|
+
var BARE_PATH_RE = /((?:\.{1,2}\/|\/)[^\s`),;\]]+\.[a-zA-Z0-9]{1,6})/g;
|
|
6696
|
+
function renderMarkdown(text, options = {}) {
|
|
6681
6697
|
if (!text || !text.trim()) return text;
|
|
6682
|
-
|
|
6698
|
+
const baseDir = options.baseDir ?? process.cwd();
|
|
6699
|
+
if (!/[*_`#\[\]>~\-]/.test(text) && !text.includes("```") && !BARE_PATH_RE.test(text)) {
|
|
6700
|
+
return text;
|
|
6701
|
+
}
|
|
6683
6702
|
const lines = text.split("\n");
|
|
6684
6703
|
const output2 = [];
|
|
6685
6704
|
let inCodeBlock = false;
|
|
@@ -6712,14 +6731,10 @@ function renderMarkdown(text) {
|
|
|
6712
6731
|
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
6713
6732
|
if (headingMatch) {
|
|
6714
6733
|
const level = headingMatch[1].length;
|
|
6715
|
-
const content = renderInline(headingMatch[2]);
|
|
6716
|
-
if (level === 1)
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
output2.push(source_default.bold.white(content));
|
|
6720
|
-
} else {
|
|
6721
|
-
output2.push(source_default.bold(content));
|
|
6722
|
-
}
|
|
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));
|
|
6723
6738
|
continue;
|
|
6724
6739
|
}
|
|
6725
6740
|
if (/^[-*_]{3,}\s*$/.test(line.trim())) {
|
|
@@ -6727,26 +6742,21 @@ function renderMarkdown(text) {
|
|
|
6727
6742
|
continue;
|
|
6728
6743
|
}
|
|
6729
6744
|
if (line.trimStart().startsWith("> ")) {
|
|
6730
|
-
const content = renderInline(line.replace(/^\s*>\s?/, ""));
|
|
6745
|
+
const content = renderInline(line.replace(/^\s*>\s?/, ""), baseDir);
|
|
6731
6746
|
output2.push(source_default.gray("\u2502 ") + source_default.italic(content));
|
|
6732
6747
|
continue;
|
|
6733
6748
|
}
|
|
6734
6749
|
const ulMatch = line.match(/^(\s*)[*+-]\s+(.+)$/);
|
|
6735
6750
|
if (ulMatch) {
|
|
6736
|
-
|
|
6737
|
-
const content = renderInline(ulMatch[2]);
|
|
6738
|
-
output2.push(`${indent}${source_default.gray("\u2022")} ${content}`);
|
|
6751
|
+
output2.push(`${ulMatch[1]}${source_default.gray("\u2022")} ${renderInline(ulMatch[2], baseDir)}`);
|
|
6739
6752
|
continue;
|
|
6740
6753
|
}
|
|
6741
6754
|
const olMatch = line.match(/^(\s*)(\d+)[.)]\s+(.+)$/);
|
|
6742
6755
|
if (olMatch) {
|
|
6743
|
-
|
|
6744
|
-
const num = olMatch[2];
|
|
6745
|
-
const content = renderInline(olMatch[3]);
|
|
6746
|
-
output2.push(`${indent}${source_default.gray(num + ".")} ${content}`);
|
|
6756
|
+
output2.push(`${olMatch[1]}${source_default.gray(olMatch[2] + ".")} ${renderInline(olMatch[3], baseDir)}`);
|
|
6747
6757
|
continue;
|
|
6748
6758
|
}
|
|
6749
|
-
output2.push(renderInline(line));
|
|
6759
|
+
output2.push(renderInline(line, baseDir));
|
|
6750
6760
|
}
|
|
6751
6761
|
if (inCodeBlock && codeBlockLines.length > 0) {
|
|
6752
6762
|
output2.push(source_default.gray("\u250C" + "\u2500".repeat(40)));
|
|
@@ -6757,11 +6767,11 @@ function renderMarkdown(text) {
|
|
|
6757
6767
|
}
|
|
6758
6768
|
return output2.join("\n");
|
|
6759
6769
|
}
|
|
6760
|
-
function renderInline(text) {
|
|
6770
|
+
function renderInline(text, baseDir) {
|
|
6761
6771
|
let result = text;
|
|
6762
6772
|
result = result.replace(/`([^`]+)`/g, (_, code) => {
|
|
6763
6773
|
if (looksLikeFilePath(code)) {
|
|
6764
|
-
return fileLink(source_default.cyan.underline(code), code);
|
|
6774
|
+
return fileLink(source_default.cyan.underline(code), code, baseDir);
|
|
6765
6775
|
}
|
|
6766
6776
|
return source_default.cyan(code);
|
|
6767
6777
|
});
|
|
@@ -6776,6 +6786,12 @@ function renderInline(text) {
|
|
|
6776
6786
|
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
6777
6787
|
(_, label, url) => source_default.blue(label) + source_default.gray.dim(` (${url})`)
|
|
6778
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
|
+
});
|
|
6779
6795
|
return result;
|
|
6780
6796
|
}
|
|
6781
6797
|
|
|
@@ -6804,8 +6820,8 @@ function UserMessage({ text }) {
|
|
|
6804
6820
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { children: text }) })
|
|
6805
6821
|
] });
|
|
6806
6822
|
}
|
|
6807
|
-
function AgentMessage({ text }) {
|
|
6808
|
-
const rendered = renderMarkdown(text);
|
|
6823
|
+
function AgentMessage({ text, workspaceDir }) {
|
|
6824
|
+
const rendered = renderMarkdown(text, { baseDir: workspaceDir });
|
|
6809
6825
|
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginBottom: 1, children: [
|
|
6810
6826
|
/* @__PURE__ */ jsxs3(Box4, { children: [
|
|
6811
6827
|
/* @__PURE__ */ jsxs3(Text4, { color: "green", bold: true, children: [
|
|
@@ -7144,12 +7160,14 @@ function App({
|
|
|
7144
7160
|
const [cursorToEnd, setCursorToEnd] = useState4(0);
|
|
7145
7161
|
const [screen, setScreen] = useState4("main");
|
|
7146
7162
|
const [resumeSessions, setResumeSessions] = useState4([]);
|
|
7163
|
+
const [ctrlCPending, setCtrlCPending] = useState4(false);
|
|
7147
7164
|
const sessionId = useMemo3(() => crypto.randomUUID(), []);
|
|
7148
7165
|
const deferredMessages = useDeferredValue(messages);
|
|
7149
7166
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
7150
7167
|
const activityFrame = useAnimatedFrame(busy);
|
|
7151
7168
|
const [agentQuestion, setAgentQuestion] = useState4(null);
|
|
7152
7169
|
const previewRef = useRef2(null);
|
|
7170
|
+
const ctrlCTimerRef = useRef2(null);
|
|
7153
7171
|
const isHome = deferredMessages.length === 0 && !busy;
|
|
7154
7172
|
const hasWorkspace = workspacePath !== null;
|
|
7155
7173
|
const hasAuth = authStatus === "connected";
|
|
@@ -7202,6 +7220,13 @@ function App({
|
|
|
7202
7220
|
cancelled = true;
|
|
7203
7221
|
};
|
|
7204
7222
|
}, [homeDir]);
|
|
7223
|
+
useEffect2(() => {
|
|
7224
|
+
return () => {
|
|
7225
|
+
if (ctrlCTimerRef.current) {
|
|
7226
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
7227
|
+
}
|
|
7228
|
+
};
|
|
7229
|
+
}, []);
|
|
7205
7230
|
const [selectedSuggestion, setSelectedSuggestion] = useState4(-1);
|
|
7206
7231
|
const atMention = useMemo3(() => extractAtMention(input2), [input2]);
|
|
7207
7232
|
const suggestions = useMemo3(() => {
|
|
@@ -7733,7 +7758,58 @@ ${msg.text}
|
|
|
7733
7758
|
addSystemMessage(`Rejected: ${next.summary}`);
|
|
7734
7759
|
});
|
|
7735
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
|
+
}
|
|
7736
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
|
+
}
|
|
7737
7813
|
if (inputKey.shift && inputKey.tab) {
|
|
7738
7814
|
setAgentMode((prev) => {
|
|
7739
7815
|
const modes = ["manual-review", "auto-approve", "auto-research"];
|
|
@@ -8132,6 +8208,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8132
8208
|
addSystemMessage("Charter cancelled. Planning reset.");
|
|
8133
8209
|
}
|
|
8134
8210
|
const statusParts = [];
|
|
8211
|
+
if (ctrlCPending) statusParts.push("Press Ctrl+C again to exit.");
|
|
8135
8212
|
if (hasAuth) statusParts.push("connected");
|
|
8136
8213
|
else statusParts.push("no auth");
|
|
8137
8214
|
if (hasWorkspace) statusParts.push(`${workspaceFiles.length} files`);
|
|
@@ -8139,7 +8216,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8139
8216
|
if (skills2.length > 0) statusParts.push(`${skills2.length} skills`);
|
|
8140
8217
|
statusParts.push(agentMode);
|
|
8141
8218
|
if (deferredPendingUpdates.length > 0) statusParts.push(`${deferredPendingUpdates.length} pending`);
|
|
8142
|
-
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";
|
|
8143
8220
|
const configItems = useMemo3(() => [
|
|
8144
8221
|
{
|
|
8145
8222
|
key: "defaults.model",
|
|
@@ -8194,8 +8271,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8194
8271
|
await saveOpenResearchConfig(updated, { homeDir });
|
|
8195
8272
|
}
|
|
8196
8273
|
function handleConfigClose() {
|
|
8197
|
-
|
|
8198
|
-
setComposerFocused(true);
|
|
8274
|
+
returnToMainScreen();
|
|
8199
8275
|
}
|
|
8200
8276
|
if (screen === "resume") {
|
|
8201
8277
|
return /* @__PURE__ */ jsx5(
|
|
@@ -8213,12 +8289,10 @@ ${error.stack}` : String(error)}` }
|
|
|
8213
8289
|
} catch (err) {
|
|
8214
8290
|
addSystemMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8215
8291
|
}
|
|
8216
|
-
|
|
8217
|
-
setComposerFocused(true);
|
|
8292
|
+
returnToMainScreen();
|
|
8218
8293
|
},
|
|
8219
8294
|
onCancel: () => {
|
|
8220
|
-
|
|
8221
|
-
setComposerFocused(true);
|
|
8295
|
+
returnToMainScreen();
|
|
8222
8296
|
}
|
|
8223
8297
|
}
|
|
8224
8298
|
);
|
|
@@ -8250,7 +8324,7 @@ ${error.stack}` : String(error)}` }
|
|
|
8250
8324
|
if (msg.role === "user") {
|
|
8251
8325
|
return /* @__PURE__ */ jsx5(UserMessage, { text: msg.text }, `msg-${idx}`);
|
|
8252
8326
|
}
|
|
8253
|
-
return /* @__PURE__ */ jsx5(AgentMessage, { text: msg.text }, `msg-${idx}`);
|
|
8327
|
+
return /* @__PURE__ */ jsx5(AgentMessage, { text: msg.text, workspaceDir: workspacePath ?? void 0 }, `msg-${idx}`);
|
|
8254
8328
|
}) }),
|
|
8255
8329
|
deferredPendingUpdates.length > 0 && /* @__PURE__ */ jsx5(
|
|
8256
8330
|
PendingUpdateCard,
|
|
@@ -8394,7 +8468,8 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
8394
8468
|
screen: "home",
|
|
8395
8469
|
pendingUpdates: []
|
|
8396
8470
|
}
|
|
8397
|
-
})
|
|
8471
|
+
}),
|
|
8472
|
+
{ exitOnCtrlC: false }
|
|
8398
8473
|
);
|
|
8399
8474
|
});
|
|
8400
8475
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|
package/package.json
CHANGED