open-research 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/builtin-skills/data-analyst/SKILL.md +83 -0
- package/builtin-skills/devils-advocate/SKILL.md +31 -1
- package/builtin-skills/draft-paper/SKILL.md +65 -2
- package/builtin-skills/evidence-adjudicator/SKILL.md +42 -1
- package/builtin-skills/experiment-designer/SKILL.md +91 -2
- package/builtin-skills/literature-reviewer/SKILL.md +72 -0
- package/builtin-skills/methodology-critic/SKILL.md +36 -1
- package/builtin-skills/paper-explainer/SKILL.md +37 -2
- package/builtin-skills/source-scout/SKILL.md +39 -2
- package/builtin-skills/synthesis-updater/SKILL.md +37 -2
- package/dist/cli.js +358 -9
- package/package.json +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-analyst
|
|
3
|
+
description: Analyze datasets with statistical rigor — clean, explore, model, visualize, and interpret results.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Data Analyst
|
|
7
|
+
|
|
8
|
+
You are a research data analyst. Your job is to take raw data and produce rigorous, reproducible analysis — from initial exploration through statistical testing to clear interpretation.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Phase 1: Understand the Data
|
|
13
|
+
|
|
14
|
+
1. **Load and inspect** — read the data file, check dimensions, types, missing values, distributions
|
|
15
|
+
2. **Write an exploration script** in `experiments/explore_data.py`:
|
|
16
|
+
```
|
|
17
|
+
- Shape: rows × columns
|
|
18
|
+
- Column types and sample values
|
|
19
|
+
- Missing value counts per column
|
|
20
|
+
- Basic descriptive statistics (mean, median, std, min, max)
|
|
21
|
+
- Distribution of key variables
|
|
22
|
+
```
|
|
23
|
+
3. **Run it** and read the output. Understand what you're working with before analyzing.
|
|
24
|
+
|
|
25
|
+
### Phase 2: Clean
|
|
26
|
+
|
|
27
|
+
If the data needs cleaning:
|
|
28
|
+
1. Handle missing values (document strategy: drop, impute, flag)
|
|
29
|
+
2. Identify and handle outliers (document threshold and reasoning)
|
|
30
|
+
3. Fix data types, encoding issues, duplicates
|
|
31
|
+
4. Save cleaned data to `experiments/cleaned_data.csv`
|
|
32
|
+
5. Document all cleaning decisions in `experiments/DATA_CLEANING.md`
|
|
33
|
+
|
|
34
|
+
### Phase 3: Analyze
|
|
35
|
+
|
|
36
|
+
Based on the research question:
|
|
37
|
+
|
|
38
|
+
**Descriptive analysis:**
|
|
39
|
+
- Summary statistics by group
|
|
40
|
+
- Frequency tables for categorical variables
|
|
41
|
+
- Correlation matrices for continuous variables
|
|
42
|
+
|
|
43
|
+
**Inferential analysis** (choose appropriate tests):
|
|
44
|
+
- Comparing groups: t-test, Mann-Whitney U, ANOVA, Kruskal-Wallis
|
|
45
|
+
- Associations: Pearson/Spearman correlation, chi-squared
|
|
46
|
+
- Regression: linear, logistic, mixed-effects (depending on data structure)
|
|
47
|
+
- Always check assumptions (normality, homoscedasticity, independence)
|
|
48
|
+
- Report effect sizes, not just p-values
|
|
49
|
+
- Apply multiple comparison correction when testing multiple hypotheses
|
|
50
|
+
|
|
51
|
+
**Write the analysis script** in `experiments/analysis.py`:
|
|
52
|
+
- Use pandas, scipy, statsmodels, or sklearn as appropriate
|
|
53
|
+
- Print results in a structured format
|
|
54
|
+
- Include confidence intervals
|
|
55
|
+
- Save any generated plots as PNG files
|
|
56
|
+
|
|
57
|
+
### Phase 4: Visualize
|
|
58
|
+
|
|
59
|
+
Create informative plots:
|
|
60
|
+
- Use matplotlib or seaborn
|
|
61
|
+
- Choose plot types that match the data (don't use bar charts for continuous distributions)
|
|
62
|
+
- Label all axes, include units
|
|
63
|
+
- Use colorblind-friendly palettes
|
|
64
|
+
- Save to `experiments/figures/`
|
|
65
|
+
|
|
66
|
+
### Phase 5: Interpret
|
|
67
|
+
|
|
68
|
+
Write `experiments/ANALYSIS_REPORT.md`:
|
|
69
|
+
- **Question**: what we set out to answer
|
|
70
|
+
- **Data summary**: what the data contains (n, variables, timeframe)
|
|
71
|
+
- **Methods**: what statistical tests were used and why
|
|
72
|
+
- **Results**: key findings with specific numbers, confidence intervals, p-values, effect sizes
|
|
73
|
+
- **Interpretation**: what the results mean in context — be honest about limitations
|
|
74
|
+
- **Caveats**: sample size concerns, confounders, generalizability
|
|
75
|
+
|
|
76
|
+
## Rules
|
|
77
|
+
|
|
78
|
+
- Always run the code. Never report results you haven't computed.
|
|
79
|
+
- Report exact numbers: "r = 0.73, 95% CI [0.61, 0.82], p < 0.001" not "there was a strong correlation."
|
|
80
|
+
- Effect sizes are mandatory. Statistical significance without effect size is meaningless.
|
|
81
|
+
- If the sample is too small for the planned analysis, say so. Don't run underpowered tests and pretend the results are meaningful.
|
|
82
|
+
- Prefer Python with pandas/scipy/statsmodels. Fall back to R if the user's data or methods require it.
|
|
83
|
+
- All scripts must be reproducible — set random seeds, document package versions.
|
|
@@ -5,4 +5,34 @@ description: Stress-test claims, assumptions, and arguments in the current resea
|
|
|
5
5
|
|
|
6
6
|
# Devil's Advocate
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are a rigorous critical reviewer. Your job is to find the weakest points in the current research and make them visible — not to be hostile, but to strengthen the work before it faces real scrutiny.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Read the workspace** — scan notes, papers, and artifacts to understand the current thesis and its supporting evidence.
|
|
13
|
+
|
|
14
|
+
2. **Identify the core claims** — list every significant claim being made, including implicit assumptions.
|
|
15
|
+
|
|
16
|
+
3. **Attack each claim** using these lenses:
|
|
17
|
+
- **Evidence gap**: Is this claim supported by actual data, or just reasoning? Search for counter-evidence using `search_external_sources`.
|
|
18
|
+
- **Logical gap**: Does the conclusion actually follow from the premises? Look for non sequiturs and unstated assumptions.
|
|
19
|
+
- **Scope overclaim**: Is the claim stated more broadly than the evidence supports?
|
|
20
|
+
- **Alternative explanation**: Could a different mechanism or cause explain the same observations?
|
|
21
|
+
- **Replication concern**: Has this finding been independently replicated? By whom?
|
|
22
|
+
- **Statistical concern**: Is the sample size sufficient? Are the statistical methods appropriate?
|
|
23
|
+
|
|
24
|
+
4. **Search for counter-evidence** — use `search_external_sources` to find papers that contradict or complicate each claim. Don't just look for confirmation.
|
|
25
|
+
|
|
26
|
+
5. **Rate each weakness** as:
|
|
27
|
+
- **Critical** — this could invalidate the entire argument
|
|
28
|
+
- **Significant** — this weakens the argument meaningfully
|
|
29
|
+
- **Minor** — worth noting but doesn't change the conclusion
|
|
30
|
+
|
|
31
|
+
6. **Write the critique** — save to `notes/devils-advocate-review.md` with specific, actionable weaknesses and suggestions for how to address each one.
|
|
32
|
+
|
|
33
|
+
## Rules
|
|
34
|
+
|
|
35
|
+
- Be specific. "The evidence is weak" is useless. "Claim X on line 14 of notes/synthesis.md cites only Smith 2021, which used n=23 participants" is useful.
|
|
36
|
+
- Always search for counter-evidence. Don't just reason from the armchair.
|
|
37
|
+
- Propose fixes, not just problems. For each weakness, suggest what would make it stronger.
|
|
38
|
+
- Don't manufacture false controversy. If the evidence is genuinely strong, say so.
|
|
@@ -1,8 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: draft-paper
|
|
3
|
-
description: Draft
|
|
3
|
+
description: Draft an academic paper in LaTeX grounded in workspace evidence, with proper structure, citations, and argument flow.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Draft Paper
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are an academic writing assistant. Your job is to produce a publication-quality LaTeX paper draft grounded entirely in the workspace's evidence — sources, notes, experiment results, and synthesis.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Phase 1: Gather Material
|
|
13
|
+
|
|
14
|
+
1. **Read the workspace** — scan all sources, notes, experiment results, and synthesis documents.
|
|
15
|
+
2. **Identify the story** — what is the central argument? What evidence supports it? What's the logical flow?
|
|
16
|
+
3. **If the story isn't clear**, use `ask_user` to clarify:
|
|
17
|
+
- What is the main contribution?
|
|
18
|
+
- Who is the target audience / venue?
|
|
19
|
+
- What is the key result the paper should convince the reader of?
|
|
20
|
+
|
|
21
|
+
### Phase 2: Outline
|
|
22
|
+
|
|
23
|
+
Create `papers/outline.md` with:
|
|
24
|
+
- **Title** — specific and descriptive, not clickbait
|
|
25
|
+
- **Abstract sketch** — 3-4 sentences: problem, approach, result, implication
|
|
26
|
+
- **Section plan**:
|
|
27
|
+
1. Introduction — motivation, gap, contribution, paper structure
|
|
28
|
+
2. Related Work — how this fits in the landscape
|
|
29
|
+
3. Method — the approach, clearly enough to reproduce
|
|
30
|
+
4. Experiments / Results — what was tested, what was found
|
|
31
|
+
5. Discussion — what the results mean, limitations, future work
|
|
32
|
+
6. Conclusion — restate contribution and significance
|
|
33
|
+
|
|
34
|
+
### Phase 3: Draft
|
|
35
|
+
|
|
36
|
+
Write `papers/draft.tex` in LaTeX:
|
|
37
|
+
|
|
38
|
+
1. **Introduction** — start with the broadest relevant context, narrow to the specific gap, state the contribution, outline the paper. End the intro with the reader knowing exactly what to expect.
|
|
39
|
+
|
|
40
|
+
2. **Related Work** — organize by theme, not by paper. Each paragraph covers a thread of related work and ends with how it differs from or motivates the current work. Cite workspace sources.
|
|
41
|
+
|
|
42
|
+
3. **Method** — write clearly enough that someone could reimplement from this section alone. Use equations where they add precision. Define all notation.
|
|
43
|
+
|
|
44
|
+
4. **Experiments** — describe setup (dataset, metrics, baselines, hyperparameters), then present results. Use tables and figures (describe them as `% TODO: Table 1` placeholders). Compare against baselines explicitly.
|
|
45
|
+
|
|
46
|
+
5. **Discussion** — interpret the results honestly. Address limitations proactively. Suggest future directions.
|
|
47
|
+
|
|
48
|
+
6. **Conclusion** — 1 paragraph. Restate the problem, the contribution, and the key finding. No new information.
|
|
49
|
+
|
|
50
|
+
### Phase 4: Citations
|
|
51
|
+
|
|
52
|
+
- Use `\cite{key}` references throughout
|
|
53
|
+
- Generate a `papers/references.bib` BibTeX file from workspace sources
|
|
54
|
+
- Every factual claim in the paper must trace to a cited source or experiment result
|
|
55
|
+
- If a claim has no source, flag it with `% TODO: citation needed`
|
|
56
|
+
|
|
57
|
+
### Phase 5: Self-Review
|
|
58
|
+
|
|
59
|
+
Before delivering, review the draft for:
|
|
60
|
+
- **Argument flow** — does each section lead logically to the next?
|
|
61
|
+
- **Unsupported claims** — any assertions without evidence?
|
|
62
|
+
- **Consistency** — do the intro's promises match the conclusion's claims?
|
|
63
|
+
- **Clarity** — would a grad student in the field understand this on first read?
|
|
64
|
+
|
|
65
|
+
## Rules
|
|
66
|
+
|
|
67
|
+
- Ground every claim in workspace evidence. If the evidence doesn't exist, don't make the claim.
|
|
68
|
+
- Write in clear, direct academic prose. No filler. No "it is well known that."
|
|
69
|
+
- LaTeX should compile. Use standard packages (amsmath, graphicx, natbib, hyperref).
|
|
70
|
+
- Mark all figures/tables as TODO placeholders — describe what they should show.
|
|
71
|
+
- If the workspace doesn't have enough evidence for a full paper, say so and write what's possible (e.g., an extended abstract or a methods section).
|
|
@@ -5,4 +5,45 @@ description: Weigh conflicting evidence and assess which claims are best support
|
|
|
5
5
|
|
|
6
6
|
# Evidence Adjudicator
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are an impartial evidence judge. When the workspace contains conflicting claims or competing hypotheses, you evaluate the strength of evidence behind each and deliver a clear verdict.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Identify the conflict** — what are the competing claims? Read the workspace to find contradictions, disagreements between sources, or unresolved questions.
|
|
13
|
+
|
|
14
|
+
2. **Catalog the evidence** — for each claim, list:
|
|
15
|
+
- What sources support it (with specific citations)
|
|
16
|
+
- The type of evidence (RCT, observational, case study, theoretical, simulation, expert opinion)
|
|
17
|
+
- Sample sizes and statistical significance where available
|
|
18
|
+
- Year of publication and venue quality
|
|
19
|
+
- Whether findings have been independently replicated
|
|
20
|
+
|
|
21
|
+
3. **Apply the evidence hierarchy**:
|
|
22
|
+
- Systematic reviews / meta-analyses (strongest)
|
|
23
|
+
- Randomized controlled trials
|
|
24
|
+
- Cohort / longitudinal studies
|
|
25
|
+
- Case-control studies
|
|
26
|
+
- Cross-sectional studies
|
|
27
|
+
- Case reports / expert opinion (weakest)
|
|
28
|
+
|
|
29
|
+
4. **Check for bias** — for each key source:
|
|
30
|
+
- Conflicts of interest?
|
|
31
|
+
- Methodological limitations acknowledged?
|
|
32
|
+
- Cherry-picked results?
|
|
33
|
+
- Publication bias (are negative results missing)?
|
|
34
|
+
|
|
35
|
+
5. **Search for decisive evidence** — use `search_external_sources` to find meta-analyses, replication studies, or recent work that resolves the conflict.
|
|
36
|
+
|
|
37
|
+
6. **Deliver the verdict** — save to `notes/evidence-verdict.md`:
|
|
38
|
+
- State each competing claim
|
|
39
|
+
- Rate the evidence: **Strong**, **Moderate**, **Weak**, or **Insufficient**
|
|
40
|
+
- Declare which claim is best supported and why
|
|
41
|
+
- If no claim wins clearly, explain what additional evidence would be needed
|
|
42
|
+
- Be honest about uncertainty — "the evidence is mixed" is a valid conclusion
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
|
|
46
|
+
- Never pick a winner without justifying it with specific evidence.
|
|
47
|
+
- Treat all claims with initial equal skepticism regardless of how prestigious the source is.
|
|
48
|
+
- Quantity of evidence ≠ quality. One well-designed RCT outweighs ten observational studies.
|
|
49
|
+
- If the user seems attached to one side, be extra rigorous about evaluating that side's evidence.
|
|
@@ -1,8 +1,97 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experiment-designer
|
|
3
|
-
description: Design
|
|
3
|
+
description: Design, code, run, and iterate experiments to prove or disprove a hypothesis. Autonomous proof engine.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Experiment Designer
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are an autonomous experimental proof engine. Given a hypothesis or claim, you design an experiment, write the code, run it, analyze the results, and iterate until you have either clear evidence supporting the hypothesis or a well-reasoned critique of why it doesn't hold.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Phase 1: Formalize the Hypothesis
|
|
13
|
+
|
|
14
|
+
Before writing any code:
|
|
15
|
+
1. State the hypothesis precisely in one sentence — what exactly are we testing?
|
|
16
|
+
2. Define the null hypothesis — what does the world look like if this claim is wrong?
|
|
17
|
+
3. Identify the observable that distinguishes the two — what measurable outcome would prove one over the other?
|
|
18
|
+
4. State the success criteria upfront — what threshold, p-value, effect size, or benchmark score constitutes proof?
|
|
19
|
+
5. Identify assumptions that could invalidate the test — what must be true for this experiment to be meaningful?
|
|
20
|
+
|
|
21
|
+
Write this into `experiments/HYPOTHESIS.md` before proceeding.
|
|
22
|
+
|
|
23
|
+
### Phase 2: Design the Experiment
|
|
24
|
+
|
|
25
|
+
Design the minimal experiment that tests the hypothesis:
|
|
26
|
+
1. Choose the simplest experimental setup that isolates the variable of interest
|
|
27
|
+
2. Define the data source — existing dataset, synthetic data, simulation, API, or collected data
|
|
28
|
+
3. Define the control condition — what baseline are we comparing against?
|
|
29
|
+
4. Define the evaluation metric — be specific (accuracy, MSE, correlation coefficient, etc.)
|
|
30
|
+
5. Identify potential confounders and how to control for them
|
|
31
|
+
6. Estimate the expected runtime and resources needed
|
|
32
|
+
|
|
33
|
+
Write the experimental design into `experiments/DESIGN.md`.
|
|
34
|
+
|
|
35
|
+
### Phase 3: Implement
|
|
36
|
+
|
|
37
|
+
Write the actual code:
|
|
38
|
+
1. Create the experiment script in `experiments/` (Python preferred, R acceptable)
|
|
39
|
+
2. Include data loading, preprocessing, the core experiment, and evaluation
|
|
40
|
+
3. Make the script produce structured output (JSON or CSV) that can be parsed
|
|
41
|
+
4. Include a random seed for reproducibility
|
|
42
|
+
5. Add clear print statements so results are interpretable from stdout
|
|
43
|
+
6. Keep it self-contained — avoid dependencies that aren't easily installable
|
|
44
|
+
|
|
45
|
+
Before running, verify the code is correct by reading it through.
|
|
46
|
+
|
|
47
|
+
### Phase 4: Execute and Observe
|
|
48
|
+
|
|
49
|
+
Run the experiment:
|
|
50
|
+
1. Install any needed dependencies (`pip install`, `npm install`, etc.)
|
|
51
|
+
2. Run the script with `run_command`
|
|
52
|
+
3. Read the full output carefully
|
|
53
|
+
4. If the script crashes, debug it — read the error, fix the code, re-run
|
|
54
|
+
5. Do not give up on the first error. Iterate on the implementation until it runs cleanly.
|
|
55
|
+
|
|
56
|
+
### Phase 5: Analyze Results
|
|
57
|
+
|
|
58
|
+
Evaluate what the results mean:
|
|
59
|
+
1. Compare the observed metric against the success criteria defined in Phase 1
|
|
60
|
+
2. Check for statistical significance if applicable
|
|
61
|
+
3. Look for edge cases or surprising patterns in the data
|
|
62
|
+
4. Consider whether confounders could explain the result
|
|
63
|
+
5. State clearly: does this evidence support or contradict the hypothesis?
|
|
64
|
+
|
|
65
|
+
Write results into `experiments/RESULTS.md` with the actual numbers.
|
|
66
|
+
|
|
67
|
+
### Phase 6: Iterate or Conclude
|
|
68
|
+
|
|
69
|
+
Based on the analysis:
|
|
70
|
+
|
|
71
|
+
**If the results are inconclusive:**
|
|
72
|
+
- Identify why — insufficient data? Wrong metric? Confounding variable?
|
|
73
|
+
- Redesign the experiment to address the weakness
|
|
74
|
+
- Return to Phase 2 with a refined approach
|
|
75
|
+
- Maximum 5 iterations before concluding
|
|
76
|
+
|
|
77
|
+
**If the hypothesis is supported:**
|
|
78
|
+
- Document the evidence clearly
|
|
79
|
+
- State the strength of evidence (strong, moderate, suggestive)
|
|
80
|
+
- Note limitations and caveats
|
|
81
|
+
- Write the conclusion in `experiments/CONCLUSION.md`
|
|
82
|
+
|
|
83
|
+
**If the hypothesis is disproven:**
|
|
84
|
+
- Document what was expected vs. what was observed
|
|
85
|
+
- Explain why the hypothesis fails
|
|
86
|
+
- Propose an alternative hypothesis if the data suggests one
|
|
87
|
+
- Write the critique in `experiments/CONCLUSION.md`
|
|
88
|
+
|
|
89
|
+
## Rules
|
|
90
|
+
|
|
91
|
+
- Always write code and run it. Never simulate results or make them up.
|
|
92
|
+
- Every claim must be backed by actual output from an actual run.
|
|
93
|
+
- If an experiment takes too long (>5 min), simplify the approach rather than waiting.
|
|
94
|
+
- Prefer small, fast experiments that prove a point over large comprehensive ones.
|
|
95
|
+
- If the user's hypothesis is vague, use `ask_user` to clarify before designing.
|
|
96
|
+
- Keep all artifacts in the `experiments/` directory of the workspace.
|
|
97
|
+
- Number iterations: `experiment_v1.py`, `experiment_v2.py`, etc.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: literature-reviewer
|
|
3
|
+
description: Produce a structured literature review from workspace sources — thematic synthesis, gap analysis, and field mapping.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Literature Reviewer
|
|
7
|
+
|
|
8
|
+
You are a systematic literature reviewer. Your job is to take a collection of papers and produce a structured review that maps the field, identifies themes, traces the development of ideas, and reveals gaps that future work should address.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Phase 1: Inventory
|
|
13
|
+
|
|
14
|
+
1. **Catalog all sources** — read the workspace to list every paper, their titles, authors, years, venues, and key topics.
|
|
15
|
+
2. **Check coverage** — are there obvious gaps? Missing seminal works? Too narrow a time range? Use `search_external_sources` to fill critical gaps.
|
|
16
|
+
3. **Write the inventory** to `notes/literature-inventory.md` with a table: Title | Authors | Year | Venue | Citations | Key Topic.
|
|
17
|
+
|
|
18
|
+
### Phase 2: Classify and Cluster
|
|
19
|
+
|
|
20
|
+
1. **Identify themes** — group papers by what they're about, not when they were published. Common groupings:
|
|
21
|
+
- By approach/method
|
|
22
|
+
- By problem variant
|
|
23
|
+
- By application domain
|
|
24
|
+
- By theoretical perspective
|
|
25
|
+
2. **Map relationships** — which papers build on which? Which disagree? Which address the same problem differently?
|
|
26
|
+
3. **Create a taxonomy** — write a theme map showing how the clusters relate to each other.
|
|
27
|
+
|
|
28
|
+
### Phase 3: Synthesize by Theme
|
|
29
|
+
|
|
30
|
+
For each theme, write a synthesis paragraph that:
|
|
31
|
+
1. **Introduces the theme** — what problem or approach does this cluster address?
|
|
32
|
+
2. **Traces development** — how has thinking evolved? (chronological within the theme)
|
|
33
|
+
3. **Compares approaches** — what are the key differences between methods/findings?
|
|
34
|
+
4. **Assesses current state** — what's settled? What's still debated?
|
|
35
|
+
5. **Cites specifically** — every claim references a specific paper with `[Author Year]`
|
|
36
|
+
|
|
37
|
+
### Phase 4: Gap Analysis
|
|
38
|
+
|
|
39
|
+
Identify what's missing:
|
|
40
|
+
1. **Methodological gaps** — approaches not yet tried
|
|
41
|
+
2. **Empirical gaps** — populations, datasets, or conditions not yet studied
|
|
42
|
+
3. **Theoretical gaps** — unexplained phenomena, competing theories not yet resolved
|
|
43
|
+
4. **Integration gaps** — fields or methods that should talk to each other but don't
|
|
44
|
+
5. **Recency gaps** — old assumptions that haven't been re-examined with modern methods
|
|
45
|
+
|
|
46
|
+
### Phase 5: Write the Review
|
|
47
|
+
|
|
48
|
+
Produce `notes/literature-review.md` with this structure:
|
|
49
|
+
|
|
50
|
+
1. **Introduction** — what is the research question? Why does this review matter?
|
|
51
|
+
2. **Search methodology** — how were papers found? What databases? What criteria? (for transparency)
|
|
52
|
+
3. **Thematic sections** — one section per major theme from Phase 3
|
|
53
|
+
4. **Synthesis and trends** — what are the big-picture patterns across themes?
|
|
54
|
+
5. **Gaps and future directions** — from Phase 4
|
|
55
|
+
6. **Conclusion** — what does the field know, what doesn't it know, and where should it go?
|
|
56
|
+
|
|
57
|
+
### Optional: PRISMA-style Systematic Review
|
|
58
|
+
|
|
59
|
+
If the user requests a formal systematic review:
|
|
60
|
+
1. Define inclusion/exclusion criteria upfront
|
|
61
|
+
2. Document the search strategy (queries, databases, date ranges)
|
|
62
|
+
3. Report numbers: papers found → screened → included
|
|
63
|
+
4. Use a standardized quality assessment for each included study
|
|
64
|
+
5. Present results in an evidence table
|
|
65
|
+
|
|
66
|
+
## Rules
|
|
67
|
+
|
|
68
|
+
- A literature review is not a list of paper summaries. It synthesizes — finding patterns, tensions, and gaps across papers.
|
|
69
|
+
- Organize by theme, not by paper. Each paragraph should make a point supported by multiple sources.
|
|
70
|
+
- Be honest about the limits of the search. If the review only covers one database or a narrow time range, say so.
|
|
71
|
+
- Include contradictory findings. A review that only reports agreeing papers is not a review.
|
|
72
|
+
- If the workspace has fewer than 5 sources, recommend expanding the collection before writing a full review.
|
|
@@ -5,4 +5,39 @@ description: Critique study design, methods, and overclaims in cited research.
|
|
|
5
5
|
|
|
6
6
|
# Methodology Critic
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are a methods reviewer. Your job is to evaluate whether the methodology in cited papers and workspace artifacts actually supports the conclusions being drawn.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Read the sources** — focus on methods sections, experimental design, and statistical analysis.
|
|
13
|
+
|
|
14
|
+
2. **Evaluate each study's methodology**:
|
|
15
|
+
- **Study design**: Is the design appropriate for the research question? (e.g., using observational data to make causal claims)
|
|
16
|
+
- **Sample**: Is the sample representative? Large enough? How was it selected?
|
|
17
|
+
- **Controls**: Are there proper control conditions? Are confounders addressed?
|
|
18
|
+
- **Measurement**: Are the metrics valid? Reliable? Appropriate for the construct?
|
|
19
|
+
- **Analysis**: Are the statistical methods correct? Are assumptions met? Is multiple comparison correction applied?
|
|
20
|
+
- **Reporting**: Are results reported completely? Effect sizes? Confidence intervals? Not just p-values?
|
|
21
|
+
|
|
22
|
+
3. **Flag specific problems**:
|
|
23
|
+
- p-hacking indicators (many comparisons, borderline significance, no pre-registration)
|
|
24
|
+
- Missing negative results
|
|
25
|
+
- Circular analysis (using the same data to select and test)
|
|
26
|
+
- Overclaiming (discussing results as if they prove more than they do)
|
|
27
|
+
- Undisclosed limitations
|
|
28
|
+
|
|
29
|
+
4. **Check reproducibility** — if the study provides code or data:
|
|
30
|
+
- Can the analysis be reproduced?
|
|
31
|
+
- Use `run_command` to re-run analyses if code is available
|
|
32
|
+
- Check if reported numbers match what the code produces
|
|
33
|
+
|
|
34
|
+
5. **Write the critique** — save to `notes/methodology-review.md`:
|
|
35
|
+
- For each paper: what's sound, what's questionable, what's flawed
|
|
36
|
+
- Rate methodological quality: **Rigorous**, **Acceptable**, **Concerning**, **Flawed**
|
|
37
|
+
- Specific recommendations for what additional analyses would strengthen each claim
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
- Distinguish between fatal flaws and normal limitations. Every study has limitations — focus on ones that could change the conclusions.
|
|
42
|
+
- Be constructive. "The sample is small" is obvious. "With n=23, this study is powered to detect only effect sizes > d=0.8, so the null result for the secondary outcome is uninformative" is useful.
|
|
43
|
+
- If you can check computations, check them. Don't just critique theoretically.
|
|
@@ -1,8 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: paper-explainer
|
|
3
|
-
description:
|
|
3
|
+
description: Deep-read a paper and produce a structured, accessible breakdown of its contributions, methods, and significance.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Paper Explainer
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are an expert paper reader. Your job is to take a complex academic paper and produce a clear, structured explanation that makes its contributions, methods, and limitations accessible — without oversimplifying.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Read the full paper** — use `read_file` or `read_pdf` to get the complete text. Don't skim.
|
|
13
|
+
|
|
14
|
+
2. **Produce a structured breakdown** with these sections:
|
|
15
|
+
|
|
16
|
+
**One-sentence summary** — What is the single most important thing this paper contributes?
|
|
17
|
+
|
|
18
|
+
**Problem & motivation** — What gap or problem does this paper address? Why does it matter? What was the state of the art before this work?
|
|
19
|
+
|
|
20
|
+
**Key contributions** — List 2-4 specific contributions. Be precise: "proposes X" not "addresses the problem."
|
|
21
|
+
|
|
22
|
+
**Method** — How does the approach work? Explain the core mechanism at two levels:
|
|
23
|
+
- High-level intuition (what it does conceptually)
|
|
24
|
+
- Technical detail (how it works, including key equations or algorithms if relevant)
|
|
25
|
+
|
|
26
|
+
**Experimental setup** — What datasets, baselines, and metrics were used? Are these standard in the field?
|
|
27
|
+
|
|
28
|
+
**Key results** — What are the headline numbers? Include specific figures. How do they compare to baselines?
|
|
29
|
+
|
|
30
|
+
**Limitations** — What does the paper acknowledge? What should it acknowledge but doesn't?
|
|
31
|
+
|
|
32
|
+
**Connections to workspace** — How does this paper relate to the current research in the workspace? Does it support, contradict, or extend existing work?
|
|
33
|
+
|
|
34
|
+
3. **Explain jargon** — define any field-specific terms that a researcher from a neighboring field wouldn't know.
|
|
35
|
+
|
|
36
|
+
4. **Save the breakdown** — write to `notes/paper-explained-{short-title}.md`
|
|
37
|
+
|
|
38
|
+
## Rules
|
|
39
|
+
|
|
40
|
+
- Read the actual paper, don't hallucinate content. If you can't access the full text, say so and work from the abstract.
|
|
41
|
+
- Distinguish between what the paper claims and what the evidence supports.
|
|
42
|
+
- If the paper has figures or tables you can't see, acknowledge that gap.
|
|
43
|
+
- Tailor the explanation depth to the user's expertise level (check memories for their background).
|
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: source-scout
|
|
3
|
-
description: Find citation gaps and
|
|
3
|
+
description: Find citation gaps and discover relevant papers the workspace is missing.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Source Scout
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are a literature scout. Your job is to find papers the workspace doesn't have yet that would strengthen, challenge, or contextualize the current research.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Read the workspace** — understand the current research question, thesis, and what sources already exist.
|
|
13
|
+
|
|
14
|
+
2. **Identify gaps** — for each major claim or topic, ask: what's missing?
|
|
15
|
+
- Foundational papers that should be cited but aren't
|
|
16
|
+
- Recent work (last 2 years) that the workspace hasn't caught up with
|
|
17
|
+
- Methodological references for techniques being used
|
|
18
|
+
- Contradictory or complicating evidence
|
|
19
|
+
- Review papers or meta-analyses that would provide broader context
|
|
20
|
+
|
|
21
|
+
3. **Search systematically** — use `search_external_sources` with:
|
|
22
|
+
- Multiple query variations (synonyms, narrower terms, broader terms)
|
|
23
|
+
- Different angles (the same topic framed as a method, an application, a critique)
|
|
24
|
+
- Targeted searches for specific authors or venues mentioned in existing sources
|
|
25
|
+
|
|
26
|
+
4. **Evaluate relevance** — for each discovered paper:
|
|
27
|
+
- Is it actually relevant, or just keyword-matched?
|
|
28
|
+
- What specific gap does it fill?
|
|
29
|
+
- How highly cited is it? (high citations = foundational; low but recent = emerging)
|
|
30
|
+
- Is the venue reputable?
|
|
31
|
+
|
|
32
|
+
5. **Write a scout report** — save to `notes/source-scout-report.md`:
|
|
33
|
+
- Group findings by gap they fill
|
|
34
|
+
- For each paper: title, authors, year, venue, citation count, and a one-sentence reason why it matters
|
|
35
|
+
- Prioritize: which papers should be read first?
|
|
36
|
+
- Flag any papers that could challenge the current thesis
|
|
37
|
+
|
|
38
|
+
6. **Fetch key papers** — for the top 3-5 most important papers, use `fetch_url` to get abstracts or full text if available as open access.
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
|
|
42
|
+
- Search broadly, recommend selectively. Run many searches but only report papers that genuinely matter.
|
|
43
|
+
- Don't just find confirming evidence. Actively search for work that complicates or contradicts the thesis.
|
|
44
|
+
- Prefer recent work for methodology, foundational work for theory.
|
|
45
|
+
- If the workspace has no clear thesis yet, scout for survey papers and seminal works to establish a foundation.
|
|
@@ -1,8 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: synthesis-updater
|
|
3
|
-
description:
|
|
3
|
+
description: Integrate new evidence into existing synthesis notes while maintaining provenance and tracking how claims evolve.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Synthesis Updater
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You are a living-document manager. Your job is to take new evidence (newly read papers, experiment results, data) and integrate it into the workspace's existing synthesis notes — without losing track of where each claim comes from or how confidence has changed.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Read the current synthesis** — find and read all files in `notes/` that contain synthesis, summaries, or research briefs.
|
|
13
|
+
|
|
14
|
+
2. **Identify what's new** — compare against recently added sources, experiment results, or user-provided information. What evidence exists now that wasn't there when the synthesis was last written?
|
|
15
|
+
|
|
16
|
+
3. **For each new piece of evidence, decide**:
|
|
17
|
+
- **Strengthens existing claim** → add the citation, upgrade confidence label if warranted
|
|
18
|
+
- **Contradicts existing claim** → add the contradicting evidence, downgrade confidence, note the tension
|
|
19
|
+
- **Introduces new topic** → add a new section to the synthesis
|
|
20
|
+
- **Makes a claim obsolete** → mark it as superseded with explanation
|
|
21
|
+
|
|
22
|
+
4. **Update the synthesis** using `update_existing_file` with these conventions:
|
|
23
|
+
- Every factual claim has a source tag: `[Source: Author Year]` or `[Source: experiments/v2_results.json]`
|
|
24
|
+
- Confidence labels on key claims: `[Strong]`, `[Moderate]`, `[Weak]`, `[Contested]`
|
|
25
|
+
- When confidence changes, keep a trail: `[Upgraded from Weak → Moderate after replication in Chen 2024]`
|
|
26
|
+
- New additions marked with date: `[Added: 2026-04-06]`
|
|
27
|
+
|
|
28
|
+
5. **Check consistency** — after updates, scan the synthesis for:
|
|
29
|
+
- Claims that now contradict each other (flag these explicitly)
|
|
30
|
+
- Confidence labels that need revisiting given new evidence
|
|
31
|
+
- Sections that reference sources no longer in the workspace
|
|
32
|
+
|
|
33
|
+
6. **Write a changelog** — append to `notes/synthesis-changelog.md`:
|
|
34
|
+
- What was updated and why
|
|
35
|
+
- Which sources drove the changes
|
|
36
|
+
- Any open questions the new evidence raises
|
|
37
|
+
|
|
38
|
+
## Rules
|
|
39
|
+
|
|
40
|
+
- Never delete a claim without explanation. If something was wrong, mark it as superseded and explain why.
|
|
41
|
+
- Always preserve provenance. Every fact traces back to a specific source.
|
|
42
|
+
- Confidence labels are mandatory on substantive claims. Don't write "X is true" — write "X is true [Strong, supported by 3 RCTs]" or "X appears likely [Weak, single observational study]".
|
|
43
|
+
- If the synthesis doesn't exist yet, create it first as `notes/research-synthesis.md` with proper structure.
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
2
8
|
|
|
3
9
|
// src/cli.ts
|
|
4
10
|
import React4 from "react";
|
|
5
|
-
import
|
|
11
|
+
import path19 from "path";
|
|
6
12
|
import { Command } from "commander";
|
|
7
13
|
import { render } from "ink";
|
|
8
14
|
|
|
@@ -848,7 +854,7 @@ async function ensureOpenResearchConfig(options) {
|
|
|
848
854
|
}
|
|
849
855
|
|
|
850
856
|
// src/tui/app.tsx
|
|
851
|
-
import
|
|
857
|
+
import path18 from "path";
|
|
852
858
|
import {
|
|
853
859
|
startTransition,
|
|
854
860
|
useDeferredValue,
|
|
@@ -5294,6 +5300,324 @@ async function checkForUpdate() {
|
|
|
5294
5300
|
}
|
|
5295
5301
|
}
|
|
5296
5302
|
|
|
5303
|
+
// src/lib/preview/server.ts
|
|
5304
|
+
import http2 from "http";
|
|
5305
|
+
import fs18 from "fs";
|
|
5306
|
+
import path17 from "path";
|
|
5307
|
+
|
|
5308
|
+
// src/lib/preview/latex-to-html.ts
|
|
5309
|
+
function latexToHtml(latex) {
|
|
5310
|
+
let body = latex;
|
|
5311
|
+
const docMatch = body.match(/\\begin\{document\}([\s\S]*?)\\end\{document\}/);
|
|
5312
|
+
if (docMatch) body = docMatch[1];
|
|
5313
|
+
const titleMatch = latex.match(/\\title\{([^}]*)\}/);
|
|
5314
|
+
const authorMatch = latex.match(/\\author\{([^}]*)\}/);
|
|
5315
|
+
const dateMatch = latex.match(/\\date\{([^}]*)\}/);
|
|
5316
|
+
const abstractMatch = body.match(/\\begin\{abstract\}([\s\S]*?)\\end\{abstract\}/);
|
|
5317
|
+
body = body.replace(/\\maketitle/, "");
|
|
5318
|
+
body = body.replace(/\\begin\{abstract\}[\s\S]*?\\end\{abstract\}/, "");
|
|
5319
|
+
body = body.replace(/\\section\*?\{([^}]*)\}/g, '<h2 class="section">$1</h2>');
|
|
5320
|
+
body = body.replace(/\\subsection\*?\{([^}]*)\}/g, '<h3 class="subsection">$1</h3>');
|
|
5321
|
+
body = body.replace(/\\subsubsection\*?\{([^}]*)\}/g, '<h4 class="subsubsection">$1</h4>');
|
|
5322
|
+
body = body.replace(/\\paragraph\{([^}]*)\}/g, '<h5 class="paragraph">$1</h5>');
|
|
5323
|
+
body = body.replace(/\\textbf\{([^}]*)\}/g, "<strong>$1</strong>");
|
|
5324
|
+
body = body.replace(/\\textit\{([^}]*)\}/g, "<em>$1</em>");
|
|
5325
|
+
body = body.replace(/\\texttt\{([^}]*)\}/g, "<code>$1</code>");
|
|
5326
|
+
body = body.replace(/\\emph\{([^}]*)\}/g, "<em>$1</em>");
|
|
5327
|
+
body = body.replace(/\\underline\{([^}]*)\}/g, "<u>$1</u>");
|
|
5328
|
+
body = body.replace(/\\cite\{([^}]*)\}/g, '<span class="citation">[$1]</span>');
|
|
5329
|
+
body = body.replace(/\\citep\{([^}]*)\}/g, '<span class="citation">($1)</span>');
|
|
5330
|
+
body = body.replace(/\\citet\{([^}]*)\}/g, '<span class="citation">$1</span>');
|
|
5331
|
+
body = body.replace(/\\ref\{([^}]*)\}/g, '<span class="ref">[ref:$1]</span>');
|
|
5332
|
+
body = body.replace(/\\label\{([^}]*)\}/g, "");
|
|
5333
|
+
body = body.replace(/\\\[([\s\S]*?)\\\]/g, '<div class="math-display">\\[$1\\]</div>');
|
|
5334
|
+
body = body.replace(/\$\$([\s\S]*?)\$\$/g, '<div class="math-display">\\[$1\\]</div>');
|
|
5335
|
+
body = body.replace(
|
|
5336
|
+
/\\begin\{equation\*?\}([\s\S]*?)\\end\{equation\*?\}/g,
|
|
5337
|
+
'<div class="math-display">\\[$1\\]</div>'
|
|
5338
|
+
);
|
|
5339
|
+
body = body.replace(
|
|
5340
|
+
/\\begin\{align\*?\}([\s\S]*?)\\end\{align\*?\}/g,
|
|
5341
|
+
'<div class="math-display">\\[$1\\]</div>'
|
|
5342
|
+
);
|
|
5343
|
+
body = body.replace(/(?<!\$)\$(?!\$)([^$]+?)\$(?!\$)/g, '<span class="math-inline">\\($1\\)</span>');
|
|
5344
|
+
body = body.replace(/\\begin\{itemize\}/g, "<ul>");
|
|
5345
|
+
body = body.replace(/\\end\{itemize\}/g, "</ul>");
|
|
5346
|
+
body = body.replace(/\\begin\{enumerate\}/g, "<ol>");
|
|
5347
|
+
body = body.replace(/\\end\{enumerate\}/g, "</ol>");
|
|
5348
|
+
body = body.replace(/\\item\s*/g, "<li>");
|
|
5349
|
+
body = body.replace(
|
|
5350
|
+
/\\begin\{quote\}([\s\S]*?)\\end\{quote\}/g,
|
|
5351
|
+
"<blockquote>$1</blockquote>"
|
|
5352
|
+
);
|
|
5353
|
+
body = body.replace(
|
|
5354
|
+
/\\begin\{verbatim\}([\s\S]*?)\\end\{verbatim\}/g,
|
|
5355
|
+
"<pre><code>$1</code></pre>"
|
|
5356
|
+
);
|
|
5357
|
+
body = body.replace(
|
|
5358
|
+
/\\begin\{figure\}[\s\S]*?\\caption\{([^}]*)\}[\s\S]*?\\end\{figure\}/g,
|
|
5359
|
+
'<figure class="figure-placeholder"><figcaption>$1</figcaption></figure>'
|
|
5360
|
+
);
|
|
5361
|
+
body = body.replace(
|
|
5362
|
+
/\\begin\{table\}[\s\S]*?\\caption\{([^}]*)\}[\s\S]*?\\end\{table\}/g,
|
|
5363
|
+
'<figure class="table-placeholder"><figcaption>Table: $1</figcaption></figure>'
|
|
5364
|
+
);
|
|
5365
|
+
body = body.replace(/\\footnote\{([^}]*)\}/g, '<sup class="footnote" title="$1">[*]</sup>');
|
|
5366
|
+
body = body.replace(/\\bibliography\{[^}]*\}/g, "");
|
|
5367
|
+
body = body.replace(/\\bibliographystyle\{[^}]*\}/g, "");
|
|
5368
|
+
body = body.replace(/\\usepackage\{[^}]*\}/g, "");
|
|
5369
|
+
body = body.replace(/\\documentclass[^{]*\{[^}]*\}/g, "");
|
|
5370
|
+
body = body.replace(/\\begin\{document\}/g, "");
|
|
5371
|
+
body = body.replace(/\\end\{document\}/g, "");
|
|
5372
|
+
body = body.replace(/\\newcommand[^{]*\{[^}]*\}\{[^}]*\}/g, "");
|
|
5373
|
+
body = body.replace(/\\\\/g, "<br>");
|
|
5374
|
+
body = body.replace(/\\newline/g, "<br>");
|
|
5375
|
+
body = body.replace(/\\noindent\s*/g, "");
|
|
5376
|
+
body = body.replace(/\\vspace\{[^}]*\}/g, "");
|
|
5377
|
+
body = body.replace(/\\hspace\{[^}]*\}/g, "");
|
|
5378
|
+
body = body.replace(/\n\s*\n/g, "</p><p>");
|
|
5379
|
+
body = `<p>${body}</p>`;
|
|
5380
|
+
body = body.replace(/<p>\s*<\/p>/g, "");
|
|
5381
|
+
body = body.replace(/<p>\s*<(h[2-5])/g, "<$1");
|
|
5382
|
+
body = body.replace(/<\/(h[2-5])>\s*<\/p>/g, "</$1>");
|
|
5383
|
+
const titleHtml = titleMatch ? `<h1 class="title">${titleMatch[1]}</h1>` : "";
|
|
5384
|
+
const authorHtml = authorMatch ? `<p class="author">${authorMatch[1]}</p>` : "";
|
|
5385
|
+
const dateHtml = dateMatch ? `<p class="date">${dateMatch[1]}</p>` : "";
|
|
5386
|
+
const abstractHtml = abstractMatch ? `<div class="abstract"><h3>Abstract</h3><p>${abstractMatch[1].trim()}</p></div>` : "";
|
|
5387
|
+
return `${titleHtml}${authorHtml}${dateHtml}${abstractHtml}${body}`;
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5390
|
+
// src/lib/preview/server.ts
|
|
5391
|
+
var HTML_TEMPLATE = `<!DOCTYPE html>
|
|
5392
|
+
<html lang="en">
|
|
5393
|
+
<head>
|
|
5394
|
+
<meta charset="UTF-8">
|
|
5395
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5396
|
+
<title>Open Research \u2014 LaTeX Preview</title>
|
|
5397
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
|
|
5398
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
|
|
5399
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"
|
|
5400
|
+
onload="renderMathInElement(document.body, {
|
|
5401
|
+
delimiters: [
|
|
5402
|
+
{left: '\\\\[', right: '\\\\]', display: true},
|
|
5403
|
+
{left: '\\\\(', right: '\\\\)', display: false}
|
|
5404
|
+
],
|
|
5405
|
+
throwOnError: false
|
|
5406
|
+
});">
|
|
5407
|
+
</script>
|
|
5408
|
+
<style>
|
|
5409
|
+
:root {
|
|
5410
|
+
--bg: #1a1a2e;
|
|
5411
|
+
--surface: #16213e;
|
|
5412
|
+
--text: #e0e0e0;
|
|
5413
|
+
--text-dim: #8892b0;
|
|
5414
|
+
--accent: #64ffda;
|
|
5415
|
+
--heading: #ccd6f6;
|
|
5416
|
+
--citation: #64ffda;
|
|
5417
|
+
--border: #233554;
|
|
5418
|
+
}
|
|
5419
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
5420
|
+
body {
|
|
5421
|
+
font-family: 'Charter', 'Georgia', 'Times New Roman', serif;
|
|
5422
|
+
background: var(--bg);
|
|
5423
|
+
color: var(--text);
|
|
5424
|
+
line-height: 1.8;
|
|
5425
|
+
max-width: 780px;
|
|
5426
|
+
margin: 0 auto;
|
|
5427
|
+
padding: 3rem 2rem;
|
|
5428
|
+
}
|
|
5429
|
+
h1.title {
|
|
5430
|
+
font-size: 2rem;
|
|
5431
|
+
color: var(--heading);
|
|
5432
|
+
text-align: center;
|
|
5433
|
+
margin-bottom: 0.5rem;
|
|
5434
|
+
line-height: 1.3;
|
|
5435
|
+
}
|
|
5436
|
+
.author {
|
|
5437
|
+
text-align: center;
|
|
5438
|
+
color: var(--text-dim);
|
|
5439
|
+
font-style: italic;
|
|
5440
|
+
margin-bottom: 0.3rem;
|
|
5441
|
+
}
|
|
5442
|
+
.date {
|
|
5443
|
+
text-align: center;
|
|
5444
|
+
color: var(--text-dim);
|
|
5445
|
+
margin-bottom: 2rem;
|
|
5446
|
+
}
|
|
5447
|
+
.abstract {
|
|
5448
|
+
background: var(--surface);
|
|
5449
|
+
border-left: 3px solid var(--accent);
|
|
5450
|
+
padding: 1.2rem 1.5rem;
|
|
5451
|
+
margin: 2rem 0;
|
|
5452
|
+
border-radius: 0 4px 4px 0;
|
|
5453
|
+
}
|
|
5454
|
+
.abstract h3 {
|
|
5455
|
+
color: var(--accent);
|
|
5456
|
+
font-size: 0.9rem;
|
|
5457
|
+
text-transform: uppercase;
|
|
5458
|
+
letter-spacing: 0.1em;
|
|
5459
|
+
margin-bottom: 0.5rem;
|
|
5460
|
+
}
|
|
5461
|
+
h2.section {
|
|
5462
|
+
font-size: 1.4rem;
|
|
5463
|
+
color: var(--heading);
|
|
5464
|
+
margin: 2.5rem 0 1rem;
|
|
5465
|
+
padding-bottom: 0.3rem;
|
|
5466
|
+
border-bottom: 1px solid var(--border);
|
|
5467
|
+
}
|
|
5468
|
+
h3.subsection {
|
|
5469
|
+
font-size: 1.15rem;
|
|
5470
|
+
color: var(--heading);
|
|
5471
|
+
margin: 1.8rem 0 0.8rem;
|
|
5472
|
+
}
|
|
5473
|
+
h4.subsubsection {
|
|
5474
|
+
font-size: 1rem;
|
|
5475
|
+
color: var(--text-dim);
|
|
5476
|
+
margin: 1.2rem 0 0.5rem;
|
|
5477
|
+
}
|
|
5478
|
+
p { margin: 0.8rem 0; }
|
|
5479
|
+
strong { color: var(--heading); }
|
|
5480
|
+
code {
|
|
5481
|
+
background: var(--surface);
|
|
5482
|
+
padding: 0.15rem 0.4rem;
|
|
5483
|
+
border-radius: 3px;
|
|
5484
|
+
font-size: 0.9em;
|
|
5485
|
+
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
5486
|
+
}
|
|
5487
|
+
pre {
|
|
5488
|
+
background: var(--surface);
|
|
5489
|
+
padding: 1rem;
|
|
5490
|
+
border-radius: 4px;
|
|
5491
|
+
overflow-x: auto;
|
|
5492
|
+
margin: 1rem 0;
|
|
5493
|
+
}
|
|
5494
|
+
pre code { background: none; padding: 0; }
|
|
5495
|
+
blockquote {
|
|
5496
|
+
border-left: 3px solid var(--border);
|
|
5497
|
+
padding-left: 1rem;
|
|
5498
|
+
color: var(--text-dim);
|
|
5499
|
+
font-style: italic;
|
|
5500
|
+
margin: 1rem 0;
|
|
5501
|
+
}
|
|
5502
|
+
ul, ol { padding-left: 1.5rem; margin: 0.8rem 0; }
|
|
5503
|
+
li { margin: 0.3rem 0; }
|
|
5504
|
+
.citation {
|
|
5505
|
+
color: var(--citation);
|
|
5506
|
+
font-weight: 500;
|
|
5507
|
+
cursor: help;
|
|
5508
|
+
}
|
|
5509
|
+
.ref { color: var(--accent); font-style: italic; }
|
|
5510
|
+
.footnote { color: var(--accent); cursor: help; }
|
|
5511
|
+
.math-display {
|
|
5512
|
+
margin: 1.2rem 0;
|
|
5513
|
+
overflow-x: auto;
|
|
5514
|
+
text-align: center;
|
|
5515
|
+
}
|
|
5516
|
+
.figure-placeholder, .table-placeholder {
|
|
5517
|
+
background: var(--surface);
|
|
5518
|
+
border: 1px dashed var(--border);
|
|
5519
|
+
padding: 2rem;
|
|
5520
|
+
margin: 1.5rem 0;
|
|
5521
|
+
text-align: center;
|
|
5522
|
+
border-radius: 4px;
|
|
5523
|
+
}
|
|
5524
|
+
.figure-placeholder::before { content: '[Figure placeholder]'; display: block; color: var(--text-dim); margin-bottom: 0.5rem; }
|
|
5525
|
+
.table-placeholder::before { content: '[Table placeholder]'; display: block; color: var(--text-dim); margin-bottom: 0.5rem; }
|
|
5526
|
+
figcaption { font-style: italic; color: var(--text-dim); font-size: 0.9rem; }
|
|
5527
|
+
|
|
5528
|
+
/* Live reload indicator */
|
|
5529
|
+
.live-badge {
|
|
5530
|
+
position: fixed;
|
|
5531
|
+
top: 1rem;
|
|
5532
|
+
right: 1rem;
|
|
5533
|
+
background: #0d7337;
|
|
5534
|
+
color: white;
|
|
5535
|
+
padding: 0.3rem 0.8rem;
|
|
5536
|
+
border-radius: 20px;
|
|
5537
|
+
font-size: 0.75rem;
|
|
5538
|
+
font-family: sans-serif;
|
|
5539
|
+
opacity: 0.8;
|
|
5540
|
+
}
|
|
5541
|
+
.live-badge.disconnected { background: #7d3030; }
|
|
5542
|
+
</style>
|
|
5543
|
+
</head>
|
|
5544
|
+
<body>
|
|
5545
|
+
<div class="live-badge" id="status">LIVE</div>
|
|
5546
|
+
<div id="content">
|
|
5547
|
+
{{CONTENT}}
|
|
5548
|
+
</div>
|
|
5549
|
+
<script>
|
|
5550
|
+
// Auto-reload via polling (simple, no WebSocket dependency)
|
|
5551
|
+
let lastHash = "";
|
|
5552
|
+
async function checkForUpdates() {
|
|
5553
|
+
try {
|
|
5554
|
+
const res = await fetch("/__hash");
|
|
5555
|
+
const hash = await res.text();
|
|
5556
|
+
if (lastHash && hash !== lastHash) {
|
|
5557
|
+
location.reload();
|
|
5558
|
+
}
|
|
5559
|
+
lastHash = hash;
|
|
5560
|
+
document.getElementById("status").textContent = "LIVE";
|
|
5561
|
+
document.getElementById("status").className = "live-badge";
|
|
5562
|
+
} catch {
|
|
5563
|
+
document.getElementById("status").textContent = "DISCONNECTED";
|
|
5564
|
+
document.getElementById("status").className = "live-badge disconnected";
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
setInterval(checkForUpdates, 1000);
|
|
5568
|
+
checkForUpdates();
|
|
5569
|
+
</script>
|
|
5570
|
+
</body>
|
|
5571
|
+
</html>`;
|
|
5572
|
+
function startPreviewServer(texPath) {
|
|
5573
|
+
const resolved = path17.resolve(texPath);
|
|
5574
|
+
let currentHash = "";
|
|
5575
|
+
function getContentHash() {
|
|
5576
|
+
try {
|
|
5577
|
+
const content = fs18.readFileSync(resolved, "utf8");
|
|
5578
|
+
return `${content.length}-${content.slice(0, 100)}-${content.slice(-100)}`;
|
|
5579
|
+
} catch {
|
|
5580
|
+
return "error";
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
function renderPage() {
|
|
5584
|
+
try {
|
|
5585
|
+
const latex = fs18.readFileSync(resolved, "utf8");
|
|
5586
|
+
const htmlContent = latexToHtml(latex);
|
|
5587
|
+
currentHash = getContentHash();
|
|
5588
|
+
return HTML_TEMPLATE.replace("{{CONTENT}}", htmlContent);
|
|
5589
|
+
} catch (err) {
|
|
5590
|
+
return HTML_TEMPLATE.replace(
|
|
5591
|
+
"{{CONTENT}}",
|
|
5592
|
+
`<p style="color: #ff6b6b;">Error reading ${resolved}: ${err instanceof Error ? err.message : String(err)}</p>`
|
|
5593
|
+
);
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
return new Promise((resolve) => {
|
|
5597
|
+
const server = http2.createServer((req, res) => {
|
|
5598
|
+
if (req.url === "/__hash") {
|
|
5599
|
+
const hash = getContentHash();
|
|
5600
|
+
res.writeHead(200, { "Content-Type": "text/plain", "Cache-Control": "no-cache" });
|
|
5601
|
+
res.end(hash);
|
|
5602
|
+
return;
|
|
5603
|
+
}
|
|
5604
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-cache" });
|
|
5605
|
+
res.end(renderPage());
|
|
5606
|
+
});
|
|
5607
|
+
server.listen(0, "127.0.0.1", () => {
|
|
5608
|
+
const addr = server.address();
|
|
5609
|
+
if (!addr || typeof addr === "string") return;
|
|
5610
|
+
const port = addr.port;
|
|
5611
|
+
const url = `http://127.0.0.1:${port}`;
|
|
5612
|
+
resolve({
|
|
5613
|
+
url,
|
|
5614
|
+
port,
|
|
5615
|
+
close: () => server.close()
|
|
5616
|
+
});
|
|
5617
|
+
});
|
|
5618
|
+
});
|
|
5619
|
+
}
|
|
5620
|
+
|
|
5297
5621
|
// src/tui/commands.ts
|
|
5298
5622
|
var SLASH_COMMANDS = [
|
|
5299
5623
|
{ name: "auth", aliases: ["/connect", "/login"], description: "Connect your OpenAI account via browser OAuth", category: "auth" },
|
|
@@ -5306,6 +5630,7 @@ var SLASH_COMMANDS = [
|
|
|
5306
5630
|
{ name: "clear", aliases: ["/new"], description: "Clear conversation and start fresh", category: "session" },
|
|
5307
5631
|
{ name: "help", aliases: ["/commands"], description: "Show available commands", category: "system" },
|
|
5308
5632
|
{ name: "config", aliases: ["/settings"], description: "View or change settings (e.g. /config theme dark)", category: "system" },
|
|
5633
|
+
{ name: "preview", aliases: [], description: "Live preview a LaTeX file in browser (e.g. /preview papers/draft.tex)", category: "workspace" },
|
|
5309
5634
|
{ name: "memory", aliases: ["/memories"], description: "View or clear stored memories about you", category: "system" },
|
|
5310
5635
|
{ name: "exit", aliases: ["/quit", "/q"], description: "Exit Open Research", category: "system" }
|
|
5311
5636
|
];
|
|
@@ -5843,6 +6168,7 @@ function App({
|
|
|
5843
6168
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
5844
6169
|
const activityFrame = useAnimatedFrame(busy);
|
|
5845
6170
|
const [agentQuestion, setAgentQuestion] = useState3(null);
|
|
6171
|
+
const previewRef = useRef(null);
|
|
5846
6172
|
const isHome = deferredMessages.length === 0 && !busy;
|
|
5847
6173
|
const hasWorkspace = workspacePath !== null;
|
|
5848
6174
|
const hasAuth = authStatus === "connected";
|
|
@@ -6132,6 +6458,29 @@ function App({
|
|
|
6132
6458
|
addSystemMessage(" Esc unfocus prompt");
|
|
6133
6459
|
break;
|
|
6134
6460
|
}
|
|
6461
|
+
case "preview": {
|
|
6462
|
+
if (!args) {
|
|
6463
|
+
addSystemMessage("Usage: /preview <path-to-tex-file>");
|
|
6464
|
+
addSystemMessage("Example: /preview papers/draft.tex");
|
|
6465
|
+
break;
|
|
6466
|
+
}
|
|
6467
|
+
const texPath = args.trim();
|
|
6468
|
+
const resolvedTex = __require("path").isAbsolute(texPath) ? texPath : __require("path").resolve(workspacePath ?? process.cwd(), texPath);
|
|
6469
|
+
try {
|
|
6470
|
+
if (previewRef.current) {
|
|
6471
|
+
previewRef.current.close();
|
|
6472
|
+
}
|
|
6473
|
+
const preview = await startPreviewServer(resolvedTex);
|
|
6474
|
+
previewRef.current = preview;
|
|
6475
|
+
addSystemMessage(`Live preview started at ${preview.url}`);
|
|
6476
|
+
addSystemMessage("Auto-reloads when the file changes. Close with /preview stop");
|
|
6477
|
+
const openModule = await import("open");
|
|
6478
|
+
await openModule.default(preview.url);
|
|
6479
|
+
} catch (err) {
|
|
6480
|
+
addSystemMessage(`Preview failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
6481
|
+
}
|
|
6482
|
+
break;
|
|
6483
|
+
}
|
|
6135
6484
|
case "memory": {
|
|
6136
6485
|
if (args === "clear") {
|
|
6137
6486
|
await clearMemories({ homeDir });
|
|
@@ -6807,7 +7156,7 @@ function App({
|
|
|
6807
7156
|
statusParts,
|
|
6808
7157
|
statusColor,
|
|
6809
7158
|
tokenDisplay,
|
|
6810
|
-
workspaceName: hasWorkspace ?
|
|
7159
|
+
workspaceName: hasWorkspace ? path18.basename(workspacePath) : process.cwd(),
|
|
6811
7160
|
mode: agentMode,
|
|
6812
7161
|
planningStatus: planningState.status
|
|
6813
7162
|
}
|
|
@@ -6819,7 +7168,7 @@ function App({
|
|
|
6819
7168
|
var program = new Command();
|
|
6820
7169
|
program.name("open-research").description("Local-first research CLI powered by ChatGPT/Codex auth.").argument("[workspacePath]", "Optional workspace path to open").action(async (workspacePath) => {
|
|
6821
7170
|
await ensureOpenResearchConfig();
|
|
6822
|
-
const target = workspacePath ?
|
|
7171
|
+
const target = workspacePath ? path19.resolve(workspacePath) : process.cwd();
|
|
6823
7172
|
const project = await loadWorkspaceProject(target);
|
|
6824
7173
|
const auth2 = await loadStoredAuth();
|
|
6825
7174
|
render(
|
|
@@ -6841,7 +7190,7 @@ program.name("open-research").description("Local-first research CLI powered by C
|
|
|
6841
7190
|
});
|
|
6842
7191
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|
|
6843
7192
|
await ensureOpenResearchConfig();
|
|
6844
|
-
const target =
|
|
7193
|
+
const target = path19.resolve(workspacePath ?? process.cwd());
|
|
6845
7194
|
const project = await initWorkspace({ workspaceDir: target });
|
|
6846
7195
|
console.log(`Initialized workspace: ${target}`);
|
|
6847
7196
|
console.log(`Title: ${project.title}`);
|
|
@@ -6910,8 +7259,8 @@ skills.command("create").argument("[name]").description("Scaffold a new user ski
|
|
|
6910
7259
|
});
|
|
6911
7260
|
skills.command("edit").argument("<name>").description("Open a user skill in $EDITOR.").action(async (name) => {
|
|
6912
7261
|
await ensureOpenResearchConfig();
|
|
6913
|
-
const skillDir =
|
|
6914
|
-
openInEditor(
|
|
7262
|
+
const skillDir = path19.join(getOpenResearchSkillsDir(), name);
|
|
7263
|
+
openInEditor(path19.join(skillDir, "SKILL.md"));
|
|
6915
7264
|
const validation = await validateSkillDirectory({ skillDir });
|
|
6916
7265
|
if (!validation.ok) {
|
|
6917
7266
|
console.error(validation.errors.join("\n"));
|
|
@@ -6922,9 +7271,9 @@ skills.command("edit").argument("<name>").description("Open a user skill in $EDI
|
|
|
6922
7271
|
});
|
|
6923
7272
|
skills.command("validate").argument("[nameOrPath]").description("Validate one user skill.").action(async (nameOrPath) => {
|
|
6924
7273
|
await ensureOpenResearchConfig();
|
|
6925
|
-
const skillDir = nameOrPath ?
|
|
7274
|
+
const skillDir = nameOrPath ? path19.isAbsolute(nameOrPath) ? nameOrPath : path19.join(getOpenResearchSkillsDir(), nameOrPath) : getOpenResearchSkillsDir();
|
|
6926
7275
|
const stat = await import("fs/promises").then(
|
|
6927
|
-
(
|
|
7276
|
+
(fs19) => fs19.stat(skillDir).catch(() => null)
|
|
6928
7277
|
);
|
|
6929
7278
|
if (!stat) {
|
|
6930
7279
|
throw new Error(`Skill path not found: ${skillDir}`);
|
package/package.json
CHANGED