opencode-autoresearch 3.3.1 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,24 @@
1
1
  import { VERSION, PACKAGE_NAME, PRODUCT_BRAND, SKILL_NAME } from "./constants.js";
2
2
  export declare const id = "autoresearch";
3
3
  export declare const repoRoot: string;
4
- export declare const version = "3.3.1";
4
+ export declare const version = "3.4.1";
5
+ type OpenCodeConfig = {
6
+ command?: Record<string, {
7
+ template: string;
8
+ }>;
9
+ skills?: {
10
+ paths?: string[];
11
+ };
12
+ };
13
+ export declare function server(): Promise<{
14
+ config(config: OpenCodeConfig): void;
15
+ event(): undefined;
16
+ }>;
17
+ declare const _default: {
18
+ id: string;
19
+ server: typeof server;
20
+ };
21
+ export default _default;
5
22
  export { VERSION, PACKAGE_NAME, PRODUCT_BRAND, SKILL_NAME };
6
23
  export type { RunConfig, WizardConfig, Metric, RunStats, RunFlags, LastIteration, RunState, SupervisorSnapshot, LabelRequirements, ArtifactPaths, } from "./types.js";
7
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,UAAU,EACX,MAAM,gBAAgB,CAAC;AAIxB,eAAO,MAAM,EAAE,iBAAa,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAA2B,CAAC;AACjD,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;AAC5D,YAAY,EACV,SAAS,EACT,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,UAAU,EACX,MAAM,gBAAgB,CAAC;AAIxB,eAAO,MAAM,EAAE,iBAAa,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAA2B,CAAC;AACjD,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,KAAK,cAAc,GAAG;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC/B,CAAC;AA4BF,wBAAsB,MAAM;mBAET,cAAc;;GAqBhC;;;;;AAED,wBAA8B;AAE9B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;AAC5D,YAAY,EACV,SAAS,EACT,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,9 +1,54 @@
1
- import { dirname, resolve } from "path";
1
+ import { readFileSync } from "fs";
2
+ import { dirname, join, relative, resolve, sep } from "path";
2
3
  import { fileURLToPath } from "url";
3
4
  import { VERSION, PACKAGE_NAME, PRODUCT_BRAND, SKILL_NAME, } from "./constants.js";
4
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
5
6
  export const id = SKILL_NAME;
6
7
  export const repoRoot = resolve(__dirname, "..");
7
8
  export const version = VERSION;
9
+ function commandNameForPath(filePath) {
10
+ const relativePath = relative(join(repoRoot, "commands"), filePath);
11
+ return relativePath.replace(/\.md$/, "").split(sep).join(":");
12
+ }
13
+ function pathForTemplate(filePath) {
14
+ return filePath.split(sep).join("/");
15
+ }
16
+ function anchorTrustedSkillReferences(template) {
17
+ const trustedSkillBundlePath = pathForTemplate(join(repoRoot, "skills", SKILL_NAME));
18
+ return template.replaceAll(`skills/${SKILL_NAME}/`, `${trustedSkillBundlePath}/`);
19
+ }
20
+ const commandFiles = [
21
+ "commands/autoresearch.md",
22
+ "commands/autoresearch/plan.md",
23
+ "commands/autoresearch/debug.md",
24
+ "commands/autoresearch/fix.md",
25
+ "commands/autoresearch/learn.md",
26
+ "commands/autoresearch/predict.md",
27
+ "commands/autoresearch/scenario.md",
28
+ "commands/autoresearch/security.md",
29
+ "commands/autoresearch/ship.md",
30
+ ];
31
+ export async function server() {
32
+ return {
33
+ config(config) {
34
+ config.command = config.command || {};
35
+ config.skills = config.skills || {};
36
+ config.skills.paths = config.skills.paths || [];
37
+ if (!config.skills.paths.includes(repoRoot)) {
38
+ config.skills.paths.push(repoRoot);
39
+ }
40
+ for (const commandFile of commandFiles) {
41
+ const filePath = join(repoRoot, commandFile);
42
+ config.command[commandNameForPath(filePath)] ??= {
43
+ template: anchorTrustedSkillReferences(readFileSync(filePath, "utf8").trim()),
44
+ };
45
+ }
46
+ },
47
+ event() {
48
+ return undefined;
49
+ },
50
+ };
51
+ }
52
+ export default { id, server };
8
53
  export { VERSION, PACKAGE_NAME, PRODUCT_BRAND, SKILL_NAME };
