scientify 1.3.0 → 1.4.1

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 (50) hide show
  1. package/README.md +38 -14
  2. package/README.zh.md +38 -15
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +21 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/services/auto-updater.d.ts +15 -0
  7. package/dist/src/services/auto-updater.d.ts.map +1 -0
  8. package/dist/src/services/auto-updater.js +188 -0
  9. package/dist/src/services/auto-updater.js.map +1 -0
  10. package/dist/src/tools/arxiv-download.d.ts +25 -0
  11. package/dist/src/tools/arxiv-download.d.ts.map +1 -0
  12. package/dist/src/tools/arxiv-download.js +179 -0
  13. package/dist/src/tools/arxiv-download.js.map +1 -0
  14. package/dist/src/tools/{arxiv-tool.d.ts → arxiv-search.d.ts} +11 -8
  15. package/dist/src/tools/arxiv-search.d.ts.map +1 -0
  16. package/dist/src/tools/arxiv-search.js +140 -0
  17. package/dist/src/tools/arxiv-search.js.map +1 -0
  18. package/dist/src/tools/github-search-tool.d.ts +5 -1
  19. package/dist/src/tools/github-search-tool.d.ts.map +1 -1
  20. package/dist/src/tools/github-search-tool.js +10 -30
  21. package/dist/src/tools/github-search-tool.js.map +1 -1
  22. package/dist/src/tools/result.d.ts +37 -0
  23. package/dist/src/tools/result.d.ts.map +1 -0
  24. package/dist/src/tools/result.js +39 -0
  25. package/dist/src/tools/result.js.map +1 -0
  26. package/dist/src/tools/workspace.d.ts +32 -0
  27. package/dist/src/tools/workspace.d.ts.map +1 -0
  28. package/dist/src/tools/workspace.js +69 -0
  29. package/dist/src/tools/workspace.js.map +1 -0
  30. package/openclaw.plugin.json +22 -1
  31. package/package.json +13 -2
  32. package/skills/_shared/workspace-spec.md +15 -5
  33. package/skills/idea-generation/SKILL.md +2 -0
  34. package/skills/install-scientify/SKILL.md +17 -17
  35. package/skills/literature-survey/SKILL.md +86 -214
  36. package/skills/research-experiment/SKILL.md +114 -0
  37. package/skills/research-implement/SKILL.md +166 -0
  38. package/skills/research-pipeline/SKILL.md +104 -166
  39. package/skills/research-plan/SKILL.md +121 -0
  40. package/skills/research-review/SKILL.md +110 -0
  41. package/skills/research-survey/SKILL.md +140 -0
  42. package/skills/write-review-paper/SKILL.md +2 -0
  43. package/dist/src/tools/arxiv-tool.d.ts.map +0 -1
  44. package/dist/src/tools/arxiv-tool.js +0 -258
  45. package/dist/src/tools/arxiv-tool.js.map +0 -1
  46. package/skills/research-pipeline/references/prompts/implement.md +0 -135
  47. package/skills/research-pipeline/references/prompts/plan.md +0 -142
  48. package/skills/research-pipeline/references/prompts/review.md +0 -118
  49. package/skills/research-pipeline/references/prompts/survey.md +0 -105
  50. package/skills/research-pipeline/references/workspace-spec.md +0 -5
package/README.md CHANGED
@@ -12,10 +12,14 @@
12
12
 
13
13
  | Skill | Description |
14
14
  |-------|-------------|
