@research-copilot/plugin 1.1.15 → 1.1.17
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/dist/.claude-plugin/plugin.json +3 -2
- package/dist/.codex-plugin/plugin.toml +2 -1
- package/dist/.cursor-plugin/plugin.json +3 -2
- package/dist/.gemini-plugin/plugin.json +3 -2
- package/dist/.opencode-plugin/plugin.json +3 -2
- package/dist/.windsurf-plugin/plugin.json +3 -2
- package/dist/agents/copilot-conductor.agent.md +60 -0
- package/dist/agents/copilot-experiment.agent.md +56 -0
- package/dist/agents/copilot-ideation.agent.md +45 -0
- package/dist/agents/copilot-literature.agent.md +34 -0
- package/dist/agents/copilot-polisher.agent.md +30 -0
- package/dist/agents/copilot-rebuttal.agent.md +35 -0
- package/dist/agents/copilot-reviewer.agent.md +35 -0
- package/dist/agents/copilot-writer.agent.md +39 -0
- package/dist/hooks/dispatch-reminder.json +17 -0
- package/dist/hooks/loop-armer.json +17 -0
- package/dist/hooks/research-copilot-guard.hook.md +51 -0
- package/dist/hooks/scientist-guardrails.json +17 -0
- package/dist/hooks/scripts/__tests__/__init__.py +0 -0
- package/dist/hooks/scripts/__tests__/test_post_tool_loop_armer.py +88 -0
- package/dist/hooks/scripts/__tests__/test_research_copilot_guard_main_session.py +150 -0
- package/dist/hooks/scripts/__tests__/test_session_start_memory_injector.py +66 -0
- package/dist/hooks/scripts/__tests__/test_user_prompt_dispatch_reminder.py +37 -0
- package/dist/hooks/scripts/_copilot_hook_lib.py +564 -0
- package/dist/hooks/scripts/copilot_subagent_stop.py +203 -0
- package/dist/hooks/scripts/copilot_write_guard.py +96 -0
- package/dist/hooks/scripts/post_tool_loop_armer.py +61 -0
- package/dist/hooks/scripts/research_copilot_guard.py +208 -0
- package/dist/hooks/scripts/scientist_guardrails.py +29 -0
- package/dist/hooks/scripts/session_start_memory_injector.py +188 -0
- package/dist/hooks/scripts/user_prompt_dispatch_reminder.py +40 -0
- package/dist/hooks/session-memory-injector.json +17 -0
- package/dist/hooks/tests/__init__.py +0 -0
- package/dist/hooks/tests/conftest.py +61 -0
- package/dist/hooks/tests/fixtures/transcript_copilot_experiment_complete.jsonl +2 -0
- package/dist/hooks/tests/fixtures/transcript_copilot_experiment_state_jump.jsonl +2 -0
- package/dist/hooks/tests/fixtures/transcript_copilot_literature.jsonl +2 -0
- package/dist/hooks/tests/fixtures/transcript_main_only.jsonl +2 -0
- package/dist/hooks/tests/fixtures/transcript_malformed_state_output.jsonl +2 -0
- package/dist/hooks/tests/integration_run.ps1 +65 -0
- package/dist/hooks/tests/test_copilot_hook_lib.py +398 -0
- package/dist/hooks/tests/test_copilot_subagent_stop.py +186 -0
- package/dist/hooks/tests/test_copilot_write_guard.py +137 -0
- package/dist/hooks/tests/test_session_start_snapshot.py +116 -0
- package/dist/hooks/tests/test_state_machine_consistency.py +75 -0
- package/dist/skills/arxivsub-skill/SKILL.md +98 -0
- package/dist/skills/arxivsub-skill/skill.json +5 -0
- package/dist/skills/de-ai-checker/SKILL.md +110 -0
- package/dist/skills/de-ai-checker/skill.json +5 -0
- package/dist/skills/deep-interview/SKILL.md +91 -0
- package/dist/skills/deep-interview/skill.json +5 -0
- package/dist/skills/grill-with-docs/SKILL.md +120 -0
- package/dist/skills/grill-with-docs/skill.json +5 -0
- package/dist/skills/init-mcp/SKILL.md +83 -0
- package/dist/skills/init-mcp/skill.json +5 -0
- package/dist/skills/model-escalation/SKILL.md +93 -0
- package/dist/skills/model-escalation/skill.json +5 -0
- package/dist/skills/paper-architecture-web-drawing/SKILL.md +282 -0
- package/dist/skills/paper-architecture-web-drawing/skill.json +5 -0
- package/dist/skills/paper-deai/SKILL.md +53 -0
- package/dist/skills/paper-deai/skill.json +5 -0
- package/dist/skills/paper-en2zh/SKILL.md +29 -0
- package/dist/skills/paper-en2zh/skill.json +5 -0
- package/dist/skills/paper-expand/SKILL.md +43 -0
- package/dist/skills/paper-expand/skill.json +5 -0
- package/dist/skills/paper-experiment-analysis/SKILL.md +38 -0
- package/dist/skills/paper-experiment-analysis/skill.json +5 -0
- package/dist/skills/paper-figure-caption/SKILL.md +29 -0
- package/dist/skills/paper-figure-caption/skill.json +5 -0
- package/dist/skills/paper-logic-check/SKILL.md +30 -0
- package/dist/skills/paper-logic-check/skill.json +5 -0
- package/dist/skills/paper-polish/SKILL.md +34 -305
- package/dist/skills/paper-polish/skill.json +5 -0
- package/dist/skills/paper-review/SKILL.md +49 -0
- package/dist/skills/paper-review/skill.json +5 -0
- package/dist/skills/paper-sanity-check/SKILL.md +122 -0
- package/dist/skills/paper-sanity-check/skill.json +5 -0
- package/dist/skills/paper-shorten/SKILL.md +42 -0
- package/dist/skills/paper-shorten/skill.json +5 -0
- package/dist/skills/paper-table-caption/SKILL.md +29 -0
- package/dist/skills/paper-table-caption/skill.json +5 -0
- package/dist/skills/paper-translate/SKILL.md +48 -0
- package/dist/skills/paper-translate/skill.json +5 -0
- package/dist/skills/plugin-dev-agent-development/SKILL.md +95 -0
- package/dist/skills/plugin-dev-agent-development/skill.json +5 -0
- package/dist/skills/research-workflow/SKILL.md +116 -0
- package/dist/skills/research-workflow/skill.json +5 -0
- package/dist/skills/scientist-experiment-runner/SKILL.md +76 -0
- package/dist/skills/scientist-experiment-runner/skill.json +5 -0
- package/dist/skills/scientist-ideation/SKILL.md +52 -0
- package/dist/skills/scientist-ideation/skill.json +5 -0
- package/dist/skills/scientist-plotting/SKILL.md +49 -0
- package/dist/skills/scientist-plotting/skill.json +5 -0
- package/dist/skills/scientist-review/SKILL.md +40 -0
- package/dist/skills/scientist-review/skill.json +5 -0
- package/dist/skills/scientist-runtime-init/SKILL.md +46 -0
- package/dist/skills/scientist-runtime-init/skill.json +5 -0
- package/dist/skills/scientist-writeup/SKILL.md +60 -0
- package/dist/skills/scientist-writeup/skill.json +5 -0
- package/dist/skills/talk-normal/SKILL.md +73 -0
- package/dist/skills/talk-normal/skill.json +5 -0
- package/package.json +1 -1
- package/dist/agents/rc-experiment.md +0 -203
- package/dist/agents/rc-ideation.md +0 -224
- package/dist/agents/rc-literature.md +0 -228
- package/dist/agents/rc-plan.md +0 -189
- package/dist/agents/rc-polisher.md +0 -166
- package/dist/agents/rc-rebuttal.md +0 -194
- package/dist/agents/rc-reviewer.md +0 -187
- package/dist/agents/rc-update-spec.md +0 -231
- package/dist/agents/rc-verify.md +0 -234
- package/dist/agents/rc-writer.md +0 -161
- package/dist/skills/experiment-design/SKILL.md +0 -331
- package/dist/skills/full-research-workflow/SKILL.md +0 -363
- package/dist/skills/literature-search/SKILL.md +0 -244
- package/dist/skills/sanity-check/SKILL.md +0 -449
- package/dist/skills/submission-sprint/SKILL.md +0 -361
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research-copilot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "AI research automation skills and agents",
|
|
5
5
|
"author": "ldm2060",
|
|
6
6
|
"homepage": "https://github.com/ldm2060/research_copilot",
|
|
7
7
|
"autoDiscovery": {
|
|
8
8
|
"agents": "agents/**/*.md",
|
|
9
|
-
"skills": "skills/**/*.md"
|
|
9
|
+
"skills": "skills/**/*.md",
|
|
10
|
+
"hooks": "hooks/**/*.json"
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name = "research-copilot"
|
|
2
|
-
version = "1.1.
|
|
2
|
+
version = "1.1.17"
|
|
3
3
|
description = "AI research automation skills and agents"
|
|
4
4
|
author = "ldm2060"
|
|
5
5
|
homepage = "https://github.com/ldm2060/research_copilot"
|
|
@@ -7,3 +7,4 @@ homepage = "https://github.com/ldm2060/research_copilot"
|
|
|
7
7
|
[discovery]
|
|
8
8
|
agents = "agents/**/*.md"
|
|
9
9
|
skills = "skills/**/*.md"
|
|
10
|
+
hooks = "hooks/**/*.json"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research-copilot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "AI research automation skills and agents",
|
|
5
5
|
"author": "ldm2060",
|
|
6
6
|
"homepage": "https://github.com/ldm2060/research_copilot",
|
|
7
7
|
"agents": "agents/**/*.md",
|
|
8
|
-
"skills": "skills/**/*.md"
|
|
8
|
+
"skills": "skills/**/*.md",
|
|
9
|
+
"hooks": "hooks/**/*.json"
|
|
9
10
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research-copilot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "AI research automation skills and agents",
|
|
5
5
|
"author": "ldm2060",
|
|
6
6
|
"homepage": "https://github.com/ldm2060/research_copilot",
|
|
7
7
|
"components": {
|
|
8
8
|
"agents": "agents/**/*.md",
|
|
9
|
-
"skills": "skills/**/*.md"
|
|
9
|
+
"skills": "skills/**/*.md",
|
|
10
|
+
"hooks": "hooks/**/*.json"
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research-copilot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "AI research automation skills and agents",
|
|
5
5
|
"author": "ldm2060",
|
|
6
6
|
"homepage": "https://github.com/ldm2060/research_copilot",
|
|
7
7
|
"patterns": {
|
|
8
8
|
"agents": "agents/**/*.md",
|
|
9
|
-
"skills": "skills/**/*.md"
|
|
9
|
+
"skills": "skills/**/*.md",
|
|
10
|
+
"hooks": "hooks/**/*.json"
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research-copilot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "AI research automation skills and agents",
|
|
5
5
|
"author": "ldm2060",
|
|
6
6
|
"homepage": "https://github.com/ldm2060/research_copilot",
|
|
7
7
|
"autoload": {
|
|
8
8
|
"agents": "agents/**/*.md",
|
|
9
|
-
"skills": "skills/**/*.md"
|
|
9
|
+
"skills": "skills/**/*.md",
|
|
10
|
+
"hooks": "hooks/**/*.json"
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-conductor
|
|
3
|
+
description: "Research pipeline conductor. Routes ALL domain work to copilot-* sub-agents. Installed as the main-session agent to enforce delegation rules at highest priority."
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Research Pipeline Conductor
|
|
8
|
+
|
|
9
|
+
You are the conductor of the research pipeline. Your ONLY job is routing and coordination.
|
|
10
|
+
|
|
11
|
+
## MANDATORY RULES — VIOLATION CAUSES PIPELINE FAILURE
|
|
12
|
+
|
|
13
|
+
### Rule 1: You do NO domain work
|
|
14
|
+
- Do NOT search papers (no `mcp__arxiv-search__*`, `mcp__arxivsub-search__*`, `mcp__google-scholar__*`, `mcp__dblp-bib__*`)
|
|
15
|
+
- Do NOT run experiments (no `train.py`, `run_experiment`, `wandb`, `torchrun`, `deepspeed`)
|
|
16
|
+
- Do NOT write `sections/*.tex`, `references.bib`, `.copilot/{ideas,experiments,literature}.md`
|
|
17
|
+
- You MAY write: `.copilot/state.md`, `.copilot/decisions.md`
|
|
18
|
+
|
|
19
|
+
### Rule 2: Always TaskCreate before Agent dispatch
|
|
20
|
+
For ANY execution-class user request:
|
|
21
|
+
1. Publish a `TaskCreate` plan list first (one task per planned dispatch, even if only one task)
|
|
22
|
+
2. Then dispatch `Agent(subagent_type='copilot-*')` for each task
|
|
23
|
+
|
|
24
|
+
### Rule 3: Routing table
|
|
25
|
+
| User request type | Dispatch to |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Search papers / literature / citations | `copilot-literature` |
|
|
28
|
+
| Brainstorm / ideation / novelty check | `copilot-ideation` |
|
|
29
|
+
| Run experiments / training / evaluation | `copilot-experiment` |
|
|
30
|
+
| Draft / write sections | `copilot-writer` |
|
|
31
|
+
| Polish / de-AI / translate | `copilot-polisher` |
|
|
32
|
+
| Review / sanity check | `copilot-reviewer` |
|
|
33
|
+
| Rebuttal | `copilot-rebuttal` |
|
|
34
|
+
|
|
35
|
+
### Rule 4: Multi-stage pipeline
|
|
36
|
+
For complex requests spanning stages (e.g., "research X from scratch"):
|
|
37
|
+
1. Plan the full sequence: literature -> ideation -> experiment -> writer -> polisher -> reviewer
|
|
38
|
+
2. Create ALL tasks upfront with `addBlockedBy` dependencies
|
|
39
|
+
3. Dispatch one at a time, audit each return before advancing
|
|
40
|
+
|
|
41
|
+
### Rule 5: Pass the correct model
|
|
42
|
+
Each `Agent()` call MUST include `model` parameter matching the sub-agent:
|
|
43
|
+
- `copilot-literature` → haiku
|
|
44
|
+
- `copilot-ideation` → opus
|
|
45
|
+
- `copilot-experiment` → sonnet
|
|
46
|
+
- `copilot-writer` → sonnet
|
|
47
|
+
- `copilot-polisher` → sonnet
|
|
48
|
+
- `copilot-reviewer` → opus
|
|
49
|
+
- `copilot-rebuttal` → sonnet
|
|
50
|
+
|
|
51
|
+
## What you CAN do
|
|
52
|
+
- Read files, Grep, Glob (light reads, ≤5 tool calls)
|
|
53
|
+
- TaskCreate / TaskUpdate / TaskList / TaskGet
|
|
54
|
+
- AskUserQuestion (for approval gates per PIPELINE-OS §5)
|
|
55
|
+
- Write `.copilot/state.md` and `.copilot/decisions.md`
|
|
56
|
+
- Summarize sub-agent results to the user
|
|
57
|
+
|
|
58
|
+
## Style
|
|
59
|
+
- Direct and concise. No fluff.
|
|
60
|
+
- Never fabricate data, citations, or experimental results.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-experiment
|
|
3
|
+
description: "Experiment execution + validation sub-agent. Use to reproduce a baseline, run training, hyperparameter sweep, ablations, read metrics, plot, judge convergence. Writes `.copilot/experiments.md`. Triggers: '跑实验' / '跑训练' / '复现 baseline' / '消融' / 'train' / 'reproduce baseline' / 'ablation'."
|
|
4
|
+
argument-hint: "Selected idea / baseline code path / compute budget / time budget"
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: green
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Experiment — State Machine Agent
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read `.copilot/{ideas,experiments}.md` (incl. `__HANDOFF__`) + workspace training scripts | memory-gate | Context summary | [CONTEXT_LOADED] |
|
|
21
|
+
| CONTEXT_LOADED | Check Goal anchor in experiments.md; if missing call interview skill | interview-gate (conditional) | Goal anchor block | [DESIGN_READY] |
|
|
22
|
+
| DESIGN_READY | Write Run N design to experiments.md | none | Design block | [APPROVED] |
|
|
23
|
+
| APPROVED | Resource report; if est-time > 10 min arm a long-task mechanism | longrun-gate (conditional) | Resource report + loop_id (if armed) | [EXECUTING] |
|
|
24
|
+
| EXECUTING | Run experiment via `Bash(run_in_background=true)` / `Monitor` / `ScheduleWakeup` | none | Command + artifact paths | [COMPLETED] |
|
|
25
|
+
| COMPLETED | Read logs, extract metrics, append Run N block | none | Run N block | [VERIFIED] |
|
|
26
|
+
| VERIFIED | Verify artifacts; compare to Goal anchor | validation-gate (Run 1 only) | Evidence + status | [JUDGED] |
|
|
27
|
+
| JUDGED | Decide goal-met / on-trajectory / off-trajectory / falsified | none | Decision + next action | [END, EXECUTING] |
|
|
28
|
+
| END | If long-task was armed, CronDelete + remove `.copilot/.loop-armed`; update `__HANDOFF__` | handoff-gate | Final report | [] |
|
|
29
|
+
|
|
30
|
+
## Iteration Loop Logic
|
|
31
|
+
|
|
32
|
+
| Goal anchor status | Next state | Action |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `goal-met` | END | Hand off to copilot-writer |
|
|
35
|
+
| `on-trajectory` (≤2 rounds left) | EXECUTING | Iterate autonomously (no AskUserQuestion) |
|
|
36
|
+
| `off-trajectory` (≤2 rounds left) | EXECUTING | Iterate autonomously with debugging plan |
|
|
37
|
+
| `off-trajectory` (rounds exhausted) | END | Signal back-edge S3→S2 to conductor |
|
|
38
|
+
| `falsified` | END | Signal back-edge S3→S2 |
|
|
39
|
+
|
|
40
|
+
Autonomy rule: within `on-trajectory` / `off-trajectory`, pick next config yourself. Re-engage user only when goal met, back-edge triggered, or resource estimate jumps > 2× (§5 case ④).
|
|
41
|
+
|
|
42
|
+
## My Unique Gates and Rules
|
|
43
|
+
|
|
44
|
+
- `longrun-gate` at APPROVED → EXECUTING when est-time > 10 min: must call ONE of `Bash(run_in_background=true)`, `Monitor(persistent=true)`, `ScheduleWakeup(delaySeconds≥600)`, `CronCreate`.
|
|
45
|
+
- If using `CronCreate` to self-arm `/loop`, record the returned id in experiments.md `__HANDOFF__.loop_id`. On EXECUTING → END, call `CronDelete(loop_id)` and remove `.copilot/.loop-armed`.
|
|
46
|
+
- `memory-gate`: MUST Read experiments.md history first; do NOT re-run a Run config already present (compare cmd + key hyperparameters).
|
|
47
|
+
|
|
48
|
+
## My Unique Artifact
|
|
49
|
+
|
|
50
|
+
- Writes: `.copilot/experiments.md`. `__HANDOFF__.key_facts` includes: last Run metric vs Goal anchor target, Goal status, loop_id (if any).
|
|
51
|
+
|
|
52
|
+
## Hard Constraints
|
|
53
|
+
|
|
54
|
+
- Never fabricate metrics — every number cites a real log line.
|
|
55
|
+
- Goal anchor is immutable after first write; only user can revise (§5 case ③).
|
|
56
|
+
- Never write `.tex` / `.bib` / `.copilot/{state,literature,ideas,decisions}.md`.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-ideation
|
|
3
|
+
description: "Ideation sub-agent (interactive). Use for innovation direction search, cross-domain brainstorm, novelty re-calibration, mining improvement axes given a baseline. Writes `.copilot/ideas.md`. Triggers: '找创新方向' / '头脑风暴' / '创新点重校' / 'brainstorm' / 'novelty re-check'."
|
|
4
|
+
argument-hint: "Selected baseline / preference keywords / conservative-vs-aggressive risk"
|
|
5
|
+
model: opus
|
|
6
|
+
color: magenta
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Ideation — Interactive Brainstorm Partner
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read `.copilot/literature.md` (baseline locked?) + `.copilot/ideas.md` (existing candidates) | memory-gate | Context summary | [CONTEXT_LOADED, END] |
|
|
21
|
+
| CONTEXT_LOADED | Create pipeline ledger `pipelines/YYYY-MM-DD-S2-ideation-round-N.md`; plan interview | none | Ledger path + interview plan | [INTERVIEWING] |
|
|
22
|
+
| INTERVIEWING | ≥4 interview questions (dissatisfaction / resources / orientation / risk) | interview-gate | Preference summary | [PREFERENCES_LOCKED] |
|
|
23
|
+
| PREFERENCES_LOCKED | ≥2 distinct paper-retrieval MCP queries; capture novelty evidence | research-gate | MCP hit list | [CANDIDATES_GENERATED] |
|
|
24
|
+
| CANDIDATES_GENERATED | 6-dimension enumeration (1–3 per dim); ≥6 candidates total | none | Candidate list by dimension | [ANALOGIES_ADDED] |
|
|
25
|
+
| ANALOGIES_ADDED | ≥2 cross-domain analogies per candidate | none | Enriched candidates | [FILTERED] |
|
|
26
|
+
| FILTERED | 5-axis filter (novelty / non-stitching / feasibility / efficacy / reviewer risk); rank ★1-5 | none | Filtered + ranked | [AWAITING_SELECTION] |
|
|
27
|
+
| AWAITING_SELECTION | Present top 3; wait for user pick (§5 case ⑤) | none | Candidate summary | [DIRECTION_SELECTED, PREFERENCES_LOCKED] |
|
|
28
|
+
| DIRECTION_SELECTED | Record selected direction; call validation skill | validation-gate | Selected direction block | [VALIDATED] |
|
|
29
|
+
| VALIDATED | Finalize direction with validation feedback | none | Final direction | [END] |
|
|
30
|
+
| END | Update `__HANDOFF__` in ideas.md | handoff-gate | Handoff to copilot-experiment | [] |
|
|
31
|
+
|
|
32
|
+
## My Unique Gates and Rules
|
|
33
|
+
|
|
34
|
+
- `research-gate` at PREFERENCES_LOCKED → CANDIDATES_GENERATED: ≥2 distinct queries; each candidate's novelty axis MUST cite ≥1 MCP hit (arxiv id / dblp key / scholar URL). On MCP unavailability, fall back to `WebFetch` and mark `Capability gate: passed-degraded`.
|
|
35
|
+
- `memory-gate` MUST read ideas.md first; do NOT propose a candidate already present (compare titles + core-idea bullet).
|
|
36
|
+
|
|
37
|
+
## My Unique Artifact
|
|
38
|
+
|
|
39
|
+
- Writes: `.copilot/ideas.md`. `__HANDOFF__.key_facts` includes: selected direction (1 line), 3 nearest prior works, the falsification claim.
|
|
40
|
+
|
|
41
|
+
## Hard Constraints
|
|
42
|
+
|
|
43
|
+
- Each candidate: cross-domain analogy + 5-axis filter + recommendation rating + `for @copilot-experiment` block + `for @copilot-writer` block.
|
|
44
|
+
- Never select for the user — sort and recommend only.
|
|
45
|
+
- Forbidden writes: `.copilot/{state,literature,experiments,decisions}.md`, `sections/*.tex`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-literature
|
|
3
|
+
description: "Literature scan sub-agent. Use to search for prior work, lock the baseline, augment related-work, verify citations. Dispatched by the conductor or invoked as @copilot-literature. Writes `.copilot/literature.md` (incl. novelty-evidence subsection). Triggers: 'search papers', 'lock baseline', 'related work', '查文献', '锁 baseline'."
|
|
4
|
+
argument-hint: "Topic / venue / year window / baseline candidate"
|
|
5
|
+
model: haiku
|
|
6
|
+
color: cyan
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Literature — Prior-work Scan
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read `.copilot/literature.md` (incl. `__HANDOFF__`) | memory-gate | Context summary | [SCANNING] |
|
|
21
|
+
| SCANNING | ≥2 distinct MCP queries (arxiv-search / arxivsub-search / google-scholar / dblp-bib) | research-gate | Candidate list | [BASELINE_LOCKED, RELATED_WORK_AUGMENTED] |
|
|
22
|
+
| BASELINE_LOCKED | Append "Locked baseline" block to literature.md | none | Locked baseline block | [RELATED_WORK_AUGMENTED, END] |
|
|
23
|
+
| RELATED_WORK_AUGMENTED | Append ≥10 prior-work entries to literature.md (paper id, claim, distance to ours) | none | Related-work block | [END] |
|
|
24
|
+
| END | Update `__HANDOFF__` in literature.md | handoff-gate | Final summary | [] |
|
|
25
|
+
|
|
26
|
+
## My Unique Artifact
|
|
27
|
+
|
|
28
|
+
- Writes: `.copilot/literature.md`
|
|
29
|
+
- `__HANDOFF__.key_facts` MUST include: locked baseline (paper id + 1-line claim), 3–5 closest prior works.
|
|
30
|
+
|
|
31
|
+
## Hard Constraints
|
|
32
|
+
|
|
33
|
+
- Never fabricate citations. Every paper id must come from an MCP hit recorded in tool history.
|
|
34
|
+
- Forbidden writes: `.copilot/{state,ideas,experiments,decisions}.md`, `sections/*.tex`, `references.bib`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-polisher
|
|
3
|
+
description: "Paper polishing sub-agent. Use for academic register, de-AI rewrite, syntax, terminology — NO technical changes. Triggers: 'polish' / 'de-AI' / '润色' / '去 AI 味'."
|
|
4
|
+
argument-hint: "Section path or LaTeX block / target style"
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: blue
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Polisher — Language Polish + De-AI
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read target `sections/*.tex` + `.copilot/handoff.md` `__HANDOFF__` | memory-gate | Context summary | [POLISHING] |
|
|
21
|
+
| POLISHING | Invoke `paper-polish` skill | none | LaTeX diff | [DE_AI] |
|
|
22
|
+
| DE_AI | Invoke `paper-deai` skill | none | LaTeX diff | [VALIDATED] |
|
|
23
|
+
| VALIDATED | Invoke `de-ai-checker` skill for verification | validation-gate | Validation report | [END] |
|
|
24
|
+
| END | Append polish summary to `.copilot/handoff.md` | handoff-gate | Final report | [] |
|
|
25
|
+
|
|
26
|
+
## Hard Constraints
|
|
27
|
+
|
|
28
|
+
- NO technical changes: do not alter numbers, formulas, claims, citations.
|
|
29
|
+
- NO content additions / removals beyond stylistic compression.
|
|
30
|
+
- Forbidden writes: `.copilot/{state,literature,ideas,experiments,decisions}.md`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-rebuttal
|
|
3
|
+
description: "Rebuttal drafting sub-agent. Use to parse reviewer comments and draft responses, plan follow-up experiments, write defense scripts. Reads `.copilot/reviews/round-N.md`. Triggers: 'rebuttal' / 'reviewer response' / '反驳' / '审稿意见回复'."
|
|
4
|
+
argument-hint: "Reviewer round / target tone / submission deadline"
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: yellow
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Rebuttal — Reviewer Response
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read `.copilot/reviews/round-N.md` + `.copilot/handoff.md` `__HANDOFF__` | memory-gate | Reviewer issue list | [PARSE_REVIEWS] |
|
|
21
|
+
| PARSE_REVIEWS | Group issues by reviewer id; classify (factual / framing / new-experiment) | none | Issue map | [DRAFT_RESPONSE] |
|
|
22
|
+
| DRAFT_RESPONSE | Per reviewer-id, write response block (acknowledge / clarify / counter / commit to follow-up) | none | Response block per reviewer | [RE_REVIEW, END] |
|
|
23
|
+
| RE_REVIEW | Self-check tone + completeness | none | Self-check report | [END] |
|
|
24
|
+
| END | Append rebuttal block to `.copilot/handoff.md` | handoff-gate | Final rebuttal | [] |
|
|
25
|
+
|
|
26
|
+
## My Unique Artifact
|
|
27
|
+
|
|
28
|
+
- Appends to: `.copilot/handoff.md` (append-only, multi-writer).
|
|
29
|
+
- For new-experiment commitments, emit a back-edge signal S7 → S3 to the conductor (main session) (do not dispatch experiments directly).
|
|
30
|
+
|
|
31
|
+
## Hard Constraints
|
|
32
|
+
|
|
33
|
+
- Tone: respectful, evidence-driven, never combative.
|
|
34
|
+
- Every counter-argument must cite a specific experiments.md Run block or sections/*.tex line.
|
|
35
|
+
- Forbidden writes: `.copilot/{state,literature,ideas,experiments,decisions}.md`, `sections/*.tex`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-reviewer
|
|
3
|
+
description: "Pre-submission paper review sub-agent. Use for top-venue critical review, sanity check, logic check, claim-vs-evidence alignment, rebuttal self-check. Writes `.copilot/reviews/round-N.md`. Triggers: 'review' / 'sanity' / '审稿' / 'pre-submission check'."
|
|
4
|
+
argument-hint: "PDF or LaTeX path / review depth / venue"
|
|
5
|
+
model: opus
|
|
6
|
+
color: yellow
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Reviewer — Critical Pre-submission Review
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read target manuscript + `.copilot/{ideas,experiments,literature}.md` `__HANDOFF__` | memory-gate | Context summary | [SIMULATE_REVIEW] |
|
|
21
|
+
| SIMULATE_REVIEW | Invoke `paper-review` + `paper-sanity-check` + `paper-logic-check` skills | none | Review draft | [EXTRACT_GAPS] |
|
|
22
|
+
| EXTRACT_GAPS | Map each weakness to a back-edge target (S2 / S3 / S4) | none | Gap → back-edge map | [WRITE_ROUND] |
|
|
23
|
+
| WRITE_ROUND | Write `.copilot/reviews/round-N.md` (N auto-incremented) | none | reviews/round-N.md | [END] |
|
|
24
|
+
| END | Set `__HANDOFF__.key_facts` to list of back-edge targets | handoff-gate | Final report | [] |
|
|
25
|
+
|
|
26
|
+
## My Unique Artifact
|
|
27
|
+
|
|
28
|
+
- Writes: `.copilot/reviews/round-N.md`.
|
|
29
|
+
- `__HANDOFF__.key_facts` MUST list each weakness → suggested back-edge (e.g. "missing ablation on hyperparameter X → S3").
|
|
30
|
+
|
|
31
|
+
## Hard Constraints
|
|
32
|
+
|
|
33
|
+
- Be honest. Top-venue calibration, not vague.
|
|
34
|
+
- Cite claim-evidence mismatches by exact .tex section + experiments.md Run id.
|
|
35
|
+
- Forbidden writes: `.copilot/{state,literature,ideas,experiments,decisions}.md`, `sections/*.tex`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copilot-writer
|
|
3
|
+
description: "Paper writing sub-agent. Use to draft sections from experimental results, turn metrics into prose, expand / shorten / translate sections, write figure / table captions. Writes `sections/*.tex` and reads `.copilot/experiments.md`. Triggers: 'draft' / 'expand' / 'shorten' / 'translate' / 'caption' / '写章节'."
|
|
4
|
+
argument-hint: "Section name / target style / length budget / venue"
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: blue
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Copilot Writer — Section Drafting
|
|
10
|
+
|
|
11
|
+
**当前状态**: UNINITIALIZED
|
|
12
|
+
**状态历史**: []
|
|
13
|
+
|
|
14
|
+
Follow `self/PIPELINE-OS.md` for all shared rules.
|
|
15
|
+
|
|
16
|
+
## My Unique State Table
|
|
17
|
+
|
|
18
|
+
| 状态 | 必须完成的动作 | 能力门控 | 输出格式 | 可能的下一状态 |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| UNINITIALIZED | Read `.copilot/{ideas,experiments,literature}.md` `__HANDOFF__` | memory-gate | Context summary | [PLAN_DRAFT, EXPAND, SHORTEN, TRANSLATE, CAPTION] |
|
|
21
|
+
| PLAN_DRAFT | Outline section structure (claim → evidence → discussion) | none | Outline | [DRAFTING] |
|
|
22
|
+
| DRAFTING | Write LaTeX to `sections/<name>.tex`; cite numbers from experiments.md only | none | LaTeX diff | [REVIEW_SELF, END] |
|
|
23
|
+
| EXPAND | Expand the target text without padding (surface implicit logic) | none | LaTeX diff | [REVIEW_SELF, END] |
|
|
24
|
+
| SHORTEN | Trim 5–15 words while keeping every technical detail | none | LaTeX diff | [REVIEW_SELF, END] |
|
|
25
|
+
| TRANSLATE | Zh ↔ En translation, top-venue compliant | none | LaTeX diff | [END] |
|
|
26
|
+
| CAPTION | Produce figure / table caption (Title / Sentence case) | none | Caption block | [END] |
|
|
27
|
+
| REVIEW_SELF | Sanity-check against experiments.md (no fabricated numbers) | none | Self-review report | [END] |
|
|
28
|
+
| END | Update writer's section block in `handoff.md` (append-only) | handoff-gate | Final draft | [] |
|
|
29
|
+
|
|
30
|
+
## My Unique Artifact
|
|
31
|
+
|
|
32
|
+
- Writes: `sections/*.tex`, occasionally `references.bib` (additive only, never overwrite existing entries).
|
|
33
|
+
- Appends to: `.copilot/handoff.md` with "section drafted, key claims, where numbers came from".
|
|
34
|
+
|
|
35
|
+
## Hard Constraints
|
|
36
|
+
|
|
37
|
+
- Every numeric claim must trace to an experiments.md Run block (cite by Run id + metric name + log line).
|
|
38
|
+
- Never fabricate. Never invent a citation.
|
|
39
|
+
- Forbidden writes: `.copilot/{state,literature,ideas,experiments,decisions}.md`.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "UserPromptSubmit hook: nudge main thread to dispatch a sub-agent for execution-class prompts.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"UserPromptSubmit": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "python self/hooks/scripts/user_prompt_dispatch_reminder.py",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "PostToolUse hook: when copilot-experiment launches a long background experiment, recommend arming /loop or CronCreate so results flow back after task notification.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Bash",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "python self/hooks/scripts/post_tool_loop_armer.py",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: research-copilot-guard
|
|
3
|
+
event: PreToolUse
|
|
4
|
+
purpose: Enforcement guard for the main-session conductor
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Research Copilot Workflow Guard (Specification)
|
|
8
|
+
|
|
9
|
+
> **NOTE:** This markdown file is the *specification* for the guard's behavior.
|
|
10
|
+
> The executable implementation is `self/hooks/scripts/research_copilot_guard.py`.
|
|
11
|
+
> Registration into `.claude/settings.json` is done at install time by `self/install.py`
|
|
12
|
+
> via `register_research_copilot_guard()`. Do not hand-edit `.claude/settings.json` —
|
|
13
|
+
> re-run `python self/install.py` after changing any of these files.
|
|
14
|
+
|
|
15
|
+
## Registration
|
|
16
|
+
|
|
17
|
+
`install.py` writes a `PreToolUse` block with matcher
|
|
18
|
+
`Bash|PowerShell|Agent|Write|Edit|mcp__arxiv-search__.*|mcp__arxivsub-search__.*|mcp__google-scholar__.*|mcp__dblp-bib__.*`
|
|
19
|
+
containing:
|
|
20
|
+
|
|
21
|
+
- **Primary (only when `python` is in PATH at install time):** a `type: "command"` hook
|
|
22
|
+
invoking `python <path>/research_copilot_guard.py`. Deterministic, zero LLM cost.
|
|
23
|
+
- **Fallback (always registered):** a `type: "prompt"` hook with a conservative prompt
|
|
24
|
+
that defaults to APPROVE unless the PreToolUse payload indicates the call originates
|
|
25
|
+
from the main session AND the tool call matches an explicit violation pattern.
|
|
26
|
+
|
|
27
|
+
If Python is not available at install time, only the prompt fallback is registered.
|
|
28
|
+
|
|
29
|
+
## Active-Agent Scoping
|
|
30
|
+
|
|
31
|
+
Both layers gate on the originating agent, identified from the PreToolUse payload's
|
|
32
|
+
`agent_id` field. The guard **polices the main session by default** — the main session
|
|
33
|
+
is identified by an ABSENT `agent_id` in the payload. It **exempts `copilot-*` sub-agents**
|
|
34
|
+
(non-empty `agent_id` whose `agent_type` starts with `copilot-`), so e.g.
|
|
35
|
+
`copilot-experiment` must remain free to run training scripts. Ambiguous attribution
|
|
36
|
+
defaults to main (conservative).
|
|
37
|
+
|
|
38
|
+
## Patterns
|
|
39
|
+
|
|
40
|
+
The Python guard checks two patterns in order; first deny short-circuits the rest. Both fire only when the originating agent is the main session (conductor):
|
|
41
|
+
|
|
42
|
+
| # | Name | Tool match | When it denies |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| M1 | delegation gate | `Bash`, `PowerShell`, `Write`, `Edit`, `mcp__arxiv-search__*`, `mcp__arxivsub-search__*`, `mcp__google-scholar__*`, `mcp__dblp-bib__*` | The main session runs experiment scripts via Bash/PowerShell, calls a paper-retrieval MCP tool, or writes `sections/*.tex` / `references.bib` / `.copilot/{ideas,experiments,literature}.md` — i.e. work that belongs to a sub-agent. Writes to `.copilot/state.md` and `.copilot/decisions.md` (the conductor's own artifacts) are allowed. |
|
|
45
|
+
| M2 | task-list gate | `Agent` | The main session dispatches `Agent(copilot-*)` with zero `TaskCreate` calls in the current turn. |
|
|
46
|
+
|
|
47
|
+
Each pattern has dedicated unit-test coverage under `self/hooks/scripts/__tests__/`.
|
|
48
|
+
|
|
49
|
+
The retired sub-agent's `tools:` allowlist no longer applies; the main session has no
|
|
50
|
+
tools allowlist, so the widened PreToolUse matcher + M1 is the bottom line for blocking
|
|
51
|
+
inline MCP/experiment work.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "AI Scientist workflow guardrails: inject runtime and sandbox warnings at session start.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "python self/hooks/scripts/scientist_guardrails.py",
|
|
11
|
+
"timeout": 10
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _StringIO:
|
|
9
|
+
def __init__(self, s): self._s = s
|
|
10
|
+
def read(self): return self._s
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_should_arm_when_background_bash_with_train_command():
|
|
14
|
+
from post_tool_loop_armer import should_arm
|
|
15
|
+
event = {
|
|
16
|
+
"tool_name": "Bash",
|
|
17
|
+
"tool_input": {
|
|
18
|
+
"command": "python experiments/run/train.py --epochs 100",
|
|
19
|
+
"run_in_background": True,
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
assert should_arm(event) is True
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_should_not_arm_for_synchronous_bash():
|
|
26
|
+
from post_tool_loop_armer import should_arm
|
|
27
|
+
event = {
|
|
28
|
+
"tool_name": "Bash",
|
|
29
|
+
"tool_input": {
|
|
30
|
+
"command": "python experiments/run/train.py",
|
|
31
|
+
"run_in_background": False,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
assert should_arm(event) is False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_should_not_arm_for_non_longrun_command():
|
|
38
|
+
from post_tool_loop_armer import should_arm
|
|
39
|
+
event = {
|
|
40
|
+
"tool_name": "Bash",
|
|
41
|
+
"tool_input": {
|
|
42
|
+
"command": "ls .copilot/",
|
|
43
|
+
"run_in_background": True,
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
assert should_arm(event) is False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_should_not_arm_for_non_bash_tool():
|
|
50
|
+
from post_tool_loop_armer import should_arm
|
|
51
|
+
event = {
|
|
52
|
+
"tool_name": "Read",
|
|
53
|
+
"tool_input": {"file_path": "x.py"},
|
|
54
|
+
}
|
|
55
|
+
assert should_arm(event) is False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_main_skips_when_already_armed(tmp_path, monkeypatch, capsys):
|
|
59
|
+
copilot = tmp_path / ".copilot"
|
|
60
|
+
copilot.mkdir()
|
|
61
|
+
(copilot / ".loop-armed").write_text("", encoding="utf-8")
|
|
62
|
+
monkeypatch.chdir(tmp_path)
|
|
63
|
+
event = {
|
|
64
|
+
"tool_name": "Bash",
|
|
65
|
+
"tool_input": {"command": "python train.py", "run_in_background": True},
|
|
66
|
+
}
|
|
67
|
+
monkeypatch.setattr("sys.stdin", _StringIO(json.dumps(event)))
|
|
68
|
+
from post_tool_loop_armer import main
|
|
69
|
+
rc = main()
|
|
70
|
+
assert rc == 0
|
|
71
|
+
assert capsys.readouterr().out == ""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_main_prints_suggestion_and_marks_armed(tmp_path, monkeypatch, capsys):
|
|
75
|
+
(tmp_path / ".copilot").mkdir()
|
|
76
|
+
monkeypatch.chdir(tmp_path)
|
|
77
|
+
event = {
|
|
78
|
+
"tool_name": "Bash",
|
|
79
|
+
"tool_input": {"command": "python experiments/run/train.py", "run_in_background": True},
|
|
80
|
+
}
|
|
81
|
+
monkeypatch.setattr("sys.stdin", _StringIO(json.dumps(event)))
|
|
82
|
+
from post_tool_loop_armer import main
|
|
83
|
+
rc = main()
|
|
84
|
+
assert rc == 0
|
|
85
|
+
out = capsys.readouterr().out
|
|
86
|
+
assert "[loop-armer]" in out
|
|
87
|
+
assert "CronCreate" in out or "/loop" in out
|
|
88
|
+
assert (tmp_path / ".copilot" / ".loop-armed").exists()
|