research-copilot 0.1.2 → 0.1.3
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/README.md +22 -0
- package/app/out/main/index.mjs +59 -21
- package/bin/cli.mjs +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,28 @@ Then reload your shell: `source ~/.zshrc`
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
+
## How is Research Copilot different from Claude Cowork?
|
|
45
|
+
|
|
46
|
+
[Claude Cowork](https://www.anthropic.com/product/claude-cowork) is Anthropic's general-purpose autonomous agent for knowledge workers — it handles file organization, document drafting, and data extraction across everyday desktop tasks.
|
|
47
|
+
|
|
48
|
+
Research Copilot is a **vertical tool built specifically for academic research**. The two differ in depth, not surface:
|
|
49
|
+
|
|
50
|
+
| | Claude Cowork | Research Copilot |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| **Scope** | Horizontal — any knowledge work | Vertical — academic research lifecycle |
|
|
53
|
+
| **Literature** | No academic search | Multi-source search (Semantic Scholar, arXiv, OpenAlex, DBLP) with relevance scoring, coverage tracking, and citation tracing |
|
|
54
|
+
| **Paper management** | Processes files you already have | Structured artifact system with DOI, bibtex, citeKey, citation counts, and relevance metadata |
|
|
55
|
+
| **Academic writing** | Generic document drafting | Venue-specific templates (NeurIPS, ICML, journals), IMRAD structure, LaTeX, citation verification (never hallucinated) |
|
|
56
|
+
| **Grant writing** | None | Agency-specific guidance (NSF, NIH, DOE, DARPA, NSTC) with compliance checklists |
|
|
57
|
+
| **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 |
|
|
59
|
+
| **Knowledge persistence** | Not specified | Artifact store, session summaries, cross-session memory, @-mention references |
|
|
60
|
+
| **Openness** | Closed-source commercial product | Open source (MIT) — fully customizable |
|
|
61
|
+
|
|
62
|
+
**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.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
44
66
|
## Features
|
|
45
67
|
|
|
46
68
|
### AI Chat with Coding & Writing Tools
|
package/app/out/main/index.mjs
CHANGED
|
@@ -1244,11 +1244,56 @@ function createArtifactSearchTool(projectPath) {
|
|
|
1244
1244
|
}
|
|
1245
1245
|
};
|
|
1246
1246
|
}
|
|
1247
|
+
function createUpdateMemoryTool(projectPath) {
|
|
1248
|
+
return {
|
|
1249
|
+
name: "update-memory",
|
|
1250
|
+
description: 'Write to the "## Agent Memory" section of agent.md — your persistent memory across sessions. Use this to save: user preferences, project context, key decisions, important findings. The content you provide REPLACES the entire Agent Memory section (User Instructions section is preserved automatically). Keep it concise (<5000 chars total). Consolidate and remove outdated entries rather than appending.',
|
|
1251
|
+
parameters: {
|
|
1252
|
+
type: "object",
|
|
1253
|
+
properties: {
|
|
1254
|
+
memory: {
|
|
1255
|
+
type: "string",
|
|
1256
|
+
description: 'The full content for the "## Agent Memory" section. Markdown format.'
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
required: ["memory"]
|
|
1260
|
+
},
|
|
1261
|
+
execute: async (input) => {
|
|
1262
|
+
const args = input;
|
|
1263
|
+
const memory = String(args.memory || "").trim();
|
|
1264
|
+
if (!memory) return toolError("MISSING_PARAMETER", "memory content is required.", {
|
|
1265
|
+
suggestions: ["Provide the content to save in the Agent Memory section."]
|
|
1266
|
+
});
|
|
1267
|
+
const record = findArtifactById(projectPath, AGENT_MD_ID);
|
|
1268
|
+
const currentContent = record?.artifact?.type === "note" ? record.artifact.content || "" : "";
|
|
1269
|
+
const agentMemoryMarker = "## Agent Memory";
|
|
1270
|
+
const markerIdx = currentContent.indexOf(agentMemoryMarker);
|
|
1271
|
+
const userInstructions = markerIdx >= 0 ? currentContent.slice(0, markerIdx).trimEnd() : currentContent.split("\n").filter((l) => !l.startsWith("## Agent Memory")).join("\n").trimEnd();
|
|
1272
|
+
const newContent = `${userInstructions}
|
|
1273
|
+
|
|
1274
|
+
${agentMemoryMarker}
|
|
1275
|
+
|
|
1276
|
+
${memory}
|
|
1277
|
+
`;
|
|
1278
|
+
const updated = updateArtifact(projectPath, AGENT_MD_ID, { content: newContent });
|
|
1279
|
+
if (!updated) {
|
|
1280
|
+
return toolError("UPDATE_FAILED", "Failed to update agent.md.", {
|
|
1281
|
+
suggestions: ["agent.md may not exist. Try opening a project folder first."]
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
return {
|
|
1285
|
+
success: true,
|
|
1286
|
+
data: { message: "Agent memory updated.", charCount: newContent.length }
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1247
1291
|
function createResearchMemoryTools(params) {
|
|
1248
1292
|
return [
|
|
1249
1293
|
createArtifactCreateTool(params.sessionId, params.projectPath),
|
|
1250
1294
|
createArtifactUpdateTool(params.projectPath),
|
|
1251
|
-
createArtifactSearchTool(params.projectPath)
|
|
1295
|
+
createArtifactSearchTool(params.projectPath),
|
|
1296
|
+
createUpdateMemoryTool(params.projectPath)
|
|
1252
1297
|
];
|
|
1253
1298
|
}
|
|
1254
1299
|
const WEB_DEFAULTS = {
|
|
@@ -1696,12 +1741,11 @@ Memory model:
|
|
|
1696
1741
|
- Session context is maintained automatically via periodic summaries.
|
|
1697
1742
|
- For quick-reference info, create a note via artifact-create({ type: "note", ... }).
|
|
1698
1743
|
|
|
1699
|
-
Long-term memory
|
|
1700
|
-
-
|
|
1701
|
-
-
|
|
1702
|
-
-
|
|
1703
|
-
-
|
|
1704
|
-
- Only persist genuinely valuable information that you would need in a future session. Do not save trivial or ephemeral details.
|
|
1744
|
+
Long-term memory:
|
|
1745
|
+
- Use the update-memory tool to persist information across sessions. It writes to the "## Agent Memory" section of agent.md, which is injected into your context every turn.
|
|
1746
|
+
- WHEN to save: user states a preference ("always do X", "I prefer Y"), a key project decision is made, you discover something important about the project that future sessions need.
|
|
1747
|
+
- WHEN NOT to save: routine task results, things already visible in files/git, ephemeral conversation details.
|
|
1748
|
+
- Keep it concise — consolidate and remove outdated entries. It's a living summary, not a log.
|
|
1705
1749
|
|
|
1706
1750
|
Coding tasks:
|
|
1707
1751
|
- For code implementation, follow test-first workflow: write/update test → confirm it fails → implement → confirm it passes.
|
|
@@ -5054,7 +5098,7 @@ async function enrichPaperArtifacts(options) {
|
|
|
5054
5098
|
onProgress?.({ paperId: paper.id, status: "done" });
|
|
5055
5099
|
} catch (err) {
|
|
5056
5100
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
5057
|
-
{
|
|
5101
|
+
if (debug) {
|
|
5058
5102
|
console.error(`[enrich] Error enriching "${paper.title?.slice(0, 60)}":`, err);
|
|
5059
5103
|
}
|
|
5060
5104
|
failed++;
|
|
@@ -5066,7 +5110,7 @@ async function enrichPaperArtifacts(options) {
|
|
|
5066
5110
|
onProgress?.({ paperId: paper.id, status: "failed" });
|
|
5067
5111
|
}
|
|
5068
5112
|
}
|
|
5069
|
-
{
|
|
5113
|
+
if (debug) {
|
|
5070
5114
|
console.log(`[enrich] Done: ${enriched} enriched, ${skipped} skipped, ${failed} failed`);
|
|
5071
5115
|
}
|
|
5072
5116
|
return {
|
|
@@ -5813,7 +5857,7 @@ function initializeProject(path2) {
|
|
|
5813
5857
|
}
|
|
5814
5858
|
ensureAgentMd(path2);
|
|
5815
5859
|
const migration = migrateLegacyArtifacts(path2);
|
|
5816
|
-
if (migration.updatedFiles > 0) {
|
|
5860
|
+
if (migration.updatedFiles > 0 && process.env.RESEARCH_COPILOT_DEBUG) {
|
|
5817
5861
|
console.log(`[ResearchPilot] migrated legacy artifacts: files=${migration.updatedFiles}, literature->paper=${migration.convertedLiteratureType}, data.name removed=${migration.removedDataNameField}`);
|
|
5818
5862
|
}
|
|
5819
5863
|
}
|
|
@@ -5840,7 +5884,7 @@ async function ensureCoordinator(state, win, model, options) {
|
|
|
5840
5884
|
reasoningEffort: state.currentReasoningEffort,
|
|
5841
5885
|
projectPath: state.projectPath,
|
|
5842
5886
|
sessionId: state.sessionId,
|
|
5843
|
-
debug:
|
|
5887
|
+
debug: !!process.env.RESEARCH_COPILOT_DEBUG,
|
|
5844
5888
|
onStream: (chunk) => {
|
|
5845
5889
|
state.realtimeBuffer.appendChunk(chunk);
|
|
5846
5890
|
safeSend(win, "agent:stream-chunk", chunk);
|
|
@@ -6098,23 +6142,17 @@ function registerIpcHandlers() {
|
|
|
6098
6142
|
sessionId: state.sessionId,
|
|
6099
6143
|
projectPath: state.projectPath,
|
|
6100
6144
|
paperIds,
|
|
6101
|
-
debug:
|
|
6145
|
+
debug: !!process.env.RESEARCH_COPILOT_DEBUG,
|
|
6102
6146
|
onProgress: (event) => {
|
|
6103
6147
|
safeSend(win, "enrich:progress", event);
|
|
6104
6148
|
}
|
|
6105
6149
|
});
|
|
6106
6150
|
});
|
|
6107
6151
|
handleWindow("mention:candidates", ({ state }, query, type) => {
|
|
6108
|
-
if (!state.projectPath)
|
|
6109
|
-
console.warn("[mention:candidates] No projectPath set");
|
|
6110
|
-
return [];
|
|
6111
|
-
}
|
|
6152
|
+
if (!state.projectPath) return [];
|
|
6112
6153
|
try {
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
return result;
|
|
6116
|
-
} catch (err) {
|
|
6117
|
-
console.error("[mention:candidates] Error:", err);
|
|
6154
|
+
return getCandidates(state.projectPath, type, query);
|
|
6155
|
+
} catch {
|
|
6118
6156
|
return [];
|
|
6119
6157
|
}
|
|
6120
6158
|
});
|
package/bin/cli.mjs
CHANGED
|
@@ -62,8 +62,11 @@ const nodePath = process.env.NODE_PATH
|
|
|
62
62
|
: pkgNodeModules
|
|
63
63
|
|
|
64
64
|
// Launch Electron with the app directory
|
|
65
|
+
// Suppress Electron's debug output (GPU warnings, CSP notices, etc.) in production.
|
|
66
|
+
// Set ELECTRON_ENABLE_LOGGING=1 to see them.
|
|
67
|
+
const quiet = !process.env.ELECTRON_ENABLE_LOGGING
|
|
65
68
|
const child = spawn(electronPath, [appDir], {
|
|
66
|
-
stdio: ['
|
|
69
|
+
stdio: quiet ? ['ignore', 'ignore', 'ignore'] : 'inherit',
|
|
67
70
|
env: { ...process.env, NODE_PATH: nodePath },
|
|
68
71
|
})
|
|
69
72
|
|
package/package.json
CHANGED