15
- | **idea-generation** | Generate innovative research ideas from a topic. Searches arXiv/GitHub, downloads papers, analyzes literature, outputs 5 ideas with citations. |
16
- | **research-pipeline** | End-to-end ML research workflow: idea literature survey plan implement → review → iterate. |
17
- | **literature-review** | Generate structured notes and synthesis from papers you've collected. |
18
- | **arxiv** | Search arXiv.org for papers and download .tex sources. |
15
+ | **research-pipeline** | Orchestrator for end-to-end ML research. Spawns sub-agents for each phase, verifies outputs between steps. |
16
+ | **research-survey** | Deep analysis of downloaded papers: extract formulas, map to code, produce method comparison table. |
17
+ | **research-plan** | Create structured 4-part implementation plan (Dataset/Model/Training/Testing) from survey results. |
18
+ | **research-implement** | Implement ML code from plan, run 2-epoch validation with `uv` venv isolation, verify real results. |
19
+ | **research-review** | Review implementation against plan and survey. Iterates fix-rerun-review up to 3 times. |
20
+ | **research-experiment** | Full training run + ablation experiments + result analysis. Requires review PASS. |
21
+ | **literature-survey** | Comprehensive literature survey: search → filter → download → cluster → report. |
22
+ | **idea-generation** | Generate innovative research ideas from a topic. Searches arXiv/GitHub, downloads papers, outputs 5 ideas. |
19
23
 
20
24
  ### Commands (Direct, no LLM)
21
25
 
@@ -32,7 +36,8 @@
32
36
 
33
37
  | Tool | Description |
34
38
  |------|-------------|
35
- | **arxiv_search** | Search arXiv.org API with keyword search, date filtering, automatic .tex download |
39
+ | **arxiv_search** | Search arXiv.org API for papers. Returns metadata only (title, authors, abstract, arxiv_id). No side effects. |
40
+ | **arxiv_download** | Download arXiv papers by ID. Tries .tex source first, falls back to PDF. Requires absolute `output_dir` path. |
36
41
  | **github_search** | Search GitHub repositories by keyword, filter by language, sort by stars/updated |
37
42
 
38
43
  ---
@@ -214,17 +219,36 @@ Agent: [Reading selected_idea.md and related papers]
214
219
 
215
220
  ```
216
221
  ~/.openclaw/workspace/projects/
217
- ├── .active # Current project ID
218
- ├── nlp-summarization/ # Project A
219
- │ ├── project.json # Metadata
220
- │ ├── task.json # Task definition
221
- │ ├── search_results.md # Search results
222
- │ ├── papers/ # Downloaded papers
223
- ├── repos/ # Cloned repos
224
- └── ideas/ # Generated ideas
222
+ ├── .active # Current project ID
223
+ ├── nlp-summarization/ # Project A
224
+ │ ├── project.json # Metadata
225
+ │ ├── task.json # Task definition
226
+ │ ├── survey/
227
+ ├── search_terms.json # Search terms used
228
+ │ └── report.md # Final survey report
229
+ ├── papers/
230
+ │ │ ├── _downloads/ # Raw downloaded files
231
+ │ │ ├── _meta/ # Paper metadata JSON files
232
+ │ │ │ └── {arxiv_id}.json
233
+ │ │ └── {direction}/ # Clustered papers by research direction
234
+ │ ├── repos/ # Cloned repos
235
+ │ ├── notes/ # /research-survey: per-paper analysis
236
+ │ │ └── paper_{arxiv_id}.md
237
+ │ ├── survey_res.md # /research-survey: method comparison
238
+ │ ├── plan_res.md # /research-plan: implementation plan
239
+ │ ├── project/ # /research-implement: ML code
240
+ │ │ ├── model/
241
+ │ │ ├── data/
242
+ │ │ ├── run.py
243
+ │ │ └── requirements.txt
244
+ │ ├── ml_res.md # /research-implement: execution report
245
+ │ ├── iterations/ # /research-review: judge reports
246
+ │ │ └── judge_v*.md
247
+ │ ├── experiment_res.md # /research-experiment: final results
248
+ │ └── ideas/ # Generated ideas
225
249
  │ ├── idea_1.md
226
250
  │ ├── idea_2.md
227
- │ └── selected_idea.md # Best idea
251
+ │ └── selected_idea.md # Best idea
228
252
  └── another-project/
229
253
  ```
230
254
 
package/README.zh.md CHANGED
@@ -12,10 +12,14 @@
12
12
 
13
13
  | Skill | 描述 |
14
14
  |-------|------|
