@master0071/dsh-autoresearch 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # dsh-autoresearch
2
+
3
+ 自主实验循环:**试一个想法 → 测量 → 留下改进、回退回归 → 重复**。适用于任何可量化指标的优化目标(测试耗时、bundle 体积、构建时间、Lighthouse 分数)。移植自 [pi-autoresearch](https://github.com/davebcn87/pi-autoresearch)(Pi 生态 7825★,源自 [karpathy/autoresearch](https://github.com/karpathy/autoresearch))。
4
+
5
+ **状态:v0.1.5 已发布**(npm 包名:`@master0071/dsh-autoresearch`;另见 [CHANGELOG](CHANGELOG.md))。注意:无作用域包名 `dsh-autoresearch` 已被其他作者占用,故本仓库以作用域包名发布,并同步以 `docs/packages/*.tgz` + git tag 分发。工具面与终端仪表盘已完备;Web 仪表盘与外层循环驱动器见 §里程碑。
6
+
7
+ ## 为什么做
8
+
9
+ - DSH Get 查重(2026-08-24 快照,3496 个插件):`experiment loop`、`benchmark optimization` 均 0 命中,`autoresearch` 仅 1 个无关技能包——完全空白。
10
+ - Pi 侧 7825 星验证了需求;DSH 侧积木齐全(`tool-ralph`、jobs、goal、subprocess),缺的只是产品封装。
11
+
12
+ ## 设计
13
+
14
+ 持久状态在 `<workspace>/.auto/`:`prompt.md`(本次优化会话的章程:目标、指标、方向)+ `log.jsonl`(只追加的实验史,永不改写)。
15
+
16
+ 单 dispatch 工具 `autoresearch`,支持五个动作:
17
+
18
+ | action | 做什么 |
19
+ |---|---|
20
+ | `init` | 写会话章程:名称、指标、单位、方向(越大越好/越小越好);生成含协议规则的结构化章程模板(0.1.3) |
21
+ | `run` | 执行任意命令,计 wall-clock,留有界输出(支持配置 `shell`) |
22
+ | `log` | 记录结果,自动提交 `.auto` 留存,判定 keep/revert(支持 `autoRevert`) |
23
+ | `status` | 汇报 best/worst/趋势(支持 `format: 'trend'` / `'table'` / `'full'` 渲染终端报表) |
24
+ | `revert` | 显式一键回退工作区改动至基线(排除 `.auto/`) |
25
+
26
+ 关键取舍:
27
+
28
+ - **留优回退靠 git**:每条实验自动 commit `.auto`,改进保留、回归支持通过 `autoRevert: true` 或 `action: revert` 自动恢复工作区代码——审计链完整,不发明自己的存储。
29
+ - **单工具 + action 分发**:五个动词一个工具,控制每请求 schema 预算。
30
+ - **实验命令走 `ctx.subprocess`**,支持指定 shell(pwsh/cmd/bash 等),共享沙箱策略,不自建执行器。
31
+
32
+ - **动态上下文注入(0.1.3)**:宿主提供 `systemPrompt` 服务时,自动向模型上下文挂载 `autoresearch:status` 状态快照(轮数/最优值),模型无需显式调 `status` 即可感知进度。
33
+
34
+ - **外层循环可选骑 `tool-ralph`**(DSH 官方的认知循环工具),本插件只管实验记录与留存——关注点分离。
35
+
36
+ ## 配置
37
+
38
+ 见 [cordis.patch.yml](cordis.patch.yml),字段与默认值与 `src/index.ts` 的 `Config` 一一对应。
39
+
40
+ ## 里程碑
41
+
42
+ - **M1 log 核心** ✅(0.1.0):log.jsonl 追加器 + best/worst 追踪 + commit 留存路径。
43
+ - **M2 run** ✅(0.1.0):subprocess 执行 + 计时 + 有界输出留存 + 超时(0.1.2 起支持配置 `shell`)。
44
+ - **M3 工具注册** ✅(0.1.0):单 dispatch 工具全动作接线(init/run/log/status/revert)。
45
+ - **M4 循环与面板** ◐:终端 ASCII 趋势图与报表 ✅(0.1.3,`status format: 'trend'/'table'/'full'`);`/autoresearch` 循环命令、ralph 挂载与 Web 仪表盘待实施。
46
+
47
+ 每步先 `npm run typecheck`,行为验收走真实 `dsh --patch` 会话。
48
+
49
+ ## 运行数据与审计
50
+
51
+ 控制面事件写入 JSONL 台账(默认 `~/.dsh-autoresearch/traces.jsonl`,`tracePath` 可配,超限自动轮转到 `.1`);实验数据本体在 `<workspace>/.auto/log.jsonl`(append-only,永不改写):
52
+
53
+ | 文件 | 内容 |
54
+ | --- | --- |
55
+ | `~/.dsh-autoresearch/traces.jsonl` | init / run / experiment-logged / auto-commit-failed / auto-reverted / auto-revert-failed / workspace-reverted / revert-failed / error 控制面事件 |
56
+ | `<workspace>/.auto/log.jsonl` | 实验记录(index/idea/command/value/unit/kept/timestamp) |
57
+ | `<workspace>/.auto/prompt.md` | 优化会话章程 |
58
+
59
+ 最小收集原则:run 命令只保留前 120 字符,输出内容不入台账。查看:`Get-Content ~/.dsh-autoresearch/traces.jsonl`。
60
+
61
+ ## FAQ
62
+
63
+ - **auto-commit 会提交我的其他改动吗?** 不会(0.1.0 起):只 `git add -- .auto` 再 commit,工作区其他已跟踪改动不受影响。
64
+ - **运行超时了怎么办?** `run` 按 `experimentTimeoutMs`(默认 10 分钟)强制终止并标注 `(timed out)`,随后可 `log` 记录超时结果或重试。
65
+ - **实验日志会不会损坏?** `log.jsonl` 只追加;`init` 幂等(已有日志时拒绝重复初始化),防止方向混杂;单行损坏会被自动跳过并告警,不影响后续 `status`/`log`(0.1.2)。
66
+ - **Windows 上命令用什么 shell 执行?** 默认 `cmd /c`(非 Windows 为 `sh -c`);可通过配置 `shell` 指定 `pwsh` / `bash` 等,调用参数自动补齐(0.1.2)。
67
+ - **如何参与开发/发布?** 见 `docs/DEVELOPMENT.md` 与 `CHANGELOG.md`。
68
+
69
+ ## 参考
70
+
71
+ - 上游:[davebcn87/pi-autoresearch](https://github.com/davebcn87/pi-autoresearch)、[karpathy/autoresearch](https://github.com/karpathy/autoresearch)
72
+ - DSH 侧积木:`@deepseek-ai/dsh-subprocess`、`tool-ralph`(见 deepseek-harness `packages/`)
@@ -0,0 +1,27 @@
1
+ # dsh-autoresearch bundle patch: inserts the autonomous experiment loop into
2
+ # any profile that lists this package in `dsh.profile.bundles`. Experiment
3
+ # commands execute through the host's ctx.subprocess seam under the shared
4
+ # sandbox policy; this patch ships no executor of its own.
5
+ - insert:
6
+ - id: autoresearch
7
+ name: 'dsh-autoresearch'
8
+ config:
9
+ # Experiment state directory, relative to the session workspace root.
10
+ # Holds prompt.md (loop charter) and log.jsonl (append-only history).
11
+ autoDir: .auto
12
+ # After each logged experiment, commit .auto to retain log history.
13
+ autoCommit: true
14
+ # Automatically restore workspace changes when an experiment is rejected (kept: false).
15
+ autoRevert: false
16
+ # Safety bound: the loop refuses to log beyond this many experiments
17
+ # in one session without an explicit user confirmation.
18
+ maxExperiments: 100
19
+ # Per-experiment-command deadline in ms.
20
+ experimentTimeoutMs: 600000
21
+ # Bytes of stdout+stderr retained per experiment record.
22
+ outputRetentionBytes: 16384
23
+ # JSONL 控制面事件台账路径;留空 = ~/.dsh-autoresearch/traces.jsonl(超限轮转 .1)
24
+ tracePath: ''
25
+ # Shell to run experiment commands ('cmd', 'pwsh', 'bash', 'sh', etc.); empty = platform default.
26
+ shell: ''
27
+
package/lib/index.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import z from '@deepseek-ai/schemastery';
3
+ import type { ExperimentRecord } from './pure.js';
4
+ /** Cordis plugin name used by loader diagnostics. */
5
+ export declare const name = "autoresearch";
6
+ /** Services required by this plugin. */
7
+ export declare const inject: string[];
8
+ /** Plugin configuration; every field maps to a row in cordis.patch.yml. */
9
+ export interface Config {
10
+ /** Experiment state directory relative to the workspace root. */
11
+ autoDir: string;
12
+ /** `git commit` after each logged experiment. */
13
+ autoCommit: boolean;
14
+ /** Automatically restore workspace changes when an experiment is rejected (kept: false). */
15
+ autoRevert: boolean;
16
+ /** Safety bound on experiments per session without user confirmation. */
17
+ maxExperiments: number;
18
+ /** Per-experiment-command deadline (ms). */
19
+ experimentTimeoutMs: number;
20
+ /** Bytes of stdout+stderr retained per experiment record. */
21
+ outputRetentionBytes: number;
22
+ /** JSONL 控制面事件台账路径;空 = ~/.dsh-autoresearch/traces.jsonl。 */
23
+ tracePath: string;
24
+ /** Shell executable to run experiment commands; empty = platform default. */
25
+ shell: string;
26
+ }
27
+ export declare const Config: z<Config>;
28
+ declare module '@deepseek-ai/cordis' {
29
+ interface Events {
30
+ /** One experiment was appended to the log (and optionally committed). */
31
+ 'autoresearch/experiment-logged'(payload: ExperimentRecord): void;
32
+ }
33
+ }
34
+ /**
35
+ * Mount the experiment-loop bridge: register the single `autoresearch` tool.
36
+ *
37
+ * @param ctx - plugin context carrying the tools service.
38
+ * @param config - resolved plugin configuration.
39
+ */
40
+ export declare function apply(ctx: Context, config: Config): () => void;
package/lib/index.js ADDED
@@ -0,0 +1,403 @@
1
+ /**
2
+ * dsh-autoresearch: an autonomous experiment loop for DeepSeek Harness —
3
+ * try an idea, benchmark it, keep improvements, revert regressions, repeat.
4
+ * Port of pi-autoresearch (karpathy/autoresearch lineage) onto DSH seams.
5
+ *
6
+ * Durable state lives in `<workspace>/.auto/`:
7
+ * - prompt.md the session charter (written by the agent via `init`).
8
+ * - log.jsonl append-only experiment history, opened by a header line.
9
+ *
10
+ * Single `autoresearch` tool with an `action` field (init | run | log |
11
+ * status), not one tool per verb. Experiment commands execute through the
12
+ * host's ctx.subprocess seam under the shared sandbox policy.
13
+ *
14
+ * @module dsh-autoresearch
15
+ */
16
+ import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import z from '@deepseek-ai/schemastery';
19
+ import { bestSoFar, decideRetention, encodeRecord, generateCharterPrompt, headerLine, parseLine, renderAsciiTrend, renderTable, resolveShell, summarize, underExperimentCap, validateRecord, } from './pure.js';
20
+ import { TraceSink } from './trace.js';
21
+ /** Cordis plugin name used by loader diagnostics. */
22
+ export const name = 'autoresearch';
23
+ /** Services required by this plugin. */
24
+ export const inject = ['tools', 'subprocess'];
25
+ export const Config = z.object({
26
+ autoDir: z.string().default('.auto'),
27
+ autoCommit: z.boolean().default(true),
28
+ autoRevert: z.boolean().default(false),
29
+ maxExperiments: z.number().step(1).min(1).max(10000).default(100),
30
+ experimentTimeoutMs: z.number().min(1000).max(86400000).default(600000),
31
+ outputRetentionBytes: z.number().min(1024).max(1048576).default(16384),
32
+ tracePath: z.string().default(''),
33
+ shell: z.string().default(''),
34
+ });
35
+ /** Read the session's workspace root (the agent's cwd), best effort. */
36
+ function workspaceRoot(ctx, execAgent) {
37
+ const cwd = execAgent?.session?.header?.cwd;
38
+ return cwd !== undefined && cwd !== '' ? cwd : process.cwd();
39
+ }
40
+ /** The `.auto` directory for one workspace. */
41
+ function autoDirFor(ctx, config, execAgent) {
42
+ return join(workspaceRoot(ctx, execAgent), config.autoDir);
43
+ }
44
+ /** Read and parse the current log; returns records, direction, metric, and unit. */
45
+ function readLog(dir, logger) {
46
+ const path = join(dir, 'log.jsonl');
47
+ if (!existsSync(path))
48
+ return { records: [], direction: 'maximize' };
49
+ const records = [];
50
+ let direction = 'maximize';
51
+ let metric;
52
+ let unit;
53
+ for (const line of readFileSync(path, 'utf8').split('\n')) {
54
+ if (line.trim() === '')
55
+ continue;
56
+ try {
57
+ const parsed = parseLine(line);
58
+ if (parsed.kind === 'header') {
59
+ direction = parsed.direction;
60
+ if (parsed.metric !== undefined)
61
+ metric = parsed.metric;
62
+ if (parsed.unit !== undefined)
63
+ unit = parsed.unit;
64
+ }
65
+ else {
66
+ records.push(parsed.record);
67
+ }
68
+ }
69
+ catch (error) {
70
+ logger?.warn?.(`autoresearch: skipped corrupt log line: ${error instanceof Error ? error.message : String(error)}`);
71
+ }
72
+ }
73
+ return { records, direction, metric, unit };
74
+ }
75
+ /** Revert workspace changes back to HEAD while preserving the .auto directory. */
76
+ async function revertWorkspace(ctx, root, autoDir) {
77
+ const excludePattern = `:!${autoDir}`;
78
+ try {
79
+ const restore = ctx.subprocess.spawn({
80
+ argv: ['git', 'restore', '--worktree', '--staged', '--', '.', excludePattern],
81
+ cwd: root,
82
+ stdio: { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' },
83
+ graceMs: 5000,
84
+ });
85
+ const res = await restore.done;
86
+ if (res.exitCode !== 0) {
87
+ throw new Error(`git restore exited with ${res.exitCode}`);
88
+ }
89
+ }
90
+ catch {
91
+ const checkout = ctx.subprocess.spawn({
92
+ argv: ['git', 'checkout', 'HEAD', '--', '.', excludePattern],
93
+ cwd: root,
94
+ stdio: { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' },
95
+ graceMs: 5000,
96
+ });
97
+ const res = await checkout.done;
98
+ if (res.exitCode !== 0) {
99
+ throw new Error(`git checkout exited with ${res.exitCode}`);
100
+ }
101
+ }
102
+ }
103
+ /**
104
+ * Mount the experiment-loop bridge: register the single `autoresearch` tool.
105
+ *
106
+ * @param ctx - plugin context carrying the tools service.
107
+ * @param config - resolved plugin configuration.
108
+ */
109
+ export function apply(ctx, config) {
110
+ // 控制面事件台账:init/run/log/commit 失败与错误持久化(最小收集:实验日志
111
+ // 本体在 log.jsonl;trace 只记控制面事件与摘要)。
112
+ const trace = TraceSink.create(config.tracePath);
113
+ const tool = {
114
+ name: 'autoresearch',
115
+ description: 'Autonomous experiment loop: try an idea, benchmark it, keep ' +
116
+ 'improvements, revert regressions, repeat. actions: init (write the ' +
117
+ 'session charter), run (execute a command, time it, retain bounded ' +
118
+ 'output), log (record the result, auto-commit, decide keep/revert), ' +
119
+ 'status (report count, best, kept/reverted), revert (restore workspace to last good state).',
120
+ parameters: {
121
+ type: 'object',
122
+ properties: {
123
+ action: { type: 'string', enum: ['init', 'run', 'log', 'status', 'revert'] },
124
+ name: { type: 'string', description: 'experiment/session name' },
125
+ metric: { type: 'string', description: 'what to measure' },
126
+ unit: { type: 'string' },
127
+ direction: { type: 'string', enum: ['maximize', 'minimize'] },
128
+ command: { type: 'string', description: 'the experiment command' },
129
+ idea: { type: 'string', description: 'the idea being tried' },
130
+ value: { type: 'number' },
131
+ text: { type: 'string', description: 'run output for the record' },
132
+ confirm: { type: 'boolean', description: 'acknowledge the safety cap' },
133
+ format: {
134
+ type: 'string',
135
+ enum: ['summary', 'trend', 'table', 'full'],
136
+ description: 'format for status output: summary (default concise line), trend (ASCII sparkline), table (history table), full (summary + trend + table)',
137
+ },
138
+ limit: {
139
+ type: 'number',
140
+ description: 'maximum recent records to display in table/full format (default 10)',
141
+ },
142
+ autoRevert: {
143
+ type: 'boolean',
144
+ description: 'automatically restore workspace changes if experiment is reverted (kept: false)',
145
+ },
146
+ },
147
+ required: ['action'],
148
+ },
149
+ output: {
150
+ schema: {
151
+ type: 'object',
152
+ properties: {
153
+ text: { type: 'string' },
154
+ },
155
+ required: ['text'],
156
+ additionalProperties: false,
157
+ },
158
+ render(_args, value) {
159
+ return [{ type: 'text', text: value.text ?? '' }];
160
+ },
161
+ },
162
+ async execute(args, exec) {
163
+ const a = (args ?? {});
164
+ try {
165
+ return await runAction(a, exec);
166
+ }
167
+ catch (error) {
168
+ trace.record('error', {
169
+ action: a.action,
170
+ message: error instanceof Error ? error.message : String(error),
171
+ });
172
+ throw error;
173
+ }
174
+ },
175
+ };
176
+ async function runAction(a, exec) {
177
+ const dir = autoDirFor(ctx, config, exec.agent);
178
+ const { records, direction, unit: headerUnit } = readLog(dir, ctx.logger);
179
+ switch (a.action) {
180
+ case 'init': {
181
+ if (a.metric === undefined || a.unit === undefined) {
182
+ throw new Error('autoresearch init requires metric and unit');
183
+ }
184
+ if (a.direction !== 'maximize' && a.direction !== 'minimize') {
185
+ throw new Error('autoresearch init direction must be maximize or minimize');
186
+ }
187
+ mkdirSync(dir, { recursive: true });
188
+ // 幂等:已存在日志时拒绝重复 init,避免 header 重复追加导致方向混乱(P2 fix)。
189
+ if (existsSync(join(dir, 'log.jsonl'))) {
190
+ throw new Error('autoresearch: log.jsonl already exists — init 已执行过。如需重开,请先手动删除 .auto/log.jsonl');
191
+ }
192
+ writeFileSync(join(dir, 'prompt.md'), generateCharterPrompt({
193
+ name: a.name,
194
+ metric: a.metric,
195
+ unit: a.unit,
196
+ direction: a.direction,
197
+ baselineValue: a.value,
198
+ }), 'utf8');
199
+ appendFileSync(join(dir, 'log.jsonl'), headerLine(a.direction, { metric: a.metric, unit: a.unit }) + '\n', 'utf8');
200
+ trace.record('init', { metric: a.metric, unit: a.unit, direction: a.direction });
201
+ return { text: `session initialized: ${a.metric} (${a.unit}), ${a.direction}` };
202
+ }
203
+ case 'run': {
204
+ if (a.command === undefined || a.command === '') {
205
+ throw new Error('autoresearch run requires a command');
206
+ }
207
+ const collect = { maxBytes: config.outputRetentionBytes };
208
+ const shell = resolveShell(config.shell);
209
+ // 实验超时:合并调用方取消信号与配置超时(P1 fix:此前 experimentTimeoutMs
210
+ // 是死配置,无超时实现)。超时后 seam 的 signal 触发树级终止。
211
+ const combined = AbortSignal.any([
212
+ exec.signal,
213
+ AbortSignal.timeout(config.experimentTimeoutMs),
214
+ ]);
215
+ const handle = ctx.subprocess.spawn({
216
+ argv: [...shell, a.command],
217
+ cwd: workspaceRoot(ctx, exec.agent),
218
+ stdio: { stdin: 'ignore', stdout: collect, stderr: collect },
219
+ graceMs: 5000,
220
+ signal: combined,
221
+ });
222
+ const outcome = await handle.done;
223
+ const out = handle.collected.stdout?.readFrom(0).text ?? '';
224
+ const err = handle.collected.stderr?.readFrom(0).text ?? '';
225
+ const combinedText = `${out}\n${err}`.trim();
226
+ const timedOut = combined.aborted && !exec.signal.aborted;
227
+ const code = outcome.exitCode ?? (outcome.signal !== null ? 1 : 0);
228
+ trace.record('run', {
229
+ exitCode: code,
230
+ timedOut,
231
+ // 最小收集:命令只保留前 120 字符用于审计。
232
+ command: (a.command ?? '').slice(0, 120),
233
+ });
234
+ return {
235
+ text: `exit=${code}${timedOut ? ' (timed out)' : ''}\n${combinedText.slice(0, config.outputRetentionBytes)}`,
236
+ };
237
+ }
238
+ case 'log': {
239
+ if (a.idea === undefined || a.command === undefined || a.value === undefined) {
240
+ throw new Error('autoresearch log requires idea, command, and value');
241
+ }
242
+ if (!underExperimentCap(records.length, config.maxExperiments)) {
243
+ if (a.confirm !== true) {
244
+ throw new Error(`experiment cap reached (${records.length}/${config.maxExperiments}) — pass confirm:true to proceed`);
245
+ }
246
+ }
247
+ const { kept, isNewBest } = decideRetention(a.value, direction, bestSoFar(records, direction));
248
+ const resolvedUnit = a.unit !== undefined && a.unit !== ''
249
+ ? a.unit
250
+ : records.length > 0
251
+ ? records[records.length - 1].unit
252
+ : (headerUnit ?? 'score');
253
+ const record = {
254
+ index: records.length + 1,
255
+ idea: a.idea,
256
+ command: a.command,
257
+ value: a.value,
258
+ unit: resolvedUnit,
259
+ kept,
260
+ timestamp: new Date().toISOString(),
261
+ };
262
+ validateRecord(record);
263
+ mkdirSync(dir, { recursive: true });
264
+ appendFileSync(join(dir, 'log.jsonl'), encodeRecord(record) + '\n', 'utf8');
265
+ if (config.autoCommit) {
266
+ // 只提交 .auto 目录(P1 fix:原 `git commit -am` 会连带提交工作区
267
+ // 所有已跟踪改动,把用户 WIP 烙进实验提交;且原实现 fire-and-forget
268
+ // 不 await)。先 git add 指定路径(含 untracked 日志),再 commit。
269
+ try {
270
+ const root = workspaceRoot(ctx, exec.agent);
271
+ const add = ctx.subprocess.spawn({
272
+ argv: ['git', 'add', '--', config.autoDir],
273
+ cwd: root,
274
+ stdio: { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' },
275
+ graceMs: 5000,
276
+ });
277
+ await add.done;
278
+ const commit = ctx.subprocess.spawn({
279
+ argv: ['git', 'commit', '-m', `autoresearch #${record.index}: ${a.idea}`.slice(0, 200)],
280
+ cwd: root,
281
+ stdio: { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' },
282
+ graceMs: 5000,
283
+ });
284
+ await commit.done;
285
+ }
286
+ catch (error) {
287
+ trace.record('auto-commit-failed', {
288
+ index: record.index,
289
+ message: error instanceof Error ? error.message : String(error),
290
+ });
291
+ ctx.logger.warn(`autoresearch: auto-commit failed for experiment #${record.index}: ${String(error)}`);
292
+ }
293
+ }
294
+ ctx.emit('autoresearch/experiment-logged', record);
295
+ trace.record('experiment-logged', {
296
+ index: record.index,
297
+ kept,
298
+ isNewBest,
299
+ value: record.value,
300
+ unit: record.unit,
301
+ });
302
+ let guidance = '';
303
+ if (!kept) {
304
+ const shouldAutoRevert = a.autoRevert ?? config.autoRevert;
305
+ if (shouldAutoRevert) {
306
+ try {
307
+ const root = workspaceRoot(ctx, exec.agent);
308
+ await revertWorkspace(ctx, root, config.autoDir);
309
+ trace.record('auto-reverted', { index: record.index });
310
+ guidance = ' (reverted — workspace changes automatically reverted)';
311
+ }
312
+ catch (error) {
313
+ trace.record('auto-revert-failed', {
314
+ index: record.index,
315
+ message: error instanceof Error ? error.message : String(error),
316
+ });
317
+ ctx.logger.warn(`autoresearch: auto-revert failed for experiment #${record.index}: ${String(error)}`);
318
+ guidance = ` (reverted — auto-revert failed: ${error instanceof Error ? error.message : String(error)}; please restore code manually)`;
319
+ }
320
+ }
321
+ else {
322
+ guidance = ' (reverted — please restore/revert code changes before the next attempt)';
323
+ }
324
+ }
325
+ return {
326
+ text: `experiment #${record.index} logged: ${kept ? 'kept' : 'reverted'}${isNewBest ? ' (new best)' : ''} — value ${record.value} ${record.unit}${guidance}`,
327
+ };
328
+ }
329
+ case 'status': {
330
+ const summary = summarize(records, direction, config.maxExperiments);
331
+ const summaryLine = `experiments=${summary.count} best=${summary.best ?? 'n/a'} kept=${summary.kept} reverted=${summary.reverted} direction=${summary.direction} cap=${summary.cap}`;
332
+ const format = a.format ?? 'summary';
333
+ const limit = a.limit ?? 10;
334
+ if (format === 'trend') {
335
+ return {
336
+ text: `${summaryLine}\n\n${renderAsciiTrend(records, direction)}`,
337
+ };
338
+ }
339
+ if (format === 'table') {
340
+ return {
341
+ text: `${summaryLine}\n\n${renderTable(records, direction, limit)}`,
342
+ };
343
+ }
344
+ if (format === 'full') {
345
+ return {
346
+ text: `${summaryLine}\n\n${renderAsciiTrend(records, direction)}\n\n${renderTable(records, direction, limit)}`,
347
+ };
348
+ }
349
+ return {
350
+ text: summaryLine,
351
+ };
352
+ }
353
+ case 'revert': {
354
+ const root = workspaceRoot(ctx, exec.agent);
355
+ try {
356
+ await revertWorkspace(ctx, root, config.autoDir);
357
+ trace.record('workspace-reverted', {});
358
+ return { text: 'workspace changes reverted (excluding .auto)' };
359
+ }
360
+ catch (error) {
361
+ trace.record('revert-failed', {
362
+ message: error instanceof Error ? error.message : String(error),
363
+ });
364
+ throw new Error(`autoresearch revert failed: ${error instanceof Error ? error.message : String(error)}`);
365
+ }
366
+ }
367
+ default:
368
+ throw new Error(`autoresearch: unknown action ${a.action}`);
369
+ }
370
+ }
371
+ ctx.effect(() => {
372
+ const disposeTool = ctx.tools.register(tool);
373
+ return () => disposeTool();
374
+ }, 'autoresearch.tool');
375
+ // 可选提示词动态上下文:若宿主存在 systemPrompt 服务,则向模型上下文注入当前研究状态快照
376
+ ctx.effect(() => {
377
+ const sysPrompt = ctx.systemPrompt;
378
+ if (!sysPrompt || typeof sysPrompt.context !== 'function')
379
+ return () => { };
380
+ const disposeContext = sysPrompt.context({
381
+ name: 'autoresearch:status',
382
+ order: 150,
383
+ text: (assembleCtx) => {
384
+ try {
385
+ const dir = autoDirFor(ctx, config, assembleCtx.scope);
386
+ const { records, direction } = readLog(dir, ctx.logger);
387
+ if (records.length === 0)
388
+ return '';
389
+ const summary = summarize(records, direction, config.maxExperiments);
390
+ return `[Autoresearch Active: ${summary.count} experiments, best=${summary.best ?? 'n/a'}, kept=${summary.kept}, reverted=${summary.reverted}]`;
391
+ }
392
+ catch {
393
+ return '';
394
+ }
395
+ },
396
+ });
397
+ return () => disposeContext();
398
+ }, 'autoresearch.systemPrompt');
399
+ return () => {
400
+ // Nothing to clean beyond the tool disposer; present for symmetry.
401
+ };
402
+ }
403
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/pure.d.ts ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Pure, dependency-free logic for dsh-autoresearch: experiment-record
3
+ * validation, JSONL line codec, best/worst tracking, keep/revert retention,
4
+ * and the safety cap. Free of @deepseek-ai imports for standalone testing.
5
+ *
6
+ * @module
7
+ */
8
+ /** One experiment record as appended to `.auto/log.jsonl`. */
9
+ export interface ExperimentRecord {
10
+ /** Monotonic experiment number within the session. */
11
+ index: number;
12
+ /** The idea being tried, in the agent's own words. */
13
+ idea: string;
14
+ /** The command whose wall-clock/output defines the metric. */
15
+ command: string;
16
+ /** Measured metric value. */
17
+ value: number;
18
+ /** Metric unit, e.g. `ms`, `bytes`, `score`. */
19
+ unit: string;
20
+ /** Whether this experiment kept (true) or reverted (false). */
21
+ kept: boolean;
22
+ /** ISO timestamp of the log entry. */
23
+ timestamp: string;
24
+ }
25
+ /** The loop's direction: maximize or minimize the metric. */
26
+ export type Direction = 'maximize' | 'minimize';
27
+ /** A header marker in log.jsonl recording the session charter. */
28
+ export interface HeaderRecord {
29
+ kind: 'header';
30
+ direction: Direction;
31
+ metric?: string;
32
+ unit?: string;
33
+ }
34
+ /** A validated log line: either a record or a header marker. */
35
+ export type LogLine = HeaderRecord | {
36
+ kind: 'record';
37
+ record: ExperimentRecord;
38
+ };
39
+ /** Validate one experiment record; throws on malformed fields. */
40
+ export declare function validateRecord(record: ExperimentRecord): void;
41
+ /** Encode one record as a single JSONL line. */
42
+ export declare function encodeRecord(record: ExperimentRecord): string;
43
+ /** Parse one JSONL line into a header or record. */
44
+ export declare function parseLine(line: string): LogLine;
45
+ /** The header line that opens a session log. */
46
+ export declare function headerLine(direction: Direction, options?: {
47
+ metric?: string;
48
+ unit?: string;
49
+ }): string;
50
+ /**
51
+ * Decide whether an experiment kept or reverted, and whether it improved the
52
+ * best-known value so far.
53
+ */
54
+ export declare function decideRetention(value: number, direction: Direction, bestSoFar: number | undefined): {
55
+ kept: boolean;
56
+ isNewBest: boolean;
57
+ };
58
+ /** Track best-so-far from a history of records. */
59
+ export declare function bestSoFar(records: readonly ExperimentRecord[], direction: Direction): number | undefined;
60
+ /** Safety cap: refuse to log beyond the cap without explicit confirmation. */
61
+ export declare function underExperimentCap(logged: number, maxExperiments: number): boolean;
62
+ /** Build the status summary the agent sees on `autoresearch status`. */
63
+ export declare function summarize(records: readonly ExperimentRecord[], direction: Direction, cap: number): {
64
+ count: number;
65
+ best: number | undefined;
66
+ kept: number;
67
+ reverted: number;
68
+ direction: Direction;
69
+ cap: number;
70
+ };
71
+ /**
72
+ * Resolve the shell command line array for executing commands.
73
+ */
74
+ export declare function resolveShell(customShell?: string, platform?: string): string[];
75
+ /**
76
+ * Render an ASCII sparkline and trajectory trend of experiment values.
77
+ *
78
+ * @param records - list of experiment records in chronological order
79
+ * @param direction - 'maximize' | 'minimize'
80
+ * @returns ASCII trend string with sparkline and trajectory
81
+ */
82
+ export declare function renderAsciiTrend(records: readonly ExperimentRecord[], direction: Direction): string;
83
+ /**
84
+ * Render a formatted ASCII table of the most recent experiments.
85
+ *
86
+ * @param records - list of experiment records
87
+ * @param direction - 'maximize' | 'minimize'
88
+ * @param limit - maximum number of recent records to display (default 10)
89
+ * @returns Formatted multi-line ASCII table
90
+ */
91
+ export declare function renderTable(records: readonly ExperimentRecord[], direction: Direction, limit?: number): string;
92
+ /**
93
+ * Generate a standard optimization charter template for LLM autonomous loops.
94
+ *
95
+ * @param charter - session options
96
+ * @returns Markdown charter text
97
+ */
98
+ export declare function generateCharterPrompt(charter: {
99
+ name?: string;
100
+ metric: string;
101
+ unit: string;
102
+ direction: Direction;
103
+ baselineValue?: number;
104
+ }): string;
package/lib/pure.js ADDED
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Pure, dependency-free logic for dsh-autoresearch: experiment-record
3
+ * validation, JSONL line codec, best/worst tracking, keep/revert retention,
4
+ * and the safety cap. Free of @deepseek-ai imports for standalone testing.
5
+ *
6
+ * @module
7
+ */
8
+ /** Validate one experiment record; throws on malformed fields. */
9
+ export function validateRecord(record) {
10
+ if (!Number.isInteger(record.index) || record.index < 1) {
11
+ throw new Error(`invalid experiment index ${record.index}: must be a positive integer`);
12
+ }
13
+ if (record.idea === '' || record.command === '') {
14
+ throw new Error('experiment idea and command must be non-empty');
15
+ }
16
+ if (!Number.isFinite(record.value)) {
17
+ throw new Error(`invalid metric value ${record.value}: must be finite`);
18
+ }
19
+ if (record.unit === '') {
20
+ throw new Error('experiment unit must be non-empty');
21
+ }
22
+ }
23
+ /** Encode one record as a single JSONL line. */
24
+ export function encodeRecord(record) {
25
+ validateRecord(record);
26
+ return JSON.stringify(record);
27
+ }
28
+ /** Parse one JSONL line into a header or record. */
29
+ export function parseLine(line) {
30
+ const trimmed = line.trim();
31
+ if (trimmed === '')
32
+ throw new Error('empty log line');
33
+ const parsed = JSON.parse(trimmed);
34
+ if (parsed.kind === 'header') {
35
+ if (parsed.direction !== 'maximize' && parsed.direction !== 'minimize') {
36
+ throw new Error('invalid header direction');
37
+ }
38
+ const header = {
39
+ kind: 'header',
40
+ direction: parsed.direction,
41
+ };
42
+ if (typeof parsed.metric === 'string' && parsed.metric !== '') {
43
+ header.metric = parsed.metric;
44
+ }
45
+ if (typeof parsed.unit === 'string' && parsed.unit !== '') {
46
+ header.unit = parsed.unit;
47
+ }
48
+ return header;
49
+ }
50
+ const record = parsed;
51
+ validateRecord(record);
52
+ return { kind: 'record', record };
53
+ }
54
+ /** The header line that opens a session log. */
55
+ export function headerLine(direction, options) {
56
+ const payload = { kind: 'header', direction };
57
+ if (options?.metric !== undefined && options.metric !== '') {
58
+ payload.metric = options.metric;
59
+ }
60
+ if (options?.unit !== undefined && options.unit !== '') {
61
+ payload.unit = options.unit;
62
+ }
63
+ return JSON.stringify(payload);
64
+ }
65
+ /**
66
+ * Decide whether an experiment kept or reverted, and whether it improved the
67
+ * best-known value so far.
68
+ */
69
+ export function decideRetention(value, direction, bestSoFar) {
70
+ if (bestSoFar === undefined)
71
+ return { kept: true, isNewBest: true };
72
+ const better = direction === 'maximize' ? value > bestSoFar : value < bestSoFar;
73
+ return { kept: better, isNewBest: better };
74
+ }
75
+ /** Track best-so-far from a history of records. */
76
+ export function bestSoFar(records, direction) {
77
+ if (records.length === 0)
78
+ return undefined;
79
+ return records.reduce((best, record) => {
80
+ if (direction === 'maximize')
81
+ return Math.max(best, record.value);
82
+ return Math.min(best, record.value);
83
+ }, records[0].value);
84
+ }
85
+ /** Safety cap: refuse to log beyond the cap without explicit confirmation. */
86
+ export function underExperimentCap(logged, maxExperiments) {
87
+ return logged < maxExperiments;
88
+ }
89
+ /** Build the status summary the agent sees on `autoresearch status`. */
90
+ export function summarize(records, direction, cap) {
91
+ return {
92
+ count: records.length,
93
+ best: bestSoFar(records, direction),
94
+ kept: records.filter((r) => r.kept).length,
95
+ reverted: records.filter((r) => !r.kept).length,
96
+ direction,
97
+ cap,
98
+ };
99
+ }
100
+ /**
101
+ * Resolve the shell command line array for executing commands.
102
+ */
103
+ export function resolveShell(customShell, platform = process.platform) {
104
+ const trimmed = customShell?.trim();
105
+ if (!trimmed) {
106
+ return platform === 'win32' ? ['cmd', '/c'] : ['sh', '-c'];
107
+ }
108
+ const lower = trimmed.toLowerCase();
109
+ if (lower === 'cmd' || lower === 'cmd.exe') {
110
+ return [trimmed, '/c'];
111
+ }
112
+ if (lower.startsWith('pwsh') || lower.startsWith('powershell')) {
113
+ return [trimmed, '-NoProfile', '-Command'];
114
+ }
115
+ if (lower.startsWith('bash') || lower.startsWith('sh') || lower.startsWith('zsh')) {
116
+ return [trimmed, '-c'];
117
+ }
118
+ return platform === 'win32' && lower.endsWith('.bat') ? [trimmed, '/c'] : [trimmed, '-c'];
119
+ }
120
+ const SPARK_BLOCKS = [' ', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
121
+ /**
122
+ * Render an ASCII sparkline and trajectory trend of experiment values.
123
+ *
124
+ * @param records - list of experiment records in chronological order
125
+ * @param direction - 'maximize' | 'minimize'
126
+ * @returns ASCII trend string with sparkline and trajectory
127
+ */
128
+ export function renderAsciiTrend(records, direction) {
129
+ if (records.length === 0)
130
+ return 'No experiments recorded yet.';
131
+ const values = records.map((r) => r.value);
132
+ const min = Math.min(...values);
133
+ const max = Math.max(...values);
134
+ const span = max - min;
135
+ const sparkline = records
136
+ .map((r) => {
137
+ if (span === 0)
138
+ return '▅';
139
+ const fraction = (r.value - min) / span;
140
+ const index = Math.min(SPARK_BLOCKS.length - 1, Math.max(0, Math.floor(fraction * (SPARK_BLOCKS.length - 1))));
141
+ return SPARK_BLOCKS[index];
142
+ })
143
+ .join('');
144
+ const statusIcons = records.map((r) => (r.kept ? '✓' : '✗')).join('');
145
+ const bestVal = bestSoFar(records, direction);
146
+ const latest = records[records.length - 1];
147
+ return (`Trend: ${sparkline} (${records.length} runs)\n` +
148
+ `Kept : ${statusIcons}\n` +
149
+ `Range: [min: ${min}, max: ${max}] | Current: ${latest.value} ${latest.unit} | Best: ${bestVal ?? 'n/a'} ${latest.unit} (${direction})`);
150
+ }
151
+ /**
152
+ * Render a formatted ASCII table of the most recent experiments.
153
+ *
154
+ * @param records - list of experiment records
155
+ * @param direction - 'maximize' | 'minimize'
156
+ * @param limit - maximum number of recent records to display (default 10)
157
+ * @returns Formatted multi-line ASCII table
158
+ */
159
+ export function renderTable(records, direction, limit = 10) {
160
+ if (records.length === 0)
161
+ return 'No experiments recorded.';
162
+ const slice = records.slice(-limit);
163
+ const best = bestSoFar(records, direction);
164
+ const rows = slice.map((r) => {
165
+ const isBest = r.value === best && r.kept;
166
+ const valStr = `${r.value} ${r.unit}${isBest ? ' ★' : ''}`;
167
+ const statusStr = r.kept ? 'kept' : 'revert';
168
+ const timeStr = r.timestamp && r.timestamp.length >= 19 ? r.timestamp.slice(11, 19) : '-';
169
+ const ideaStr = r.idea.length > 30 ? r.idea.slice(0, 27) + '...' : r.idea;
170
+ return {
171
+ index: `#${r.index}`,
172
+ idea: ideaStr,
173
+ value: valStr,
174
+ status: statusStr,
175
+ time: timeStr,
176
+ };
177
+ });
178
+ const colIdxWidth = Math.max(5, ...rows.map((r) => r.index.length));
179
+ const colIdeaWidth = Math.max(10, ...rows.map((r) => r.idea.length));
180
+ const colValWidth = Math.max(10, ...rows.map((r) => r.value.length));
181
+ const colStatusWidth = Math.max(6, ...rows.map((r) => r.status.length));
182
+ const colTimeWidth = Math.max(8, ...rows.map((r) => r.time.length));
183
+ const pad = (s, len) => s + ' '.repeat(Math.max(0, len - s.length));
184
+ const header = `| ${pad('Index', colIdxWidth)} | ${pad('Idea', colIdeaWidth)} | ${pad('Value', colValWidth)} | ${pad('Status', colStatusWidth)} | ${pad('Time', colTimeWidth)} |`;
185
+ const sep = `|-${'-'.repeat(colIdxWidth)}-|-${'-'.repeat(colIdeaWidth)}-|-${'-'.repeat(colValWidth)}-|-${'-'.repeat(colStatusWidth)}-|-${'-'.repeat(colTimeWidth)}-|`;
186
+ const body = rows
187
+ .map((r) => `| ${pad(r.index, colIdxWidth)} | ${pad(r.idea, colIdeaWidth)} | ${pad(r.value, colValWidth)} | ${pad(r.status, colStatusWidth)} | ${pad(r.time, colTimeWidth)} |`)
188
+ .join('\n');
189
+ return `${header}\n${sep}\n${body}`;
190
+ }
191
+ /**
192
+ * Generate a standard optimization charter template for LLM autonomous loops.
193
+ *
194
+ * @param charter - session options
195
+ * @returns Markdown charter text
196
+ */
197
+ export function generateCharterPrompt(charter) {
198
+ const nameHeader = charter.name !== undefined ? `: ${charter.name}` : '';
199
+ const baseLine = charter.baselineValue !== undefined ? `\n- Baseline Value: ${charter.baselineValue} ${charter.unit}` : '';
200
+ return (`# Autonomous Research Charter${nameHeader}\n\n` +
201
+ `## Objective\n` +
202
+ `- Metric: ${charter.metric} (${charter.unit})\n` +
203
+ `- Optimization Direction: ${charter.direction} (${charter.direction === 'maximize' ? 'higher is better' : 'lower is better'})${baseLine}\n\n` +
204
+ `## Protocol Rules\n` +
205
+ `1. **One Mutation Per Iteration**: Modify code/config to test a single hypothesis.\n` +
206
+ `2. **Benchmark Execution**: Run standard evaluation using \`autoresearch run\` to measure the metric.\n` +
207
+ `3. **Log & Retain Decisions**: Log value via \`autoresearch log\`. If kept (improved), commit and build upon it. If reverted (regression), restore the workspace.\n` +
208
+ `4. **Bounded Output & Safety**: Adhere to experiment deadlines and execution safety caps.\n`);
209
+ }
210
+ //# sourceMappingURL=pure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pure.js","sourceRoot":"","sources":["../src/pure.ts"],"names":[],"mappings":"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"}
package/lib/trace.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /** 默认台账路径(由配置项 tracePath 覆盖)。 */
2
+ export declare const DEFAULT_TRACE_PATH: string;
3
+ /** 一条台账记录(JSON 安全,整行写入)。 */
4
+ export interface TraceEntry {
5
+ seq: number;
6
+ ts: string;
7
+ event: string;
8
+ detail: Record<string, unknown>;
9
+ }
10
+ export declare class TraceSink {
11
+ private readonly filePath;
12
+ private readonly maxBytes;
13
+ private seq;
14
+ private writeErrors;
15
+ private constructor();
16
+ static create(path: string | undefined, maxBytes?: number): TraceSink;
17
+ /** 台账文件路径(供文档与排查引用)。 */
18
+ get path(): string;
19
+ /** 写入失败累计次数(0 = 全部成功)。 */
20
+ get failureCount(): number;
21
+ /** 追加一条事件;永不抛出。 */
22
+ record(event: string, detail?: Record<string, unknown>): void;
23
+ }
package/lib/trace.js ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * JSONL 事件台账(TraceSink):关键生命周期事件与错误追加写入持久化文件,
3
+ * 供运行回溯审计。最小收集原则:只记事件名与结构化摘要,不记录会话输出内容。
4
+ *
5
+ * - 默认路径:~/.dsh-autoresearch/traces.jsonl(`tracePath` 可配)
6
+ * - 超限轮转:超过 maxBytes 时把当前文件改名为 .1(覆盖旧 .1),继续写新文件
7
+ * - best-effort:写入失败只计数,绝不抛出、绝不影响插件主流程
8
+ *
9
+ * @module dsh-autoresearch/trace
10
+ */
11
+ import { appendFileSync, existsSync, mkdirSync, renameSync, statSync } from 'node:fs';
12
+ import { homedir } from 'node:os';
13
+ import { dirname, join } from 'node:path';
14
+ /** 默认台账路径(由配置项 tracePath 覆盖)。 */
15
+ export const DEFAULT_TRACE_PATH = join(homedir(), '.dsh-autoresearch', 'traces.jsonl');
16
+ export class TraceSink {
17
+ filePath;
18
+ maxBytes;
19
+ seq = 0;
20
+ writeErrors = 0;
21
+ constructor(filePath, maxBytes) {
22
+ this.filePath = filePath;
23
+ this.maxBytes = maxBytes;
24
+ }
25
+ static create(path, maxBytes = 5 * 1024 * 1024) {
26
+ return new TraceSink(path === undefined || path === '' ? DEFAULT_TRACE_PATH : path, maxBytes);
27
+ }
28
+ /** 台账文件路径(供文档与排查引用)。 */
29
+ get path() {
30
+ return this.filePath;
31
+ }
32
+ /** 写入失败累计次数(0 = 全部成功)。 */
33
+ get failureCount() {
34
+ return this.writeErrors;
35
+ }
36
+ /** 追加一条事件;永不抛出。 */
37
+ record(event, detail = {}) {
38
+ this.seq += 1;
39
+ const entry = { seq: this.seq, ts: new Date().toISOString(), event, detail };
40
+ try {
41
+ mkdirSync(dirname(this.filePath), { recursive: true });
42
+ if (existsSync(this.filePath)) {
43
+ try {
44
+ if (statSync(this.filePath).size > this.maxBytes) {
45
+ renameSync(this.filePath, `${this.filePath}.1`);
46
+ }
47
+ }
48
+ catch {
49
+ // 轮转失败(如文件被占用)就继续追加,不阻塞主流程。
50
+ }
51
+ }
52
+ appendFileSync(this.filePath, `${JSON.stringify(entry)}\n`, 'utf8');
53
+ }
54
+ catch {
55
+ this.writeErrors += 1;
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.js","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC,iCAAiC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAA;AAUtF,MAAM,OAAO,SAAS;IAKD;IACA;IALX,GAAG,GAAG,CAAC,CAAA;IACP,WAAW,GAAG,CAAC,CAAA;IAEvB,YACmB,QAAgB,EAChB,QAAgB;QADhB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAQ;IAChC,CAAC;IAEJ,MAAM,CAAC,MAAM,CAAC,IAAwB,EAAE,WAAmB,CAAC,GAAG,IAAI,GAAG,IAAI;QACxE,OAAO,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC/F,CAAC;IAED,wBAAwB;IACxB,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED,0BAA0B;IAC1B,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED,mBAAmB;IACnB,MAAM,CAAC,KAAa,EAAE,SAAkC,EAAE;QACxD,IAAI,CAAC,GAAG,IAAI,CAAC,CAAA;QACb,MAAM,KAAK,GAAe,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;QACxF,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACtD,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC;oBACH,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACjD,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAA;oBACjD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,4BAA4B;gBAC9B,CAAC;YACH,CAAC;YACD,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QACrE,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,WAAW,IAAI,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@master0071/dsh-autoresearch",
3
+ "version": "0.1.5",
4
+ "description": "Autonomous experiment loop for DeepSeek Harness: try an idea, benchmark it, keep improvements, revert regressions, repeat. init/run/log experiment tools over an append-only .auto/log.jsonl with auto-commit retention. Port of pi-autoresearch (karpathy/autoresearch lineage).",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "lib/",
13
+ "cordis.patch.yml",
14
+ "README.md"
15
+ ],
16
+ "main": "./lib/index.js",
17
+ "types": "./lib/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./lib/index.d.ts",
21
+ "default": "./lib/index.js"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "dsh": {
26
+ "bundle": {
27
+ "patch": "cordis.patch.yml"
28
+ }
29
+ },
30
+ "engines": {
31
+ "node": ">=22.19"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.json",
35
+ "typecheck": "tsc --noEmit -p tsconfig.json",
36
+ "test": "npm run build && node --test",
37
+ "test:coverage": "npm run build && node --experimental-test-coverage --test \"test/*.test.mjs\"",
38
+ "prepack": "npm run build",
39
+ "lint": "oxlint src test"
40
+ },
41
+ "dependencies": {
42
+ "@deepseek-ai/schemastery": "^3.18.1-rc.1"
43
+ },
44
+ "peerDependencies": {
45
+ "@deepseek-ai/cordis": "^4.0.1",
46
+ "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
47
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
48
+ "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
49
+ "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2",
50
+ "@deepseek-ai/dsh-tools": "^0.1.1-rc.2"
51
+ },
52
+ "devDependencies": {
53
+ "@deepseek-ai/cordis": "^4.0.1",
54
+ "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
55
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
56
+ "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
57
+ "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2",
58
+ "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
59
+ "@types/node": "^24.0.0",
60
+ "oxlint": "^1.80.0",
61
+ "typescript": "^5.8.0"
62
+ }
63
+ }