research-copilot 0.2.9 → 0.2.11

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 (67) hide show
  1. package/README.md +42 -34
  2. package/app/out/main/index.mjs +42 -7
  3. package/app/out/preload/index.js +3 -2
  4. package/app/out/renderer/assets/{MilkdownMarkdownEditor-CK0d0F6d.js → MilkdownMarkdownEditor-BqfydyHs.js} +50 -50
  5. package/app/out/renderer/assets/{arc-CgrgxBD6.js → arc-B102x0uC.js} +1 -1
  6. package/app/out/renderer/assets/{blockDiagram-c4efeb88-BqZGW4Le.js → blockDiagram-c4efeb88-hlEjcPtb.js} +8 -8
  7. package/app/out/renderer/assets/{c4Diagram-c83219d4-gNbl9eSr.js → c4Diagram-c83219d4-Dc1nfavC.js} +3 -3
  8. package/app/out/renderer/assets/{channel-vUNI1iNi.js → channel-ZMdB8bH1.js} +1 -1
  9. package/app/out/renderer/assets/{classDiagram-beda092f-jMkGJ9Ey.js → classDiagram-beda092f-Gbpax7vO.js} +6 -6
  10. package/app/out/renderer/assets/{classDiagram-v2-2358418a-CNuFkLzW.js → classDiagram-v2-2358418a-_KwHXPjs.js} +10 -10
  11. package/app/out/renderer/assets/{clone-rSI1fs-P.js → clone-DDahKPIj.js} +1 -1
  12. package/app/out/renderer/assets/{createText-1719965b-BXIo6gGa.js → createText-1719965b-BNW0X7Oe.js} +2 -2
  13. package/app/out/renderer/assets/{edges-96097737-nhmklBMU.js → edges-96097737-G9l1oUoZ.js} +3 -3
  14. package/app/out/renderer/assets/{erDiagram-0228fc6a-DAEu9LLq.js → erDiagram-0228fc6a-BUs4XtQY.js} +5 -5
  15. package/app/out/renderer/assets/{flowDb-c6c81e3f-BCxc52Bt.js → flowDb-c6c81e3f-CQ-jcycx.js} +1 -1
  16. package/app/out/renderer/assets/{flowDiagram-50d868cf-DAeMm-oV.js → flowDiagram-50d868cf-uu8ab--w.js} +12 -12
  17. package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-B3DiSW7H.js → flowDiagram-v2-4f6560a1-CAw9BkoT.js} +12 -12
  18. package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-C3U45hIj.js → flowchart-elk-definition-6af322e1-BjQ21EHx.js} +6 -6
  19. package/app/out/renderer/assets/{ganttDiagram-a2739b55-DH_BJl1v.js → ganttDiagram-a2739b55-CP8oCEhK.js} +3 -3
  20. package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-BQYI6jwt.js → gitGraphDiagram-82fe8481-BwBuEj3Z.js} +2 -2
  21. package/app/out/renderer/assets/{graph-Cbmv2S9S.js → graph-Cm7VMO24.js} +1 -1
  22. package/app/out/renderer/assets/{index-CdhMP7aL.js → index-21ZazB27.js} +3 -3
  23. package/app/out/renderer/assets/{index-5325376f-tk-JBjUy.js → index-5325376f-rxU_OBcM.js} +6 -6
  24. package/app/out/renderer/assets/{index-DCdUaSNI.js → index-B0bfGE4l.js} +3 -3
  25. package/app/out/renderer/assets/{index-Dk6CqgIG.js → index-B86Rm5VH.js} +5 -5
  26. package/app/out/renderer/assets/{index-DU4yTtXH.js → index-BOSzW1Fp.js} +3 -3
  27. package/app/out/renderer/assets/{index-HX-NQu3g.js → index-BireTC8B.js} +6 -6
  28. package/app/out/renderer/assets/{index-ByH1hCUC.js → index-BurA4U4Q.js} +4 -4
  29. package/app/out/renderer/assets/{index-DcOi0itd.js → index-C90yL_Oq.js} +159 -70
  30. package/app/out/renderer/assets/{index-CqAzD5Mv.js → index-CXW3LNrw.js} +6 -6
  31. package/app/out/renderer/assets/{index-Do8kanBG.js → index-CYcmNTWS.js} +1 -1
  32. package/app/out/renderer/assets/{index-BTNmK-qR.js → index-CZmZWnTr.js} +3 -3
  33. package/app/out/renderer/assets/{index-hDvDO954.js → index-CdJBtB9B.js} +6 -6
  34. package/app/out/renderer/assets/{index-QjeQ3sgb.js → index-CmuzUeEb.js} +3 -3
  35. package/app/out/renderer/assets/{index-C4WNjCL0.js → index-CnSaLake.js} +6 -6
  36. package/app/out/renderer/assets/{index-DbWCHQ2E.js → index-Cnl3rlb4.js} +3 -3
  37. package/app/out/renderer/assets/{index-BaHR_2Nj.js → index-D075LvBi.js} +3 -3
  38. package/app/out/renderer/assets/{index-xqpIz9Nc.js → index-DQ1LKaqr.js} +6 -6
  39. package/app/out/renderer/assets/{index--rks7CK0.js → index-DnIy5Txo.js} +3 -3
  40. package/app/out/renderer/assets/{index-DK2BzNnx.js → index-DwyuGyq2.js} +3 -3
  41. package/app/out/renderer/assets/{index-BgoqHomD.js → index-JxH0rooB.js} +6 -6
  42. package/app/out/renderer/assets/{index-BdSZkB2P.js → index-PcwO-UQr.js} +4 -4
  43. package/app/out/renderer/assets/{index-B05MKQl-.js → index-UvRVROtt.js} +3 -3
  44. package/app/out/renderer/assets/{index-Bg6-UTvh.js → index-YHTq32NV.js} +3 -3
  45. package/app/out/renderer/assets/{index-LbAr_1fx.css → index-lAZsmnj1.css} +26 -2
  46. package/app/out/renderer/assets/{index-BkmP_G4w.js → index-qYYoWrK0.js} +3 -3
  47. package/app/out/renderer/assets/{infoDiagram-8eee0895-B7stNUSw.js → infoDiagram-8eee0895-DX3y3-A9.js} +2 -2
  48. package/app/out/renderer/assets/{journeyDiagram-c64418c1-BmjjCYfG.js → journeyDiagram-c64418c1-CWFt3XGT.js} +4 -4
  49. package/app/out/renderer/assets/{layout-BwUXWB3n.js → layout-BlEAfCmy.js} +2 -2
  50. package/app/out/renderer/assets/{line-DAwxPIOb.js → line-C8wQDOie.js} +1 -1
  51. package/app/out/renderer/assets/{linear-DF3tF_pi.js → linear-B-vozVTM.js} +1 -1
  52. package/app/out/renderer/assets/{mindmap-definition-8da855dc-Dcm6UXzX.js → mindmap-definition-8da855dc-BCWxRP64.js} +3 -3
  53. package/app/out/renderer/assets/{pieDiagram-a8764435-DkGcoK7i.js → pieDiagram-a8764435-CjTt_TYd.js} +3 -3
  54. package/app/out/renderer/assets/{quadrantDiagram-1e28029f-C1Q8r814.js → quadrantDiagram-1e28029f-D1Ke9L8a.js} +3 -3
  55. package/app/out/renderer/assets/{requirementDiagram-08caed73-C83u7Zho.js → requirementDiagram-08caed73-qZ5fBq-x.js} +5 -5
  56. package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-CmjgGu4H.js → sankeyDiagram-a04cb91d-B-KtJYmc.js} +2 -2
  57. package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-B0tN0kuE.js → sequenceDiagram-c5b8d532-BjqWnQP_.js} +3 -3
  58. package/app/out/renderer/assets/{stateDiagram-1ecb1508-CvChhiL2.js → stateDiagram-1ecb1508-DQo_1-ne.js} +6 -6
  59. package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-DuV4iLKk.js → stateDiagram-v2-c2b004d7-BNb4d-sS.js} +10 -10
  60. package/app/out/renderer/assets/{styles-b4e223ce-CYC1lyng.js → styles-b4e223ce-pjL5kdCz.js} +1 -1
  61. package/app/out/renderer/assets/{styles-ca3715f6-wbpEm70M.js → styles-ca3715f6-CtyHB9Sz.js} +1 -1
  62. package/app/out/renderer/assets/{styles-d45a18b0-dtPSe0gc.js → styles-d45a18b0-r6zLUSmM.js} +4 -4
  63. package/app/out/renderer/assets/{svgDrawCommon-b86b1483-DeFjfiKP.js → svgDrawCommon-b86b1483-CbHYm_eu.js} +1 -1
  64. package/app/out/renderer/assets/{timeline-definition-faaaa080-WkpCNoL6.js → timeline-definition-faaaa080-DvoW_Frb.js} +3 -3
  65. package/app/out/renderer/assets/{xychartDiagram-f5964ef8-DhjmJVco.js → xychartDiagram-f5964ef8-C-G_0ZnR.js} +5 -5
  66. package/app/out/renderer/index.html +2 -2
  67. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Research Copilot