15
- | **idea-generation** | 从研究主题生成创新想法。自动搜索 arXiv/GitHub、下载论文、分析文献,输出 5 个带引用的研究想法。 |
16
- | **research-pipeline** | 端到端 ML 研究流程:想法 → 文献 → 综述 → 计划 → 实现 → 评审 → 迭代。 |
17
- | **literature-review** | 从已收集的论文生成结构化笔记和综述。 |
18
- | **arxiv** | 搜索 arXiv 论文并下载 .tex 源文件。 |
15
+ | **research-pipeline** | 端到端 ML 研究编排器。通过 sessions_spawn 逐阶段派发子 agent,验证产出后推进。 |
16
+ | **research-survey** | 深度分析已下载论文:提取公式、映射代码、生成核心方法对比表。 |
17
+ | **research-plan** | 从调研结果制定四部分实现计划(数据集/模型/训练/测试)。 |
18
+ | **research-implement** | 按计划实现 ML 代码,使用 `uv` 虚拟环境隔离,2 epoch 验证,确保真实结果。 |
19
+ | **research-review** | 对照计划和调研审查实现代码,最多迭代修复 3 轮。 |
20
+ | **research-experiment** | 完整训练 + 消融实验 + 结果分析。需要 review PASS。 |
21
+ | **literature-survey** | 文献综述:搜索 → 筛选 → 下载 → 聚类 → 报告。 |
22
+ | **idea-generation** | 从研究主题生成创新想法。搜索 arXiv/GitHub、下载论文,输出 5 个研究想法。 |
19
23
 
20
24
  ### Commands (直接执行,不经 LLM)
21
25
 
@@ -32,8 +36,9 @@
32
36
 
33
37
  | Tool | 描述 |
34
38
  |------|------|
35
- | **arxiv_search** | 搜索 arXiv API,支持关键词搜索、日期过滤、自动下载 .tex 源文件 |
36
- | **github_search** | 搜索 GitHub 仓库,支持关键词、语言过滤、按 stars/更新时间排序 |
39
+ | **arxiv_search** | 搜索 arXiv API,返回论文元数据(标题、作者、摘要、ID)。 |
40
+ | **arxiv_download** | ID 下载 arXiv 论文,优先 .tex 源文件,回退到 PDF。内置速率限制。 |
41
+ | **github_search** | 搜索 GitHub 仓库,支持关键词、语言过滤、按 stars/更新时间排序。 |
37
42
 
38
43
  ---
39
44
 
@@ -215,17 +220,35 @@ Agent: [读取 selected_idea.md 和相关论文]
215
220
 
216
221
  ```
217
222
  ~/.openclaw/workspace/projects/
218
- ├── .active # 当前项目 ID
219
- ├── nlp-summarization/ # 项目 A
220
- │ ├── project.json # 元数据
221
- │ ├── task.json # 任务定义
222
- │ ├── search_results.md # 搜索结果
223
- │ ├── papers/ # 下载的论文
224
- ├── repos/ # 克隆的仓库
225
- └── ideas/ # 生成的想法
223
+ ├── .active # 当前项目 ID
224
+ ├── nlp-summarization/ # 项目 A
225
+ │ ├── project.json # 元数据
226
+ │ ├── task.json # 任务定义
227
+ │ ├── survey/ # /literature-survey 产出
228
+ ├── search_terms.json
229
+ │ └── report.md
230
+ ├── papers/ # 下载的论文
231
+ │ │ ├── _downloads/ # 原始文件
232
+ │ │ ├── _meta/ # 元数据 JSON
233
+ │ │ └── {direction}/ # 按方向聚类
234
+ │ ├── repos/ # 克隆的仓库
235
+ │ ├── notes/ # /research-survey: 逐篇深度笔记
236
+ │ │ └── paper_{arxiv_id}.md
237
+ │ ├── survey_res.md # /research-survey: 方法对比
238
+ │ ├── plan_res.md # /research-plan: 实现计划
239
+ │ ├── project/ # /research-implement: ML 代码
240
+ │ │ ├── model/
241
+ │ │ ├── data/
242
+ │ │ ├── run.py
243
+ │ │ └── requirements.txt
244
+ │ ├── ml_res.md # /research-implement: 执行报告
245
+ │ ├── iterations/ # /research-review: 审查报告
246
+ │ │ └── judge_v*.md
247
+ │ ├── experiment_res.md # /research-experiment: 最终结果
248
+ │ └── ideas/ # 生成的想法
226
249
  │ ├── idea_1.md
227
250
  │ ├── idea_2.md
228
- │ └── selected_idea.md # 最佳想法
251
+ │ └── selected_idea.md # 最佳想法
229
252
  └── another-project/
230
253
  ```
