open-research 0.1.22 → 0.1.23

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 +79 -13
  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 React5 from "react";
11
- import path21 from "path";
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.22";
814
+ var PACKAGE_VERSION = "0.1.23";
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 path20 from "path";
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 when mentioning them, e.g. `notes/brief.md` or `experiments/analysis.py`. This makes them clickable in the terminal.",
5417
5418
  "",
5418
5419
  `## Workspace
5419
5420
  Root: ${process.cwd()}
@@ -6616,6 +6617,66 @@ function truncate3(value, max = 96) {
6616
6617
  import { Box as Box4, Text as Text4 } from "ink";
6617
6618
 
6618
6619
  // src/tui/markdown.ts
6620
+ import path20 from "path";
6621
+ import fs21 from "fs";
6622
+ var FILE_EXTENSIONS = /* @__PURE__ */ new Set([
6623
+ ".py",
6624
+ ".ts",
6625
+ ".tsx",
6626
+ ".js",
6627
+ ".jsx",
6628
+ ".r",
6629
+ ".R",
6630
+ ".tex",
6631
+ ".bib",
6632
+ ".md",
6633
+ ".txt",
6634
+ ".json",
6635
+ ".yaml",
6636
+ ".yml",
6637
+ ".toml",
6638
+ ".csv",
6639
+ ".tsv",
6640
+ ".sh",
6641
+ ".bash",
6642
+ ".zsh",
6643
+ ".sql",
6644
+ ".html",
6645
+ ".css",
6646
+ ".xml",
6647
+ ".pdf",
6648
+ ".png",
6649
+ ".jpg",
6650
+ ".svg",
6651
+ ".gif",
6652
+ ".cfg",
6653
+ ".ini",
6654
+ ".env",
6655
+ ".lock",
6656
+ ".log"
6657
+ ]);
6658
+ function looksLikeFilePath(text) {
6659
+ if (text.length < 3 || text.length > 200) return false;
6660
+ if (text.includes(" ") || text.includes("\n")) return false;
6661
+ const ext = path20.extname(text).toLowerCase();
6662
+ if (FILE_EXTENSIONS.has(ext)) return true;
6663
+ if (text.includes("/") && !text.startsWith("http")) return true;
6664
+ return false;
6665
+ }
6666
+ function resolveFilePath(filePath) {
6667
+ if (path20.isAbsolute(filePath)) return filePath;
6668
+ return path20.resolve(process.cwd(), filePath);
6669
+ }
6670
+ function fileLink(displayText, filePath) {
6671
+ const absPath = resolveFilePath(filePath);
6672
+ try {
6673
+ fs21.statSync(absPath);
6674
+ } catch {
6675
+ return displayText;
6676
+ }
6677
+ const uri = `file://${absPath}`;
6678
+ return `\x1B]8;;${uri}\x1B\\${displayText}\x1B]8;;\x1B\\`;
6679
+ }
6619
6680
  function renderMarkdown(text) {
6620
6681
  if (!text || !text.trim()) return text;
6621
6682
  if (!/[*_`#\[\]>~\-]/.test(text) && !text.includes("```")) return text;
@@ -6698,7 +6759,12 @@ function renderMarkdown(text) {
6698
6759
  }
6699
6760
  function renderInline(text) {
6700
6761
  let result = text;
6701
- result = result.replace(/`([^`]+)`/g, (_, code) => source_default.cyan(code));
6762
+ result = result.replace(/`([^`]+)`/g, (_, code) => {
6763
+ if (looksLikeFilePath(code)) {
6764
+ return fileLink(source_default.cyan.underline(code), code);
6765
+ }
6766
+ return source_default.cyan(code);
6767
+ });
6702
6768
  result = result.replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => source_default.bold.italic(t));
6703
6769
  result = result.replace(/___(.+?)___/g, (_, t) => source_default.bold.italic(t));
6704
6770
  result = result.replace(/\*\*(.+?)\*\*/g, (_, t) => source_default.bold(t));
@@ -8305,7 +8371,7 @@ ${error.stack}` : String(error)}` }
8305
8371
  statusParts,
8306
8372
  statusColor,
8307
8373
  tokenDisplay,
8308
- workspaceName: hasWorkspace ? path20.basename(workspacePath) : process.cwd(),
8374
+ workspaceName: hasWorkspace ? path21.basename(workspacePath) : process.cwd(),
8309
8375
  mode: agentMode,
8310
8376
  planningStatus: planningState.status
8311
8377
  }
@@ -8317,7 +8383,7 @@ ${error.stack}` : String(error)}` }
8317
8383
  var program = new Command();
8318
8384
  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
8385
  await ensureOpenResearchConfig();
8320
- const target = workspacePath ? path21.resolve(workspacePath) : process.cwd();
8386
+ const target = workspacePath ? path22.resolve(workspacePath) : process.cwd();
8321
8387
  const project = await loadWorkspaceProject(target);
8322
8388
  const auth2 = await loadStoredAuth();
8323
8389
  render(
@@ -8333,7 +8399,7 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
8333
8399
  });
8334
8400
  program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
8335
8401
  await ensureOpenResearchConfig();
8336
- const target = path21.resolve(workspacePath ?? process.cwd());
8402
+ const target = path22.resolve(workspacePath ?? process.cwd());
8337
8403
  const project = await initWorkspace({ workspaceDir: target });
8338
8404
  console.log(`Initialized workspace: ${target}`);
8339
8405
  console.log(`Title: ${project.title}`);
@@ -8402,8 +8468,8 @@ skills.command("create").argument("[name]").description("Scaffold a new user ski
8402
8468
  });
8403
8469
  skills.command("edit").argument("<name>").description("Open a user skill in $EDITOR.").action(async (name) => {
8404
8470
  await ensureOpenResearchConfig();
8405
- const skillDir = path21.join(getOpenResearchSkillsDir(), name);
8406
- openInEditor(path21.join(skillDir, "SKILL.md"));
8471
+ const skillDir = path22.join(getOpenResearchSkillsDir(), name);
8472
+ openInEditor(path22.join(skillDir, "SKILL.md"));
8407
8473
  const validation = await validateSkillDirectory({ skillDir });
8408
8474
  if (!validation.ok) {
8409
8475
  console.error(validation.errors.join("\n"));
@@ -8414,9 +8480,9 @@ skills.command("edit").argument("<name>").description("Open a user skill in $EDI
8414
8480
  });
8415
8481
  skills.command("validate").argument("[nameOrPath]").description("Validate one user skill.").action(async (nameOrPath) => {
8416
8482
  await ensureOpenResearchConfig();
8417
- const skillDir = nameOrPath ? path21.isAbsolute(nameOrPath) ? nameOrPath : path21.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
8483
+ const skillDir = nameOrPath ? path22.isAbsolute(nameOrPath) ? nameOrPath : path22.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
8418
8484
  const stat = await import("fs/promises").then(
8419
- (fs21) => fs21.stat(skillDir).catch(() => null)
8485
+ (fs22) => fs22.stat(skillDir).catch(() => null)
8420
8486
  );
8421
8487
  if (!stat) {
8422
8488
  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.22",
3
+ "version": "0.1.23",
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",