9
54
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;AAC7B,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;AAC7B,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAO/B,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,OAAO,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,4BAA4B,CAAC,QAAgB;IACpD,MAAM,sBAAsB,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IACrF,OAAO,QAAQ,CAAC,UAAU,CAAC,UAAU,UAAU,GAAG,EAAE,GAAG,sBAAsB,GAAG,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,YAAY,GAAG;IACnB,0BAA0B;IAC1B,+BAA+B;IAC/B,gCAAgC;IAChC,8BAA8B;IAC9B,gCAAgC;IAChC,kCAAkC;IAClC,mCAAmC;IACnC,mCAAmC;IACnC,+BAA+B;CAChC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,OAAO;QACL,MAAM,CAAC,MAAsB;YAC3B,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;YACtC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAEhD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,CAAC;YAED,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;gBAC7C,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,KAAK;oBAC/C,QAAQ,EAAE,4BAA4B,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;iBAC9E,CAAC;YACJ,CAAC;QACH,CAAC;QAED,KAAK;YACH,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAY/C,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiDzB"}
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAY/C,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkDzB"}
package/dist/wizard.js CHANGED
@@ -2,7 +2,8 @@ import { basename } from "path";
2
2
  import { resolveRepo, normalizeDirection, normalizeMode, parseDurationSeconds, normalizeLabels, inferVerifyCommand, } from "./helpers.js";
3
3
  import { buildSubagentPoolPlan, buildContinuationPolicy } from "./subagent-pool.js";