2
2
 
3
- An AI-powered desktop research assistant for scientists and academics. Literature search, data analysis, academic writing, and project management — all in one place.
3
+ An AI-powered desktop research assistant for scientists and academics. Literature search, data analysis, academic writing, cross-project paper memory, and project management — powered by your **ChatGPT Pro / Claude Max subscription** (or an API key), all in one desktop app.
4
4
 
5
5
  Built on [pi-mono](https://github.com/badlogic/pi-mono) (agent runtime) + Electron + React.
6
6
 
@@ -8,36 +8,42 @@ Built on [pi-mono](https://github.com/badlogic/pi-mono) (agent runtime) + Electr
8
8
 
9
9
  ---
10
10
 
11
- ## API Keys Setup (READ THIS FIRST)
11
+ ## Signing in (READ THIS FIRST)
12
12
 
13
- Research Copilot requires API keys to function. The easiest way is to **enter them directly in the app** on first launch you'll see a setup screen. Keys are saved to `~/.research-copilot/config.json`.
13
+ Research Copilot supports three auth methods and automatically prefers the cheapest working one. When multiple are configured, priority is:
14
14
 
15
- Alternatively, add them to your shell profile (`~/.zshrc`, `~/.bashrc`, etc.):
15
+ **ChatGPT subscription Claude subscription OpenAI API key → Anthropic API key**
16
16
 
17
- ```bash
18
- # ===== REQUIRED (at least one) =====
19
- export OPENAI_API_KEY="sk-..." # For OpenAI models (GPT-4o, GPT-5, o3, etc.)
20
- export ANTHROPIC_API_KEY="sk-ant-..." # For Anthropic models (Claude Sonnet, Opus, etc.)
17
+ First-launch model selection follows this order; you can override it any time from the model selector.
21
18
 
22
- # ===== RECOMMENDED =====
23
- export BRAVE_API_KEY="BSA..." # For web search (https://brave.com/search/api/)
24
- export OPENROUTER_API_KEY="sk-or-..." # For AI-generated scientific diagrams (https://openrouter.ai/)
25
- ```
19
+ ### Option 1 — Sign in with a subscription (recommended)
20
+
21
+ The fastest and most cost-predictable path. No API key needed, no metered billing surprises.
22
+
23
+ - **ChatGPT Pro / Plus** — click the model selector, pick a `GPT-5.4 (sub)` entry, sign in via OAuth. Uses the official ChatGPT subscription endpoint.
24
+ - **Claude Pro / Max** — click the model selector, pick a `Claude … (sub)` entry, sign in via OAuth. Uses the official Anthropic subscription endpoint. *(Previously gated behind `ENABLE_CLAUDE_SUB=1`; enabled by default since `0235a3f`.)*
26
25
 
27
- Then reload your shell: `source ~/.zshrc`
26
+ Credentials are stored in the OS keychain via pi-ai's OAuth helper and refreshed automatically.
28
27
 
29
- ### What happens without each key?
28
+ ### Option 2 Bring an API key
29
+
30
+ Open the unified settings panel (**Cmd+.**) and paste a key, or set it in your shell profile:
31
+
32
+ ```bash
33
+ export OPENAI_API_KEY="sk-..." # GPT-5.4, GPT-4o, o-series
34
+ export ANTHROPIC_API_KEY="sk-ant-..." # Claude Opus / Sonnet / Haiku
35
+ ```
30
36
 
31
- | Key | Required? | What it powers | Without it |
32
- |-----|-----------|---------------|------------|
33
- | `OPENAI_API_KEY` | **Yes** (if using OpenAI models) | Core AI agent — all chat, coding, writing, analysis | App cannot start the agent. You'll see an error dialog on first message. |
34
- | `ANTHROPIC_API_KEY` | **Yes** (if using Anthropic models) | Core AI agent (same as above, for Claude models) | Same — agent won't initialize for Claude models. |
35
- | `BRAVE_API_KEY` | Recommended | `web_search` tool — general web search via Brave Search | **Graceful fallback**: web search automatically degrades to arXiv-only (academic papers). No general web results. |
36
- | `OPENROUTER_API_KEY` | Optional | `scientific-schematics` skill — AI-generated diagrams, flowcharts, graphical abstracts | The schematics skill fails when invoked. All other skills (writing, visualization, data analysis) work fine. |
37
+ Keys entered in the UI are saved to `~/.research-copilot/config.json`.
37
38
 
38
- > **Minimum viable setup**: You need **at least one** of `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` to use the app. Everything else enhances the experience but is not strictly required.
39
+ ### Optional supporting keys
39
40
 
40
- > **Semantic Scholar, arXiv, OpenAlex, DBLP**: These academic APIs are used for literature search and **do not require API keys**. They work out of the box.
41
+ | Key | Enhances | Without it |
42
+ |-----|----------|------------|
43
+ | `BRAVE_API_KEY` | `web_search` tool — general web search via Brave | Falls back gracefully to arXiv-only academic search |
44
+ | `OPENROUTER_API_KEY` | `scientific-schematics` skill — AI-generated diagrams | The schematics skill fails when invoked; all other skills still work |
45
+
46
+ > **Semantic Scholar, arXiv, OpenAlex, DBLP**: used for literature search and **do not require API keys**. They work out of the box.
41
47
 
42
48
  ---
43
49
 
@@ -55,8 +61,10 @@ Research Copilot is a **vertical tool built specifically for academic research**
55
61
  | **Academic writing** | Generic document drafting | Venue-specific templates (NeurIPS, ICML, journals), IMRAD structure, LaTeX, citation verification (never hallucinated) |
56
62
  | **Grant writing** | None | Agency-specific guidance (NSF, NIH, DOE, DARPA, NSTC) with compliance checklists |
57
63
  | **Data analysis** | Extracts data from documents | LLM-generated Python scripts with statistical modeling, matplotlib/seaborn visualization, and output manifests |
58
- | **Domain skills** | General capabilities | 13 pluggable research skills (scientific writing, visualization, scholar evaluation, etc.) — extensible via Markdown |
64
+ | **Domain skills** | General capabilities | 14 pluggable research skills (scientific writing, visualization, scholar evaluation, paper revision, slides, etc.) — extensible via Markdown |
65
+ | **Cross-project memory** | Per-conversation only | Background **Paper Wiki** agent that indexes every paper you touch into a local, concept-organized knowledge base shared across all your projects |
59
66
  | **Knowledge persistence** | Not specified | Artifact store, session summaries, cross-session memory, @-mention references |
67
+ | **Auth** | Claude subscription only | **ChatGPT Pro / Claude Max** via OAuth *or* OpenAI / Anthropic API keys — priority-ordered so subscriptions are preferred automatically |
60
68
  | **Openness** | Closed-source commercial product | Open source (MIT) — fully customizable |
61
69
 
62
70
  **In short**: Claude Cowork is like a smart office assistant. Research Copilot is like a lab partner who knows how to search literature, run stats, write papers, and apply for grants.
@@ -73,8 +81,13 @@ Search across **Semantic Scholar**, **arXiv**, **OpenAlex**, and **DBLP** simult
73
81
 
74
82
  ![Literature Management](docs/literature.png)
75
83
 
84
+ ### Cross-Project Paper Wiki
85
+ A background agent that turns every paper you've ever opened into a **local, concept-organized knowledge base** shared across all your projects. Each paper gets a summarized wiki page; recurring concepts get their own pages with back-references to the papers that mention them. The wiki is searchable from any project via `wiki_search` / `wiki_get` / `wiki_coverage` tools, so the AI can recall and cite work from earlier projects without you re-feeding it context.
86
+
87
+ The wiki runs offline and **is disabled by default** — it consumes LLM tokens (roughly 8K–25K input / 2K–4K output per paper), so you opt in from the Settings panel and pick a model you're comfortable paying for. Subscription-backed models are recommended; an "Auto" option follows the system-wide priority (sub before API key). Identity drift across DOI/arXiv/title lookups is reconciled automatically so papers don't get reprocessed.
88
+
76
89
  ### Extensible Skills System
77
- Skills are lazy-loaded knowledge modules that give the AI domain expertise. The app ships with 13 builtin skills covering academic writing (paper-writing, grant proposals, rewrite-humanize), visualization (matplotlib, scientific schematics), data analysis, and more. You can also add your own project-specific skills.
90
+ Skills are lazy-loaded knowledge modules that give the AI domain expertise. The app ships with **14 builtin skills** covering academic writing (paper-writing, paper-revision, research-grants, rewrite-humanize, scientific-writing, scholar-evaluation), visualization (matplotlib, seaborn, scientific-schematics, scientific-visualization, marp-slides), research ideation (brainstorming, creative-thinking), and general coding. You can also add your own project-specific skills as plain Markdown files.
78
91
 
79
92
  ### File Attachments in Chat
80
93
  Attach files directly in the chat input via the paperclip button, drag & drop, or paste. Supported formats:
@@ -96,7 +109,8 @@ Attach files directly in the chat input via the paperclip button, drag & drop, o
96
109
  - **@-mention system** — reference entities inline in chat
97
110
  - **Session continuity** — automatic context compaction and session summaries
98
111
  - **Integrated terminal** — run commands without leaving the app
99
- - **LLM providers** — OpenAI and Anthropic models supported
112
+ - **LLM providers** — OpenAI and Anthropic, via ChatGPT Pro / Claude Max subscription OAuth *or* API keys, with automatic priority selection
113
+ - **Unified settings panel** — `Cmd+.` opens a single pane for models, API keys, research presets, data-analysis timeouts, and the Paper Wiki agent
100
114
 
101
115
  ## Prerequisites
102
116
 
@@ -123,17 +137,11 @@ npm install
123
137
  npm run dev
124
138
  ```
125
139
 
126
- ### API Keys
127
-
128
- On first launch, the app will prompt you to enter your API keys directly in the UI. Keys are saved to `~/.research-copilot/config.json`.
140
+ ### Authentication
129
141
 
130
- You can also set them as environment variables in your shell profile (`~/.zshrc`, `~/.bashrc`):
131
-
132
- ```bash
133
- export ANTHROPIC_API_KEY="sk-ant-..." # or OPENAI_API_KEY="sk-..."
134
- ```
142
+ On first launch, open the model selector (top of the chat pane) and either **sign in** with ChatGPT Pro / Claude Max via OAuth, or paste an `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` into the unified settings panel (`Cmd+.`). Everything else is optional.
135
143
 
136
- See [API Keys Setup](#api-keys-setup-read-this-first) above for the full list.
144
+ See [Signing in](#signing-in-read-this-first) above for the full breakdown and optional supporting keys.
137
145
 
138
146
  ### Build for Production
139
147
 
@@ -222,6 +222,7 @@ function registerConfigHandlers(handleRaw) {
222
222
  }
223
223
  return result;
224
224
  });
225
+ handleRaw("config:pick-preferred-model", () => pickPreferredModelId());
225
226
  handleRaw("config:save-api-key", (keyName, value) => {
226
227
  if (!API_KEY_NAMES.includes(keyName)) {
227
228
  return { success: false, error: `Unknown key: ${keyName}` };
@@ -256,6 +257,13 @@ function hasLlmAuth() {
256
257
  const hasAnthropicSub = !!loadAnthropicSubCredentials();
257
258
  return hasAnthropicKey || hasOpenaiKey || hasCodex || hasAnthropicSub;
258
259
  }
260
+ function pickPreferredModelId() {
261
+ if (loadCodexCredentials()) return "openai-codex:gpt-5.4";
262
+ if (loadAnthropicSubCredentials()) return "anthropic-sub:claude-opus-4-6";
263
+ if ((process.env.OPENAI_API_KEY || "").trim()) return "openai:gpt-5.4";
264
+ if ((process.env.ANTHROPIC_API_KEY || "").trim()) return "anthropic:claude-opus-4-6";
265
+ return null;
266
+ }
259
267
  function registerSettingsHandlers(handleRaw) {
260
268
  handleRaw("config:has-llm-auth", () => hasLlmAuth());
261
269
  handleRaw("settings:load", () => loadSettingsFromConfig());
@@ -879,6 +887,22 @@ const PATHS = {
879
887
  // Local compute runs
880
888
  computeRuns: ".research-pilot/compute-runs"
881
889
  };
890
+ const _warnedReaddirPaths = /* @__PURE__ */ new Set();
891
+ function safeReaddir(dir) {
892
+ try {
893
+ return readdirSync$1(dir);
894
+ } catch (err) {
895
+ const code = err?.code;
896
+ if (code === "EPERM" || code === "ENOENT" || code === "ENOTDIR" || code === "EACCES") {
897
+ if (!_warnedReaddirPaths.has(dir)) {
898
+ _warnedReaddirPaths.add(dir);
899
+ console.warn(`[memory-v2] cannot read artifact dir (${code}): ${dir}`);
900
+ }
901
+ return [];
902
+ }
903
+ throw err;
904
+ }
905
+ }
882
906
  function nowIso() {
883
907
  return (/* @__PURE__ */ new Date()).toISOString();
884
908
  }
@@ -980,7 +1004,7 @@ function migrateLegacyArtifacts(projectPath) {
980
1004
  let removedDataNameField = 0;
981
1005
  for (const { dir } of dirs) {
982
1006
  if (!existsSync(dir)) continue;
983
- for (const file of readdirSync$1(dir)) {
1007
+ for (const file of safeReaddir(dir)) {
984
1008
  if (!file.endsWith(".json")) continue;
985
1009
  const filePath = join(dir, file);
986
1010
  let raw;
@@ -1100,7 +1124,7 @@ function listArtifacts(projectPath, types) {
1100
1124
  for (const { type, dir } of dirs) {
1101
1125
  if (typeSet && !typeSet.has(type)) continue;
1102
1126
  if (!existsSync(dir)) continue;
1103
- for (const file of readdirSync$1(dir)) {
1127
+ for (const file of safeReaddir(dir)) {
1104
1128
  if (!file.endsWith(".json")) continue;
1105
1129
  const artifact = readArtifactFromFile(join(dir, file));
1106
1130
  if (!artifact) continue;
@@ -1113,7 +1137,7 @@ function findArtifactById(projectPath, artifactId) {
1113
1137
  const dirs = resolveArtifactDirs(projectPath);
1114
1138
  for (const { dir } of dirs) {
1115
1139
  if (!existsSync(dir)) continue;
1116
- for (const file of readdirSync$1(dir)) {
1140
+ for (const file of safeReaddir(dir)) {
1117
1141
  if (!file.endsWith(".json")) continue;
1118
1142
  const fullPath = join(dir, file);
1119
1143
  const artifact = readArtifactFromFile(fullPath);
@@ -1222,7 +1246,7 @@ function writeSessionSummary(projectPath, summary) {
1222
1246
  function readLatestSessionSummary(projectPath, sessionId) {
1223
1247
  const dir = join(projectPath, PATHS.sessionSummaries, sessionId);
1224
1248
  if (!existsSync(dir)) return null;
1225
- const files = readdirSync$1(dir).filter((f) => f.endsWith(".json"));
1249
+ const files = safeReaddir(dir).filter((f) => f.endsWith(".json"));
1226
1250
  if (files.length === 0) return null;
1227
1251
  files.sort((a, b) => {
1228
1252
  const na = parseInt(a, 10);
@@ -12838,11 +12862,22 @@ function registerIpcHandlers() {
12838
12862
  registerFolderOpenHandler(sharedHandle, getCtx);
12839
12863
  (async () => {
12840
12864
  const wikiSettings = loadSettingsFromConfig().wikiAgent;
12841
- if (wikiSettings && wikiSettings.model !== "none") {
12865
+ let wikiModel = wikiSettings?.model ?? "none";
12866
+ if (wikiModel === "auto") {
12867
+ const preferred = pickPreferredModelId();
12868
+ if (!preferred) {
12869
+ if (process.env.RESEARCH_COPILOT_DEBUG) {
12870
+ console.log("[wiki-agent] auto mode but no auth configured; skipping startup");
12871
+ }
12872
+ return;
12873
+ }
12874
+ wikiModel = preferred;
12875
+ }
12876
+ if (wikiSettings && wikiModel !== "none") {
12842
12877
  try {
12843
12878
  const { getModel: getPiModel, completeSimple: completeSimple2 } = await import("@mariozechner/pi-ai");
12844
- const wikiAuth = resolveCoordinatorAuth(wikiSettings.model);
12845
- const [rawProvider, modelId] = wikiSettings.model.split(":");
12879
+ const wikiAuth = resolveCoordinatorAuth(wikiModel);
12880
+ const [rawProvider, modelId] = wikiModel.split(":");
12846
12881
  const piProvider = rawProvider === "anthropic-sub" ? "anthropic" : rawProvider;
12847
12882
  const model = getPiModel(piProvider, modelId);
12848
12883
  let resolveApiKey;
@@ -28,11 +28,12 @@ const api = {
28
28
  getOpenAICodexStatus: () => electron.ipcRenderer.invoke("auth:get-openai-codex-status"),
29
29
  openaiCodexLogin: () => electron.ipcRenderer.invoke("auth:openai-codex-login"),
30
30
  openaiCodexLogout: () => electron.ipcRenderer.invoke("auth:openai-codex-logout"),
31
- // Anthropic Subscription (Claude Pro/Max) OAuth
32
- isClaudeSubEnabled: () => process.env.ENABLE_CLAUDE_SUB === "1",
31
+ // Anthropic Subscription (Claude Pro/Max) OAuth — enabled by default
32
+ isClaudeSubEnabled: () => true,
33
33
  getAnthropicSubStatus: () => electron.ipcRenderer.invoke("auth:get-anthropic-sub-status"),
34
34
  anthropicSubLogin: () => electron.ipcRenderer.invoke("auth:anthropic-sub-login"),
35
35
  anthropicSubLogout: () => electron.ipcRenderer.invoke("auth:anthropic-sub-logout"),
36
+ pickPreferredModel: () => electron.ipcRenderer.invoke("config:pick-preferred-model"),
36
37
  getApiKeyStatus: () => electron.ipcRenderer.invoke("config:get-api-key-status"),
37
38
  saveApiKey: (keyName, value) => electron.ipcRenderer.invoke("config:save-api-key", keyName, value),
38
39
  listNotes: () => electron.ipcRenderer.invoke("cmd:list-notes"),