231
254
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAYlD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QAuDtD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAiBlD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA0EtD"}
package/dist/index.js CHANGED
@@ -1,10 +1,29 @@
1
1
  import { handleResearchStatus, handlePapers, handleIdeas, handleProjects, handleProjectSwitch, handleProjectDelete, } from "./src/commands.js";
2
- import { createArxivTool } from "./src/tools/arxiv-tool.js";
2
+ import { createArxivSearchTool } from "./src/tools/arxiv-search.js";
3
+ import { createArxivDownloadTool } from "./src/tools/arxiv-download.js";
3
4
  import { createGithubSearchTool } from "./src/tools/github-search-tool.js";
5
+ import { createAutoUpdaterService } from "./src/services/auto-updater.js";
6
+ // Default: check every hour
7
+ const UPDATE_CHECK_INTERVAL_MS = 60 * 60 * 1000;
4
8
  export default function register(api) {
5
9
  // Register tools
6
- api.registerTool(createArxivTool());
10
+ api.registerTool(createArxivSearchTool());
11
+ api.registerTool(createArxivDownloadTool());
7
12
  api.registerTool(createGithubSearchTool());
13
+ // Register auto-updater service (silent updates)
14
+ const pluginConfig = api.pluginConfig;
15
+ const autoUpdateEnabled = pluginConfig?.autoUpdate !== false; // enabled by default
16
+ if (autoUpdateEnabled) {
17
+ api.registerService(createAutoUpdaterService({
18
+ packageName: "scientify",
19
+ checkIntervalMs: UPDATE_CHECK_INTERVAL_MS,
20
+ logger: {
21
+ info: (msg) => api.logger.info(msg),
22
+ warn: (msg) => api.logger.warn(msg),
23
+ debug: (msg) => api.logger.debug?.(msg),
24
+ },
25
+ }));
26
+ }
8
27
  // Register chat commands (bypass LLM)
9
28
  api.registerCommand({
10
29
  name: "research-status",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAsB;IACrD,iBAAiB;IACjB,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC,CAAC;IACpC,GAAG,CAAC,YAAY,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAE3C,sCAAsC;IACtC,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,gEAAgE;QAC7E,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,oBAAoB;KAC9B,CAAC,CAAC;IAEH,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,0CAA0C;QACvD,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,YAAY;KACtB,CAAC,CAAC;IAEH,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,wCAAwC;QACrD,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,WAAW;KACrB,CAAC,CAAC;IAEH,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,4BAA4B;QACzC,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,wCAAwC;QACrD,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,mBAAmB;KAC7B,CAAC,CAAC;IAEH,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,oDAAoD;QACjE,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,IAAI,EAAE,yCAAyC;QAC5D,OAAO,EAAE,mBAAmB;KAC7B,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface AutoUpdaterOptions {
2
+ packageName: string;
3
+ checkIntervalMs: number;
4
+ logger: {
5
+ info: (msg: string) => void;
6
+ warn: (msg: string) => void;
7
+ debug?: (msg: string) => void;
8
+ };
9
+ }
10
+ export declare function createAutoUpdaterService(options: AutoUpdaterOptions): {
11
+ id: string;
12
+ start: () => Promise<void>;
13
+ stop: () => void;
14
+ };
15
+ //# sourceMappingURL=auto-updater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-updater.d.ts","sourceRoot":"","sources":["../../../src/services/auto-updater.ts"],"names":[],"mappings":"AAmJA,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC/B,CAAC;CACH;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,kBAAkB;;;;EA4DnE"}
@@ -0,0 +1,188 @@
1
+ import { exec } from "child_process";
2
+ import { readFileSync, existsSync, lstatSync } from "fs";
3
+ import { fileURLToPath } from "url";
4
+ import { dirname, join } from "path";
5
+ /**
6
+ * Get the plugin root directory (where package.json lives).
7
+ */
8
+ function getPluginRoot() {
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ // From dist/src/services/ → go up 3 levels to plugin root
12
+ // Check for package.json at each level to find the correct root
13
+ let root = __dirname;
14
+ for (let i = 0; i < 5; i++) {
15
+ if (existsSync(join(root, "package.json"))) {
16
+ return root;
17
+ }
18
+ root = dirname(root);
19
+ }
20
+ // Fallback: assume dist/src/services structure
21
+ return join(__dirname, "../../..");
22
+ }
23
+ /**
24
+ * Check if running in development mode.
25
+ * Detection methods (no main package dependency):
26
+ * 1. SCIENTIFY_DEV=1 environment variable
27
+ * 2. tsconfig.json exists in plugin root (source checkout)
28
+ * 3. Plugin directory is a symlink (npm link / pnpm link)
29
+ * 4. Version contains "-dev" suffix
30
+ * 5. NODE_ENV=development
31
+ */
32
+ function isDevMode() {
33
+ // 1. Explicit env var
34
+ const scientifyDev = process.env.SCIENTIFY_DEV;
35
+ if (scientifyDev === "1" || scientifyDev === "true") {
36
+ return true;
37
+ }
38
+ // 2. NODE_ENV
39
+ if (process.env.NODE_ENV === "development") {
40
+ return true;
41
+ }
42
+ const pluginRoot = getPluginRoot();
43
+ // 3. tsconfig.json exists (source checkout, not installed from npm)
44
+ if (existsSync(join(pluginRoot, "tsconfig.json"))) {
45
+ return true;
46
+ }
47
+ // 4. Plugin directory is a symlink (npm/pnpm link)
48
+ try {
49
+ if (lstatSync(pluginRoot).isSymbolicLink()) {
50
+ return true;
51
+ }
52
+ }
53
+ catch {
54
+ // ignore
55
+ }
56
+ // 5. Version contains "-dev"
57
+ try {
58
+ const pkg = JSON.parse(readFileSync(join(pluginRoot, "package.json"), "utf-8"));
59
+ if (pkg.version && pkg.version.includes("-dev")) {
60
+ return true;
61
+ }
62
+ }
63
+ catch {
64
+ // ignore
65
+ }
66
+ return false;
67
+ }
68
+ // Get current version from package.json
69
+ function getCurrentVersion() {
70
+ try {
71
+ const packagePath = join(getPluginRoot(), "package.json");
72
+ const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
73
+ return pkg.version;
74
+ }
75
+ catch {
76
+ return "0.0.0";
77
+ }
78
+ }
79
+ // Check npm registry for latest version
80
+ async function getLatestVersion(packageName) {
81
+ return new Promise((resolve) => {
82
+ exec(`npm view ${packageName} version`, { timeout: 10000 }, (error, stdout) => {
83
+ if (error) {
84
+ resolve(null);
85
+ return;
86
+ }
87
+ resolve(stdout.trim());
88
+ });
89
+ });
90
+ }
91
+ // Compare semver versions: returns true if latest > current
92
+ function isNewerVersion(current, latest) {
93
+ const currentParts = current.split(".").map(Number);
94
+ const latestParts = latest.split(".").map(Number);
95
+ for (let i = 0; i < 3; i++) {
96
+ const c = currentParts[i] || 0;
97
+ const l = latestParts[i] || 0;
98
+ if (l > c)
99
+ return true;
100
+ if (l < c)
101
+ return false;
102
+ }
103
+ return false;
104
+ }
105
+ /**
106
+ * Get the OpenClaw extensions directory.
107
+ */
108
+ function getExtensionsDir() {
109
+ const home = process.env.HOME || process.env.USERPROFILE || "";
110
+ return join(home, ".openclaw", "extensions");
111
+ }
112
+ /**
113
+ * Run the update using npm pack + extract approach.
114
+ * This avoids dependency on `openclaw` CLI being in PATH.
115
+ */
116
+ async function runUpdate(packageName, logger) {
117
+ const extensionsDir = getExtensionsDir();
118
+ const targetDir = join(extensionsDir, packageName);
119
+ return new Promise((resolve) => {
120
+ // Use npm pack to download the tarball, then extract
121
+ const cmd = `cd "${extensionsDir}" && npm pack ${packageName} --pack-destination . && tar -xzf ${packageName}-*.tgz && rm -rf "${targetDir}" && mv package "${targetDir}" && rm ${packageName}-*.tgz`;
122
+ exec(cmd, { timeout: 120000 }, (error, stdout, stderr) => {
123
+ if (error) {
124
+ logger.warn(`Scientify auto-update failed: ${stderr || error.message}`);
125
+ resolve(false);
126
+ return;
127
+ }
128
+ logger.info(`Scientify updated. Restart gateway to apply.`);
129
+ resolve(true);
130
+ });
131
+ });
132
+ }
133
+ export function createAutoUpdaterService(options) {
134
+ const { packageName, checkIntervalMs, logger } = options;
135
+ let intervalId = null;
136
+ let isChecking = false;
137
+ const checkAndUpdate = async () => {
138
+ if (isChecking)
139
+ return;
140
+ isChecking = true;
141
+ try {
142
+ const currentVersion = getCurrentVersion();
143
+ const latestVersion = await getLatestVersion(packageName);
144
+ if (!latestVersion) {
145
+ logger.debug?.(`Scientify update check: could not fetch latest version`);
146
+ return;
147
+ }
148
+ if (isNewerVersion(currentVersion, latestVersion)) {
149
+ logger.info(`Scientify update available: ${currentVersion} → ${latestVersion}`);
150
+ await runUpdate(packageName, logger);
151
+ }
152
+ else {
153
+ logger.debug?.(`Scientify is up to date (${currentVersion})`);
154
+ }
155
+ }
156
+ catch (err) {
157
+ logger.warn(`Scientify update check error: ${err}`);
158
+ }
159
+ finally {
160
+ isChecking = false;
161
+ }
162
+ };
163
+ return {
164
+ id: "scientify-auto-updater",
165
+ start: async () => {
166
+ // Skip auto-updates in development mode
167
+ if (isDevMode()) {
168
+ logger.debug?.("Scientify auto-updater skipped (dev mode)");
169
+ return;
170
+ }
171
+ logger.debug?.("Scientify auto-updater service started");
172
+ // Check once on startup (with a small delay to not block gateway start)
173
+ setTimeout(() => {
174
+ checkAndUpdate();
175
+ }, 5000);
176
+ // Then check periodically
177
+ intervalId = setInterval(checkAndUpdate, checkIntervalMs);
178
+ },
179
+ stop: () => {
180
+ if (intervalId) {
181
+ clearInterval(intervalId);
182
+ intervalId = null;
183
+ }
184
+ logger.debug?.("Scientify auto-updater service stopped");
185
+ },
186
+ };
187
+ }
188
+ //# sourceMappingURL=auto-updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-updater.js","sourceRoot":"","sources":["../../../src/services/auto-updater.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export declare const ArxivDownloadSchema: import("@sinclair/typebox").TObject<{
2
+ arxiv_ids: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
3
+ output_dir: import("@sinclair/typebox").TString;
4
+ }>;
5
+ /**
6
+ * arxiv_download: Download papers by arxiv_id. Requires explicit output_dir.
7
+ */
8
+ export declare function createArxivDownloadTool(): {
9
+ label: string;
10
+ name: string;
11
+ description: string;
12
+ parameters: import("@sinclair/typebox").TObject<{
13
+ arxiv_ids: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
14
+ output_dir: import("@sinclair/typebox").TString;
15
+ }>;
16
+ execute: (_toolCallId: string, rawArgs: unknown) => Promise<{
17
+ type: "tool_result";
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ isError?: boolean;
23
+ }>;
24
+ };
25
+ //# sourceMappingURL=arxiv-download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arxiv-download.d.ts","sourceRoot":"","sources":["../../../src/tools/arxiv-download.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,mBAAmB;;;EAO9B,CAAC;AAoIH;;GAEG;AACH,wBAAgB,uBAAuB;;;;;;;;2BAMN,MAAM,WAAW,OAAO;;;;;;;;EA4DxD"}
@@ -0,0 +1,179 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import * as tar from "tar";
5
+ import { Result } from "./result.js";
6
+ // Rate limit: arXiv recommends ~3 seconds between requests
7
+ const RATE_LIMIT_MS = 3000;
8
+ /** Non-blocking delay that yields to event loop */
9
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10
+ export const ArxivDownloadSchema = Type.Object({
11
+ arxiv_ids: Type.Array(Type.String(), {
12
+ description: "List of arXiv IDs to download (e.g. ['2401.12345', '2312.00001']).",
13
+ }),
14
+ output_dir: Type.String({
15
+ description: "Directory to save files. MUST be an absolute path.",
16
+ }),
17
+ });
18
+ function readStringParam(params, key, opts) {
19
+ const value = params[key];
20
+ if (value === undefined || value === null) {
21
+ if (opts?.required) {
22
+ throw new Error(`Missing required parameter: ${key}`);
23
+ }
24
+ return undefined;
25
+ }
26
+ return String(value);
27
+ }
28
+ function readArrayParam(params, key) {
29
+ const value = params[key];
30
+ if (Array.isArray(value))
31
+ return value.map(String);
32
+ if (typeof value === "string") {
33
+ try {
34
+ const parsed = JSON.parse(value);
35
+ if (Array.isArray(parsed))
36
+ return parsed.map(String);
37
+ }
38
+ catch {
39
+ return [value];
40
+ }
41
+ }
42
+ return [];
43
+ }
44
+ async function downloadTexSource(arxivId, outputDir, logger) {
45
+ const log = (msg) => logger?.debug?.(`[arxiv:${arxivId}] ${msg}`);
46
+ const paperDir = path.join(outputDir, arxivId);
47
+ await fs.promises.mkdir(paperDir, { recursive: true });
48
+ const srcUrl = `https://arxiv.org/src/${arxivId}`;
49
+ const tarPath = path.join(paperDir, "source.tar.gz");
50
+ try {
51
+ log(`Fetching source from ${srcUrl}`);
52
+ const response = await fetch(srcUrl);
53
+ if (!response.ok) {
54
+ const reason = `Source download failed: HTTP ${response.status} ${response.statusText}`;
55
+ log(reason);
56
+ const result = await downloadPdf(arxivId, outputDir, logger);
57
+ return { ...result, fallbackReason: reason };
58
+ }
59
+ const buffer = Buffer.from(await response.arrayBuffer());
60
+ log(`Downloaded ${buffer.length} bytes`);
61
+ await fs.promises.writeFile(tarPath, buffer);
62
+ const isTarGz = buffer[0] === 0x1f && buffer[1] === 0x8b;
63
+ log(`Format check: ${isTarGz ? "tar.gz" : "single file"}`);
64
+ if (isTarGz) {
65
+ await tar.x({ file: tarPath, cwd: paperDir });
66
+ await fs.promises.unlink(tarPath);
67
+ const files = await findTexFiles(paperDir);
68
+ log(`Found ${files.length} .tex files: ${files.join(", ")}`);
69
+ if (files.length === 0) {
70
+ const reason = "No .tex files found in source archive";
71
+ log(reason);
72
+ const result = await downloadPdf(arxivId, outputDir, logger);
73
+ return { ...result, fallbackReason: reason };
74
+ }
75
+ return { success: true, format: "tex", path: paperDir, files };
76
+ }
77
+ else {
78
+ const texPath = path.join(paperDir, "main.tex");
79
+ await fs.promises.rename(tarPath, texPath);
80
+ log("Saved as single main.tex file");
81
+ return { success: true, format: "tex", path: paperDir, files: ["main.tex"] };
82
+ }
83
+ }
84
+ catch (error) {
85
+ const reason = `Source extraction error: ${error instanceof Error ? error.message : String(error)}`;
86
+ log(reason);
87
+ const result = await downloadPdf(arxivId, outputDir, logger);
88
+ return { ...result, fallbackReason: reason };
89
+ }
90
+ }
91
+ async function downloadPdf(arxivId, outputDir, logger) {
92
+ const log = (msg) => logger?.debug?.(`[arxiv:${arxivId}] ${msg}`);
93
+ try {
94
+ const pdfUrl = `https://arxiv.org/pdf/${arxivId}.pdf`;
95
+ log(`Downloading PDF: ${pdfUrl}`);
96
+ const response = await fetch(pdfUrl);
97
+ if (!response.ok) {
98
+ log(`PDF download failed: HTTP ${response.status}`);
99
+ return { success: false, format: "pdf", path: "", files: [], error: `PDF download failed: ${response.status}` };
100
+ }
101
+ const pdfPath = path.join(outputDir, `${arxivId}.pdf`);
102
+ const buffer = Buffer.from(await response.arrayBuffer());
103
+ await fs.promises.writeFile(pdfPath, buffer);
104
+ log(`PDF saved: ${pdfPath} (${buffer.length} bytes)`);
105
+ return { success: true, format: "pdf", path: pdfPath, files: [`${arxivId}.pdf`] };
106
+ }
107
+ catch (error) {
108
+ log(`PDF download error: ${error}`);
109
+ return { success: false, format: "pdf", path: "", files: [], error: String(error) };
110
+ }
111
+ }
112
+ async function findTexFiles(dir) {
113
+ const files = [];
114
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
115
+ for (const entry of entries) {
116
+ const fullPath = path.join(dir, entry.name);
117
+ if (entry.isDirectory()) {
118
+ const subFiles = await findTexFiles(fullPath);
119
+ files.push(...subFiles.map((f) => path.join(entry.name, f)));
120
+ }
121
+ else if (entry.name.endsWith(".tex")) {
122
+ files.push(entry.name);
123
+ }
124
+ }
125
+ return files;
126
+ }
127
+ /**
128
+ * arxiv_download: Download papers by arxiv_id. Requires explicit output_dir.
129
+ */
130
+ export function createArxivDownloadTool() {
131
+ return {
132
+ label: "ArXiv Download",
133
+ name: "arxiv_download",
134
+ description: "Download arXiv papers by ID. Downloads .tex source (with PDF fallback). Requires explicit output_dir (absolute path).",
135
+ parameters: ArxivDownloadSchema,
136
+ execute: async (_toolCallId, rawArgs) => {
137
+ const params = rawArgs;
138
+ const arxivIds = readArrayParam(params, "arxiv_ids");
139
+ const outputDir = readStringParam(params, "output_dir", { required: true });
140
+ if (arxivIds.length === 0) {
141
+ return Result.err("invalid_params", "arxiv_ids must be a non-empty array");
142
+ }
143
+ if (!path.isAbsolute(outputDir)) {
144
+ return Result.err("invalid_params", `output_dir must be an absolute path, got: ${outputDir}`);
145
+ }
146
+ await fs.promises.mkdir(outputDir, { recursive: true });
147
+ const logger = { debug: (msg) => console.log(`[arxiv-download] ${msg}`) };
148
+ const downloads = [];
149
+ for (let i = 0; i < arxivIds.length; i++) {
150
+ const arxivId = arxivIds[i];
151
+ // Rate limit: wait before each request (except first)
152
+ if (i > 0) {
153
+ await delay(RATE_LIMIT_MS);
154
+ }
155
+ // Always try .tex first, fallback to PDF automatically
156
+ const result = await downloadTexSource(arxivId, outputDir, logger);
157
+ downloads.push({
158
+ arxiv_id: arxivId,
159
+ success: result.success,
160
+ format: result.format,
161
+ path: result.path,
162
+ files: result.files,
163
+ error: result.error,
164
+ fallback_reason: result.fallbackReason,
165
+ });
166
+ }
167
+ const successful = downloads.filter((d) => d.success).length;
168
+ const failed = downloads.filter((d) => !d.success).length;
169
+ return Result.ok({
170
+ output_dir: outputDir,
171
+ total: arxivIds.length,
172
+ successful,
173
+ failed,
174
+ downloads,
175
+ });
176
+ },
177
+ };
178
+ }
179
+ //# sourceMappingURL=arxiv-download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arxiv-download.js","sourceRoot":"","sources":["../../../src/tools/arxiv-download.ts"],"names":[],"mappings":"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"}