4
4
  export function buildSetupSummary(repo, config) {
5
- const verify = config.verify ?? inferVerifyCommand(repo);
5
+ const explicitVerify = config.verify?.trim();
6
+ const verify = explicitVerify || inferVerifyCommand(repo);
6
7
  const direction = normalizeDirection(config.direction);
7
8
  const mode = normalizeMode(config.mode);
8
9
  const durationSeconds = parseDurationSeconds(config.duration);
@@ -16,7 +17,7 @@ export function buildSetupSummary(repo, config) {
16
17
  const missingRequired = [];
17
18
  if (!config.goal)
18
19
  missingRequired.push("goal");
19
- if (verify === "<set verify command>")
20
+ if (!explicitVerify)
20
21
  missingRequired.push("verify");
21
22
  const stopReasons = [];
22
23
  if (verify !== "<set verify command>") {
@@ -29,7 +30,7 @@ export function buildSetupSummary(repo, config) {
29
30
  const questions = [];
30
31
  if (!config.goal)
31
32
  questions.push({ id: "goal", prompt: "What outcome should this run optimize for?", reason: "The loop needs one concrete result to chase." });
32
- if (!config.verify)
33
+ if (!explicitVerify)
33
34
  questions.push({ id: "verify", prompt: "What command should mechanically verify the metric?", reason: "The loop should not keep changes on intuition alone." });
34
35
  if (!config.mode)
35
36
  questions.push({ id: "mode", prompt: "Should the run stay in `foreground` or move to `background`?", reason: "The skill requires an explicit run-mode choice." });
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.js","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wizard.js","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,17 @@
1
1
  # Auto Research Architecture
2
2
 
3
- > Current reference for v3.3.0.
3
+ > Current reference for v3.3.3.
4
4
 
5
- Auto Research is an OpenCode-only npm package with recursive self-improvement capabilities. The runtime is Node.js ESM. All workflow semantics are preserved from earlier releases.
5
+ Auto Research is a multi-runtime npm package with recursive self-improvement capabilities. The runtime is Node.js ESM. All workflow semantics are preserved from earlier releases.
6
+
7
+ ## Supported Runtimes
8
+
9
+ | Runtime | Entry | Subagent Model | Background Mode |
10
+ |---------|-------|----------------|-----------------|
11
+ | OpenCode | `/autoresearch` slash commands | Standing pool (unlimited) | `autoresearch launch` |
12
+ | Hermes Agent | Cronjob + `delegate_task` | Batch pool (max 3) | Native cron |
13
+
14
+ Both runtimes share the same state format, CLI, and artifact paths.
6
15
 
7
16
  ## Package Layout
8
17
 
@@ -19,15 +28,22 @@ commands/autoresearch.md # Main command
19
28
  commands/autoresearch/*.md # Mode commands (plan, debug, fix, learn, etc.)
20
29
  skills/autoresearch/ # OpenCode skill bundle
21
30
  skills/autoresearch/references/# Workflow and runtime references
31
+ skills/hermes/ # Hermes Agent skill bundle
32
+ README.md # Hermes setup and usage
33
+ INTEGRATION.md # Architecture and command mapping
34
+ autoresearch-prompt.md # Cron prompt template
22
35
  hooks/init.sh # SessionStart hook
23
36
  hooks/status.sh # Status hook
24
37
  hooks/stop.sh # Stop hook
25
38
  hooks/verify-package.sh # Package verification
39
+ INSTALL.md # Public raw install handoff (both runtimes)
40
+ .opencode/INSTALL.md # OpenCode native plugin install guide
26
41
  docs/OPENCODE_INSTALL.md # OpenCode install guide
27
42
  docs/ARCHITECTURE.md # This document
28
43
  docs/RELEASE.md # Release process
29
44
  plugins/autoresearch.ts # OpenCode plugin entry point
30
45
  .opencode-plugin/plugin.json # OpenCode plugin manifest
46
+ AGENTS.md # Repository-specific agent guide
31
47
  .autoresearch/ # Runtime state directory (created at runtime)
32
48
  ```
33
49
 
@@ -36,15 +52,16 @@ plugins/autoresearch.ts # OpenCode plugin entry point
36
52
  ```mermaid
37
53
  flowchart LR
38
54
  A[OpenCode /autoresearch] --> B[CLI]
55
+ H[Hermes Cronjob] --> B
39
56
  B --> C[Run Manager]
40
57
  C --> D[State JSON]
41
58
  C --> E[Results TSV]
42
59
  C --> F[Subagent Pool]
43
60
  F --> G[Orchestrator]
44
- F --> H[Scout]
45
- F --> I[Analyst]
46
- F --> J[Verifier]
47
- F --> K[Synthesizer]
61
+ F --> I[Scout]
62
+ F --> J[Analyst]
63
+ F --> K[Verifier]
64
+ F --> L[Synthesizer]
48
65
  ```
49
66
 
50
67
  ## Core Loop
@@ -52,7 +69,7 @@ flowchart LR
52
69
  ```mermaid
53
70
  flowchart TD
54
71
  A[Goal + Metric + Verify] --> B[Baseline]
55
- B --> C[Standing Pool Init]
72
+ B --> C[Pool Init]
56
73
  C --> D[Iteration N]
57
74
  D --> E[Subagent Context]
58
75
  E --> F[Focused Change]
@@ -85,7 +102,7 @@ flowchart TD
85
102
 
86
103
  ## Source of Truth
87
104
 
88
- `src/` is authoritative for runtime behavior. `commands/` and `skills/` define the OpenCode surfaces.
105
+ `src/` is authoritative for runtime behavior. `commands/` and `skills/autoresearch/` define the OpenCode surfaces. `skills/hermes/` defines the Hermes Agent surface.
89
106
 
90
107
  ## Runtime Artifacts
91
108
 
@@ -100,6 +117,8 @@ flowchart TD
100
117
 
101
118
  ## Command Surface
102
119
 
120
+ ### OpenCode
121
+
103
122
  | Command | Workflow |
104
123
  | --- | --- |
105
124
  | `/autoresearch` | Default improve-verify loop |
@@ -112,6 +131,21 @@ flowchart TD
112
131
  | `/autoresearch:security` | Security review |
113
132
  | `/autoresearch:ship` | Ship-readiness workflow |
114
133
 
134
+ ### Hermes
135
+
136
+ | OpenCode Command | Hermes Equivalent |
137
+ |-----------------|-------------------|
138
+ | `/autoresearch` | Cron runs iteration loop |
139
+ | `/autoresearch:plan` | Subagent task: plan experiments |
140
+ | `/autoresearch:debug` | Subagent task: debug failures |
141
+ | `/autoresearch:fix` | Subagent task: fix issues |
142
+ | `/autoresearch:learn` | Memory tool + pattern analysis |
143
+ | `autoresearch init` | Manual setup (same CLI) |
144
+ | `autoresearch status` | `cat .autoresearch/state.json` |
145
+ | `autoresearch launch` | `hermes cron create` |
146
+ | `autoresearch stop` | `hermes cron pause` |
147
+ | `autoresearch resume` | `hermes cron resume` |
148
+
115
149
  ## CLI Commands
116
150
 
117
151
  | Command | Purpose |
@@ -158,6 +192,15 @@ The standing pool provides:
158
192
  | `research_tracker` | Pattern tracking across iterations |
159
193
  | `meta_orchestrator` | Owns meta-goal and child loop decisions (self-improvement) |
160
194
 
195
+ ### Runtime Differences
196
+
197
+ | Feature | OpenCode | Hermes |
198
+ |---------|----------|--------|
199
+ | Pool type | Standing (persistent across iterations) | Batch (spawned per phase) |
200
+ | Max concurrent | Unlimited | 3 (Hermes limit) |
201
+ | Real-time | Yes | 15-minute cron intervals |
202
+ | Memory | File-based | `memory` tool + file |
203
+
161
204
  ## Validation
162
205
 
163
206
  1. `npm run typecheck` — TypeScript strict checks.
@@ -191,5 +234,6 @@ The release workflow is automated via GitHub Actions:
191
234
  - State is now in `.autoresearch/state.json` (was `autoresearch-state.json` at root).
192
235
  - Runtime helpers are TypeScript (`src/helpers.ts`) not Python.
193
236
  - Plugin format is `.opencode-plugin/plugin.json`.
194
- - The Claude and Codex plugin bundles (`plugins/autoresearch/`, `plugins/codex-autoresearch/`) are no longer shipped.
237
+ - Legacy plugin bundles are no longer shipped.
195
238
  - Self-improvement loop added in v3.2.0.
239
+ - Hermes Agent support added in v3.3.3.
@@ -1,48 +1,109 @@
1
1
  # OpenCode Install
2
2
 
3
- Install `opencode-autoresearch` as a global npm package.
3
+ For the public raw install handoff, see [`../INSTALL.md`](../INSTALL.md).
4
4
 
5
- ## Install
5
+ ## Recommended: OpenCode Plugin Install
6
6
 
7
- ```bash
8
- npm install -g opencode-autoresearch
7
+ Add Auto Research to the `plugin` array in your global or project-level `opencode.json`:
8
+
9
+ ```json
10
+ {
11
+ "plugin": ["opencode-autoresearch@latest"]
12
+ }
9
13
  ```
10
14
 
15
+ Restart OpenCode. OpenCode installs npm plugins automatically at startup.
16
+
11
17
  ## Verify Installation
12
18
 
19
+ Start the setup wizard inside OpenCode:
20
+
21
+ ```text
22
+ /autoresearch
23
+ ```
24
+
25
+ ## Optional: Global CLI Install
26
+
13
27
  ```bash
28
+ npm install -g opencode-autoresearch
14
29
  opencode-autoresearch doctor
15
30
  ```
16
31
 
17
- Should print the package version and confirm the plugin surfaces are in place.
32
+ For one-time CLI use:
33
+
34
+ ```bash
35
+ npx opencode-autoresearch doctor
36
+ ```
18
37
 
19
- ## OpenCode Plugin Registration
38
+ ## OpenCode Commands
20
39
 
21
- After install, the plugin is available as `autoresearch`:
40
+ | Command | Purpose |
41
+ | --- | --- |
42
+ | `/autoresearch` | Run the main improve-verify loop |
43
+ | `/autoresearch:plan` | Planning workflow |
44
+ | `/autoresearch:debug` | Debugging workflow |
45
+ | `/autoresearch:fix` | Fix workflow |
46
+ | `/autoresearch:learn` | Learning workflow |
47
+ | `/autoresearch:predict` | Prediction workflow |
48
+ | `/autoresearch:scenario` | Scenario expansion |
49
+ | `/autoresearch:security` | Security review |
50
+ | `/autoresearch:ship` | Ship-readiness workflow |
22
51
 
23
- - `/autoresearch` Run the main improve-verify loop
24
- - `/autoresearch:plan` — Planning workflow
25
- - `/autoresearch:debug` Debugging workflow
26
- - `/autoresearch:fix` — Fix workflow
27
- - `/autoresearch:learn` Learning workflow
28
- - `/autoresearch:predict` — Prediction workflow
29
- - `/autoresearch:scenario` Scenario expansion
30
- - `/autoresearch:security` Security review
31
- - `/autoresearch:ship` Ship-readiness workflow
52
+ ## Hermes Agent Commands
53
+
54
+ Hermes uses cronjobs and `delegate_task` instead of slash commands. See [`../skills/hermes/INTEGRATION.md`](../skills/hermes/INTEGRATION.md) for the full command mapping.
55
+
56
+ | OpenCode Command | Hermes Equivalent |
57
+ |-----------------|-------------------|
58
+ | `/autoresearch` | Cron runs iteration loop |
59
+ | `/autoresearch:plan` | Subagent task: plan experiments |
60
+ | `/autoresearch:debug` | Subagent task: debug failures |
61
+ | `/autoresearch:fix` | Subagent task: fix issues |
62
+ | `/autoresearch:learn` | Memory tool + pattern analysis |
63
+ | `autoresearch init` | Manual setup (same CLI) |
64
+ | `autoresearch status` | `cat .autoresearch/state.json` |
65
+ | `autoresearch launch` | `hermes cron create` |
66
+ | `autoresearch stop` | `hermes cron pause` |
67
+ | `autoresearch resume` | `hermes cron resume` |
32
68
 
33
69
  ## Runtime Artifacts
34
70
 
35
- After install, artifacts are stored in `.autoresearch/` under the working directory:
71
+ Artifacts are stored under the working directory:
36
72
 
37
73
  | Artifact | Purpose |
38
74
  | --- | --- |
39
75
  | `.autoresearch/state.json` | Current run state |
76
+ | `.autoresearch/launch.json` | Background launch manifest |
40
77
  | `autoresearch-results.tsv` | Iteration log |
41
78
  | `autoresearch-report.md` | End-of-run report |
42
79
  | `autoresearch-memory.md` | Reusable memory |
43
80
 
44
- ## Uninstall
81
+ ## Updating
82
+
83
+ The `opencode-autoresearch@latest` plugin entry follows the current npm `latest` release. Restart OpenCode after a new Auto Research package release is available. To pin a fixed version instead:
84
+
85
+ ```json
86
+ {
87
+ "plugin": ["opencode-autoresearch@3.3.4"]
88
+ }
89
+ ```
90
+
91
+ ## Troubleshooting
92
+
93
+ ### Plugin not loading
94
+
95
+ 1. Verify `opencode.json` uses `"plugin": ["opencode-autoresearch@latest"]`.
96
+ 2. Restart OpenCode after editing config.
97
+ 3. Check logs with `opencode run --print-logs "hello"`.
98
+
99
+ ### CLI not found
100
+
101
+ 1. Run `npm install -g opencode-autoresearch`.
102
+ 2. Verify your npm global bin directory is on `PATH`.
103
+ 3. Run `opencode-autoresearch doctor`.
104
+
105
+ ## Uninstall CLI
45
106
 
46
107
  ```bash
47
108
  npm uninstall -g opencode-autoresearch
48
- ```
109
+ ```
@@ -2,11 +2,33 @@
2
2
 
3
3
  ## Installation
4
4
 
5
+ ### OpenCode
6
+
5
7
  ```bash
6
8
  npm install -g opencode-autoresearch
7
9
  autoresearch doctor
8
10
  ```
9
11
 
12
+ ### Hermes Agent
13
+
14
+ ```bash
15
+ # 1. Install the skill
16
+ git clone https://github.com/Maleick/AutoResearch.git
17
+ cd AutoResearch
18
+ npm install
19
+ mkdir -p ~/.hermes/skills/software-development/autoresearch
20
+ cp skills/hermes/autoresearch-prompt.md ~/.hermes/skills/software-development/autoresearch/SKILL.md
21
+ cp skills/hermes/INTEGRATION.md ~/.hermes/skills/software-development/autoresearch/REFERENCES.md
22
+
23
+ # 2. Create a cronjob
24
+ hermes cron create \
25
+ --name "autoresearch-loop" \
26
+ --workdir ~/projects/AutoResearch \
27
+ --skill autoresearch-hermes \
28
+ "every 15m" \
29
+ "Run AutoResearch iteration loop. Detect phase from .autoresearch/state.json and execute one phase. Approved verify command: 'npm run test:coverage'. Approved guard command: 'npm run typecheck'."
30
+ ```
31
+
10
32
  ## Basic Usage
11
33
 
12
34
  ### 1. Initialize a run
@@ -66,6 +88,26 @@ autoresearch launch
66
88
  autoresearch status
67
89
  ```
68
90
 
91
+ ### Hermes Background Runs
92
+
93
+ ```bash
94
+ # Initialize state from a trusted shell before enabling unattended cron
95
+ autoresearch init \
96
+ --goal "Improve test coverage" \
97
+ --metric "coverage_pct" \
98
+ --direction "higher" \
99
+ --verify "npm run test:coverage" \
100
+ --guard "npm run typecheck" \
101
+ --iterations 20 \
102
+ --mode background
103
+
104
+ # Start cron
105
+ hermes cron resume autoresearch-loop
106
+
107
+ # Check progress
108
+ cat .autoresearch/state.json | jq .
109
+ ```
110
+
69
111
  ## Self-Improvement
70
112
 
71
113
  Run AutoResearch on itself:
package/docs/RELEASE.md CHANGED
@@ -4,7 +4,7 @@ This package uses npm publish for releases. GitHub Actions automates the full re
4
4
 
5
5
  ## Version Alignment
6
6
 
7
- `VERSION`, `package.json`, `src/constants.ts`, and `.opencode-plugin/plugin.json` must all stay aligned. The `VERSION` file is the canonical source of truth.
7
+ `VERSION`, `package.json`, `package-lock.json`, `src/constants.ts`, and `.opencode-plugin/plugin.json` must all stay aligned. The `VERSION` file is the canonical source of truth.
8
8
 
9
9
  ## Release Steps
10
10
 
@@ -12,10 +12,10 @@ This package uses npm publish for releases. GitHub Actions automates the full re
12
12
 
13
13
  ```bash
14
14
  # Update VERSION file
15
- echo "3.2.0" > VERSION
15
+ echo "3.3.3" > VERSION
16
16
 
17
17
  # Sync to package.json
18
- npm version 3.2.0 --no-git-tag-version
18
+ npm version 3.3.3 --no-git-tag-version
19
19
 
20
20
  # Sync to src/constants.ts
21
21
  # Update the VERSION export manually or use sed
@@ -36,25 +36,24 @@ npm test
36
36
  Add a new section for the version in `CHANGELOG.md`:
37
37
 
38
38
  ```markdown
39
- ## [3.2.0] - YYYY-MM-DD
39
+ ## [3.3.3] - YYYY-MM-DD
40
40
 
41
41
  ### Added
42
- - Recursive self-improvement loop support
43
- - Mermaid diagrams in documentation
44
- - Enhanced subagent pool with meta-orchestrator role
42
+ - Root install handoff
43
+ - Public install verification notes
45
44
 
46
45
  ### Changed
47
- - Updated README with banner and visual diagrams
48
- - Improved wiki pages with architecture charts
46
+ - Installation docs
47
+ - Package verification allowlist
49
48
  ```
50
49
 
51
50
  ### 4. Commit and tag
52
51
 
53
52
  ```bash
54
53
  git add -A
55
- git commit -m "Release v3.2.0"
56
- git tag v3.2.0
57
- git push origin main v3.2.0
54
+ git commit -m "Release v3.3.3"
55
+ git tag v3.3.3
56
+ git push origin main v3.3.3
58
57
  ```
59
58
 
60
59
  ### 5. Automated release
@@ -64,8 +63,8 @@ GitHub Actions will:
64
63
  1. Build and type-check
65
64
  2. Verify package contents
66
65
  3. Run tests
67
- 4. Create a GitHub Release with CHANGELOG section
68
- 5. Publish to npm
66
+ 4. Create a GitHub Release with the CHANGELOG section
67
+ 5. Publish to npm with provenance through trusted publishing
69
68
 
70
69
  ## Manual publish (fallback)
71
70
 
@@ -86,7 +85,9 @@ The shipped package includes:
86
85
  - `commands/` — OpenCode command surfaces (`autoresearch.md`, `autoresearch/*.md`)
87
86
  - `skills/autoresearch/` — Skill bundle with references
88
87
  - `hooks/` — Shell hooks for session lifecycle
89
- - `docs/` — Installation, architecture, and release docs
88
+ - selected `docs/` files `ARCHITECTURE.md`, `OPENCODE_INSTALL.md`, `QUICKSTART.md`, `RELEASE.md`, documentation site assets, and `CNAME`
89
+ - `INSTALL.md` — Public raw OpenCode install handoff
90
+ - `.opencode/INSTALL.md` — OpenCode native plugin install guide
90
91
  - `.opencode-plugin/plugin.json` — OpenCode plugin manifest
91
92
  - `AGENTS.md` — Agent guide
92
93
  - `VERSION` — Version marker
package/hooks/status.sh CHANGED
@@ -7,18 +7,20 @@ set -e
7
7
  STATUS_FILE="${AUTORESEARCH_STATE:-.autoresearch/state.json}"
8
8
 
9
9
  if [ -f "$STATUS_FILE" ]; then
10
- node --input-type=module -e "
11
- import { readFileSync } from 'fs';
12
- const s = JSON.parse(readFileSync('$STATUS_FILE', 'utf8'));
13
- console.log('Auto Research run: ' + s.run_id);
14
- console.log('Status: ' + s.status);
15
- console.log('Mode: ' + s.mode);
16
- console.log('Goal: ' + s.goal);
17
- console.log('Iterations: ' + s.stats.total_iterations);
18
- console.log('Kept: ' + s.stats.kept + ' | Discarded: ' + s.stats.discarded);
19
- if (s.flags.needs_human) console.log('NEEDS HUMAN');
20
- if (s.flags.stop_requested) console.log('STOP REQUESTED');
21
- " 2>/dev/null || echo "No active run."
10
+ AUTORESEARCH_STATUS_FILE="$STATUS_FILE" node --input-type=module -e '
11
+ import { readFileSync } from "fs";
12
+ const statusFile = process.env.AUTORESEARCH_STATUS_FILE;
13
+ if (!statusFile) throw new Error("Missing AUTORESEARCH_STATUS_FILE");
14
+ const s = JSON.parse(readFileSync(statusFile, "utf8"));
15
+ console.log("Auto Research run: " + s.run_id);
16
+ console.log("Status: " + s.status);
17
+ console.log("Mode: " + s.mode);
18
+ console.log("Goal: " + s.goal);
19
+ console.log("Iterations: " + s.stats.total_iterations);
20
+ console.log("Kept: " + s.stats.kept + " | Discarded: " + s.stats.discarded);
21
+ if (s.flags.needs_human) console.log("NEEDS HUMAN");
22
+ if (s.flags.stop_requested) console.log("STOP REQUESTED");
23
+ ' 2>/dev/null || echo "No active run."
22
24
  else
23
25
  echo "No active run."
24
26
  fi
package/hooks/stop.sh CHANGED
@@ -5,24 +5,58 @@
5
5
  set -e
6
6
 
7
7
  STATUS_FILE="${AUTORESEARCH_STATE:-.autoresearch/state.json}"
8
+ WORKSPACE_ROOT="$(pwd -P)"
8
9
 
9
- if [ -f "$STATUS_FILE" ]; then
10
- mode=$(node --input-type=module -e "
11
- import { readFileSync } from 'fs';
12
- const s = JSON.parse(readFileSync('$STATUS_FILE', 'utf8'));
13
- console.log(s.mode || '');
14
- " 2>/dev/null || true)
10
+ case "$STATUS_FILE" in
11
+ /*) STATUS_FILE_ABS="$STATUS_FILE" ;;
12
+ *) STATUS_FILE_ABS="$WORKSPACE_ROOT/$STATUS_FILE" ;;
13
+ esac
14
+
15
+ if [ -L "$STATUS_FILE_ABS" ]; then
16
+ echo "Refusing symlinked state file."
17
+ exit 0
18
+ fi
19
+
20
+ STATUS_DIR="${STATUS_FILE_ABS%/*}"
21
+ STATUS_NAME="${STATUS_FILE_ABS##*/}"
22
+ STATUS_DIR_REAL="$(cd "$STATUS_DIR" 2>/dev/null && pwd -P)" || {
23
+ echo "No active run."
24
+ exit 0
25
+ }
26
+ STATUS_FILE_REAL="$STATUS_DIR_REAL/$STATUS_NAME"
27
+ WORKSPACE_STATE_DIR="$WORKSPACE_ROOT/.autoresearch"
28
+
29
+ case "$STATUS_FILE_REAL" in
30
+ "$WORKSPACE_STATE_DIR"/*) ;;
31
+ *)
32
+ echo "Refusing state file outside workspace."
33
+ exit 0
34
+ ;;
35
+ esac
36
+
37
+ if [ -f "$STATUS_FILE_ABS" ]; then
38
+ mode=$(AUTORESEARCH_STATUS_FILE="$STATUS_FILE_ABS" node --input-type=module -e '
39
+ import { readFileSync } from "fs";
40
+ const statusFile = process.env.AUTORESEARCH_STATUS_FILE;
41
+ if (!statusFile) throw new Error("Missing AUTORESEARCH_STATUS_FILE");
42
+ const s = JSON.parse(readFileSync(statusFile, "utf8"));
43
+ console.log(s.mode || "");
44
+ ' 2>/dev/null || true)
15
45
  if [ "$mode" = "background" ]; then
16
- node --input-type=module -e "
17
- import { readFileSync, writeFileSync } from 'fs';
18
- const s = JSON.parse(readFileSync('$STATUS_FILE', 'utf8'));
46
+ AUTORESEARCH_STATUS_FILE="$STATUS_FILE_ABS" node --input-type=module -e '
47
+ import { readFileSync, renameSync, writeFileSync } from "fs";
48
+ const statusFile = process.env.AUTORESEARCH_STATUS_FILE;
49
+ if (!statusFile) throw new Error("Missing AUTORESEARCH_STATUS_FILE");
50
+ const s = JSON.parse(readFileSync(statusFile, "utf8"));
19
51
  s.updated_at = new Date().toISOString();
20
52
  s.flags.stop_requested = true;
21
53
  s.flags.background_active = false;
22
- s.status = 'stopping';
23
- writeFileSync('$STATUS_FILE', JSON.stringify(s, null, 2) + '\n');
24
- console.log('Stop requested for run: ' + s.run_id);
25
- " 2>/dev/null || echo "Could not update state."
54
+ s.status = "stopping";
55
+ const tmp = `${statusFile}.tmp.${process.pid}`;
56
+ writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n", { mode: 0o600 });
57
+ renameSync(tmp, statusFile);
58
+ console.log("Stop requested for run: " + s.run_id);
59
+ ' 2>/dev/null || echo "Could not update state."
26
60
  else
27
61
  echo "Only background runs can be stopped."
28
62
  fi