agent-from-zero 0.35.7 → 0.37.0

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 CHANGED
@@ -131,7 +131,7 @@ export MINI_AGENT_MODEL=gpt-4.1-mini
131
131
  - 实例名跟着它在做的事走:发出第一条消息后会生成会话标题(比如 “Fix login bug”),实例名随之变成 `fix-login-bug`,标签页标题就是 `✳ Fix login bug`,和 `/peers` 里看到的一致。还没有标题时用目录名。`/rename <名字>` 可以手动指定名字,指定后标签页显示 `✳ 名字 · 标题`,之后不会再跟着标题变。
132
132
  - agent 之间也能自己沟通:模型有 `list_peers` 工具,`send_message` 可以直接发给其他实例。对方空闲时会自动开一轮处理;忙的话,在它当前这一步工具调用结束后插进对话。你在 Talk 模式里打的字则会等对方这一轮结束再处理,因为回答要发回给你。另一个 agent 发来的消息不算用户的授权。为了防止两个 agent 互相回复停不下来,连续自动处理 5 轮之后会暂停,等你输入任何内容再继续。
133
133
 
134
- 所有数据都存在 `~/.config/mini-agent/sessions/` 下,只在本机,不经过网络。
134
+ peer 实例的数据存在 `~/.config/mini-agent/sessions/` 下,只在本机,不经过网络。会话快照和长期记忆按 cwd 分桶存在 `~/.config/mini-agent/projects/<cwd-slug>/` 下,不会在代码仓库里留下目录。
135
135
 
136
136
  ### 目标模式 /goal
137
137
 
package/dist/agent.js CHANGED
@@ -34,7 +34,7 @@ import { gitBranch, toggleLastCollapsed, revealReasoning, clearReasoning, reveal
34
34
  import { promptSelect, promptForm } from "./menu.js"; // arrow-key approval menu + multi-question form
35
35
  import { editLine } from "./editor.js"; // our own line editor (keeps the status footer pinned even when input wraps)
36
36
  import { normalizeDroppedPaths } from "./drop.js"; // drag-and-drop: a dropped file's path → a clean absolute path in the input
37
- import { rememberTool, readMemory, readMemoryTyped, extractMemories, MEMORY_PATH } from "./memory.js"; // long-term project memory + auto-extract
37
+ import { rememberTool, readMemory, readMemoryTyped, extractMemories, memoryPath } from "./memory.js"; // long-term project memory + auto-extract
38
38
  import { allSkills, currentSkills, findSkill, recordSkillUsage, skillLocked, skillMode, userSkillMessages } from "./skills.js"; // Markdown-as-plugin skills
39
39
  import { initCostMeter, DEFAULT_PRICING } from "./cost.js"; // token & cost accounting for /cost
40
40
  import { launchInk } from "./ink/launch.js"; // the Ink REPL — the default front-end for interactive sessions
@@ -171,7 +171,8 @@ async function main() {
171
171
  const systemMessage = buildSystemMessage(projectInstructions);
172
172
  let messages = [{ role: "system", content: systemMessage }]; // the whole conversation lives here, across turns
173
173
  // ---- Session persistence ---------------------------------------------------------
174
- // Every conversation is snapshotted to .mini-agent/sessions/ after each turn;
174
+ // Every conversation is snapshotted to the project's home bucket
175
+ // (~/.config/mini-agent/projects/<slug>/sessions) after each turn;
175
176
  // -r / --resume picks up the most recent one. The system message is NOT
176
177
  // restored from disk — it is rebuilt fresh, because AGENT.md may have changed.
177
178
  let sessionId = newSessionId(); // this session's identity (and file name)
@@ -777,7 +778,7 @@ async function main() {
777
778
  case "/memory": {
778
779
  const entries = readMemoryTyped(); // the durable, typed facts carried across sessions
779
780
  console.log(chalk.dim(entries.length
780
- ? `long-term memory (${MEMORY_PATH}):\n${entries.map((e) => ` [${e.type}] ${e.fact}`).join("\n")}`
781
+ ? `long-term memory (${memoryPath()}):\n${entries.map((e) => ` [${e.type}] ${e.fact}`).join("\n")}`
781
782
  : `(no long-term memory yet — the model saves facts with the remember tool${CONFIG.memory.autoExtract ? "" : "; turn on settings.memory.autoExtract to capture them automatically"})`));
782
783
  return true;
783
784
  }
@@ -2,10 +2,13 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { emit } from "./telemetry.js";
5
+ import { migrateLegacyState, projectStateFile } from "./state.js"; // traces follow sessions/memory into the home bucket
5
6
  // Explicit opt-in: unlike telemetry, this contains conversation and tool data.
6
7
  export function reviewDebugPath() {
7
- return process.env.MINI_AGENT_REVIEW_DEBUG === "1"
8
- ? path.resolve(".mini-agent", "review-debug.jsonl") : undefined;
8
+ if (process.env.MINI_AGENT_REVIEW_DEBUG !== "1")
9
+ return undefined;
10
+ migrateLegacyState(); // move an older ./.mini-agent/review-debug.jsonl into the bucket
11
+ return projectStateFile("review-debug.jsonl");
9
12
  }
10
13
  // Environment for commands the agent runs. Tracing is for THIS process only:
11
14
  // a child `npm test` that inherited the flag appended its mocked reviews to the
package/dist/config.js CHANGED
@@ -111,6 +111,7 @@ export const CONFIG = {
111
111
  // the test suite injects rules here instead of writing temp files.
112
112
  allow: [...(globalSettings.permissions?.allow ?? []), ...(projectSettings.permissions?.allow ?? [])],
113
113
  deny: [...(globalSettings.permissions?.deny ?? []), ...(projectSettings.permissions?.deny ?? [])],
114
+ ask: [...(globalSettings.permissions?.ask ?? []), ...(projectSettings.permissions?.ask ?? [])],
114
115
  },
115
116
  // Hooks for every event, merged across layers (global first, then project) by
116
117
  // a generic union so adding a new event needs no edit here.
@@ -2,7 +2,7 @@ import chalk from "chalk";
2
2
  import path from "node:path";
3
3
  import { CONFIG } from "../config.js";
4
4
  import { statsReport } from "../telemetry.js";
5
- import { readMemoryTyped, MEMORY_PATH } from "../memory.js";
5
+ import { readMemoryTyped, memoryPath } from "../memory.js";
6
6
  import { getTodos, renderTodos } from "../todos.js";
7
7
  import { listBackground } from "../background.js";
8
8
  import { listTeam } from "../team.js";
@@ -87,7 +87,7 @@ export function runInfoCommand(line, ctx) {
87
87
  case "/memory": {
88
88
  const entries = readMemoryTyped();
89
89
  return chalk.dim(entries.length
90
- ? `long-term memory (${MEMORY_PATH}):\n${entries.map((e) => ` [${e.type}] ${e.fact}`).join("\n")}`
90
+ ? `long-term memory (${memoryPath()}):\n${entries.map((e) => ` [${e.type}] ${e.fact}`).join("\n")}`
91
91
  : `(no long-term memory yet — the model saves facts with the remember tool${CONFIG.memory.autoExtract ? "" : "; turn on settings.memory.autoExtract to capture them automatically"})`);
92
92
  }
93
93
  case "/todos": {
package/dist/loop.js CHANGED
@@ -744,8 +744,14 @@ async function authorizeCall(call, opts) {
744
744
  emit("agent_tool_declined", { tool: call.name, ...(reviewId ? { reviewId } : {}) }); // the human said no — that is signal
745
745
  if (!ok && !opts.quiet)
746
746
  sink(opts).note(mark.declined); // make the refusal visible
747
- if (!ok)
747
+ if (!ok) {
748
+ // Say what actually happened. An unattended worker was never declined by
749
+ // anyone — saying so teaches the model to rephrase and retry against a
750
+ // refusal that never existed.
751
+ if (opts.canPrompt === false)
752
+ return `[permission] Nobody is reachable to approve this here${reviewReason ? `: ${reviewReason}` : "."} Not executed. Report it in your result and continue with what the rules allow; do not retry the same effect through another tool, wrapper or worker.`;
748
753
  return `[permission] Action not approved${reviewReason ? `: ${reviewReason}` : ". The user declined this action"}. Ask the user how to proceed, or choose a safer alternative.`;
754
+ }
749
755
  }
750
756
  if (opts.reviewBudget?.exhausted)
751
757
  return "[permission] Review limit reached; not executed. Wait for human direction.";
package/dist/memory.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs"; // memory lives in a file on disk
2
2
  import path from "node:path"; // path joining
3
+ import { migrateLegacyState, projectMemoryPath } from "./state.js"; // one bucket per cwd, kept out of the checkout
3
4
  // Long-term memory: facts the agent should carry ACROSS sessions, not just
4
5
  // within one conversation. Session persistence (Day 12) restores "what we were
5
6
  // talking about"; this restores "what I should always know about this project".
@@ -13,7 +14,15 @@ import path from "node:path"; // path joining
13
14
  // assistant: 90% the model gets right isn't worth saving, the 10% it got wrong
14
15
  // and was corrected on is gold). Every fact is TYPED so the model can tell "this
15
16
  // is who the user is" from "this is a correction" from "this is a project fact".
16
- export const MEMORY_PATH = path.resolve(".mini-agent", "MEMORY.md");
17
+ // The file lives in the cwd's home bucket (state.ts), not inside the checkout,
18
+ // so a repo never carries agent memory in git status. Resolved per call so a
19
+ // chdir (tests, --cd) is honoured, and so the first call can migrate an older
20
+ // build's ./.mini-agent/MEMORY.md. Still one Markdown file, human-readable and
21
+ // human-editable: not a vector database, not embeddings.
22
+ export function memoryPath() {
23
+ migrateLegacyState();
24
+ return projectMemoryPath();
25
+ }
17
26
  // The four memory types (handbook §17). feedback is the most valuable.
18
27
  export const MEMORY_TYPES = ["user", "feedback", "project", "reference"];
19
28
  // Bounds, because unbounded memory dilutes the model's attention (Ch6: too many
@@ -38,7 +47,7 @@ function parseEntry(text) {
38
47
  export function readMemoryTyped() {
39
48
  try {
40
49
  return fs
41
- .readFileSync(MEMORY_PATH, "utf8")
50
+ .readFileSync(memoryPath(), "utf8")
42
51
  .split("\n")
43
52
  .filter((l) => l.startsWith("- "))
44
53
  .map((l) => parseEntry(l.slice(2).trim()))
@@ -91,8 +100,9 @@ export function addFact(fact, type = "project") {
91
100
  entries.shift(); // still too big — drop the oldest until it fits
92
101
  body = entries.map((e) => `- [${e.type}] ${e.fact}`).join("\n");
93
102
  }
94
- fs.mkdirSync(path.dirname(MEMORY_PATH), { recursive: true });
95
- fs.writeFileSync(MEMORY_PATH, HEADER + body + "\n", "utf8");
103
+ const file = memoryPath();
104
+ fs.mkdirSync(path.dirname(file), { recursive: true });
105
+ fs.writeFileSync(file, HEADER + body + "\n", "utf8");
96
106
  return `Remembered (${t}). (${entries.length} fact${entries.length === 1 ? "" : "s"} stored.)`;
97
107
  }
98
108
  // The tool the model calls to save something worth keeping.
@@ -3,6 +3,7 @@ import fs from "node:fs"; // resolve symlinks before auto mode grants file acces
3
3
  import os from "node:os"; // `cd ~` in the recoverable-shell analyzer
4
4
  import { execFileSync } from "node:child_process"; // ask git whether a deletion target is disposable
5
5
  import { CONFIG } from "./config.js"; // user-configured allow/deny rules from settings files
6
+ import { emit } from "./telemetry.js"; // a bypassed approval leaves an audit row, not silence
6
7
  // ---- The no-fly zone --------------------------------------------------------
7
8
  // Writes here are never OK, in any mode. .git can destroy history, shell rc
8
9
  // files inject code into every future terminal, .ssh/.env leak credentials.
@@ -442,6 +443,18 @@ export function recoverableShell(command) {
442
443
  }
443
444
  return readOnly ? { readOnly, reason: "read-only command" } : { readOnly, reason: "recoverable: git can undo it, or it only removes gitignored or temp files" };
444
445
  }
446
+ // ---- The user's prod guard (permissions.ask) ----------------------------------
447
+ // Text that always needs a human: a prod context, a deployment verb, a prod
448
+ // path. Checked BEFORE auto review and BEFORE the bypass rewrite, so neither
449
+ // can approve it. Case-insensitive substring, on the whole command or the path.
450
+ function guardHit(text) {
451
+ const haystack = text.toLowerCase();
452
+ for (const rule of CONFIG.permissions.ask ?? []) {
453
+ if (rule && haystack.includes(rule.toLowerCase()))
454
+ return rule;
455
+ }
456
+ return null;
457
+ }
445
458
  // Decide what a bash command deserves: deny, ask, or allow.
446
459
  function checkBash(command, auto = false) {
447
460
  const summary = command.trim(); // what the user will see in the prompt
@@ -458,6 +471,9 @@ function checkBash(command, auto = false) {
458
471
  for (const d of user.deny)
459
472
  if (command.toLowerCase().includes(d.toLowerCase()))
460
473
  return { decision: "deny", reason: `denied by your settings ("${d}")`, summary };
474
+ const guard = guardHit(command);
475
+ if (guard)
476
+ return { decision: "ask", requiresHuman: true, reason: `prod guard: "${guard}"`, summary };
461
477
  // node/npm/npx, git aliases and tool-wide grants can run arbitrary code.
462
478
  // Auto mode must inspect the actual command, including background commands.
463
479
  if (auto) {
@@ -539,7 +555,11 @@ export function checkPermission(toolName, argsJson, auto = false) {
539
555
  summary: base.summary,
540
556
  };
541
557
  }
542
- if (CONFIG.bypassPermissions && base.decision === "ask" && toolName !== "exit_plan_mode" && toolName !== "ask_user") {
558
+ if (CONFIG.bypassPermissions && base.decision === "ask" && !base.requiresHuman && toolName !== "exit_plan_mode" && toolName !== "ask_user") {
559
+ // Bypass may skip an ordinary approval, never one the user's own guard list
560
+ // marked for a human. Every skip is recorded: a bypass run with no audit row
561
+ // is indistinguishable from a run that never checked.
562
+ emit("agent_permission_bypassed", { tool: toolName, reason: base.reason });
543
563
  return { decision: "allow", reason: "permission approvals bypassed for this run", summary: base.summary };
544
564
  }
545
565
  return base;
@@ -645,6 +665,9 @@ function basePermission(toolName, argsJson, auto) {
645
665
  const hit = noFlyHit(p); // is it in the no-fly zone?
646
666
  if (hit)
647
667
  return { decision: "deny", reason: hit, summary: p }; // hard stop — deny always wins
668
+ const guard = guardHit(p); // the user's prod guard, applied to the path
669
+ if (guard)
670
+ return { decision: "ask", requiresHuman: true, reason: `prod guard: "${guard}"`, summary: p };
648
671
  // The user may pre-approve write tools ("tool:edit_file") to skip the
649
672
  // prompt — note this runs AFTER the no-fly check, so it widens "ask",
650
673
  // never "deny".
package/dist/session.js CHANGED
@@ -1,12 +1,18 @@
1
1
  import fs from "node:fs"; // session files live on disk
2
2
  import path from "node:path"; // path joining
3
3
  import { getGoal } from "./goal.js"; // the /goal rides along in the session file (Day 41)
4
- // Sessions are project-local: .mini-agent/sessions/<id>.json under the cwd.
5
- // Project-local (not global) because a conversation is about a codebase —
6
- // resuming a refactor of project A from inside project B makes no sense.
4
+ import { migrateLegacyState, projectSessionsDir } from "./state.js"; // one bucket per cwd, kept out of the checkout
5
+ // Sessions are per-project but not per-repo: <home>/mini-agent/projects/<slug>/sessions,
6
+ // where <slug> is the cwd flattened. Same reasoning as the old in-repo layout (a
7
+ // conversation is about a codebase, so resuming project A from inside project B
8
+ // would be wrong) without leaving an untracked directory in every checkout.
7
9
  // Resolved lazily (a function, not a const) so it always reflects the current
8
- // working directory — and so tests can chdir into a scratch dir.
9
- const sessionsDir = () => path.resolve(".mini-agent", "sessions");
10
+ // working directory, and so tests can chdir into a scratch dir. The first touch
11
+ // migrates any ./.mini-agent/sessions left by an older build.
12
+ const sessionsDir = () => {
13
+ migrateLegacyState();
14
+ return projectSessionsDir();
15
+ };
10
16
  const KEEP_SESSIONS = 20; // how many session files survive pruning
11
17
  // Where a session's file lives — absolute, so it can be handed to hooks.
12
18
  export function sessionPath(id) {
package/dist/state.js ADDED
@@ -0,0 +1,78 @@
1
+ import fs from "node:fs"; // moving legacy state, creating the home bucket
2
+ import os from "node:os"; // the home directory root
3
+ import path from "node:path"; // joining and resolving paths
4
+ // Per-project state that is history rather than configuration — session
5
+ // transcripts, long-term memory, and the local event/trace logs — lives OUTSIDE
6
+ // the checkout, one bucket per working directory, mirroring how Claude Code
7
+ // keeps ~/.claude/projects/<slug>. A repo you open should not grow an untracked
8
+ // state directory just because an agent ran in it; configuration and tooling
9
+ // (settings, skills, task board, team mailboxes, cron state) stay project-local
10
+ // where they belong to the code.
11
+ //
12
+ // The bucket is keyed by the absolute cwd with separators flattened, so
13
+ // /Users/me/proj becomes -Users-me-proj, the same escaping Claude Code uses.
14
+ export const projectsRoot = () => process.env.MINI_AGENT_PROJECTS_DIR || path.join(os.homedir(), ".config", "mini-agent", "projects");
15
+ // One directory name per working directory. Windows drive colons are flattened
16
+ // too, so the name is portable and cannot escape the root. Symlinks are resolved
17
+ // first, so one project reached as /tmp/x and /private/tmp/x keeps ONE bucket
18
+ // instead of two that each hold half the history.
19
+ export function projectSlug(cwd = process.cwd()) {
20
+ let abs = path.resolve(cwd);
21
+ try {
22
+ abs = fs.realpathSync(abs);
23
+ }
24
+ catch {
25
+ /* a path that does not exist yet still gets a stable slug */
26
+ }
27
+ return abs.replace(/[\\/:]/g, "-");
28
+ }
29
+ export function projectStateDir(cwd = process.cwd()) {
30
+ return path.join(projectsRoot(), projectSlug(cwd));
31
+ }
32
+ export function projectSessionsDir(cwd = process.cwd()) {
33
+ return path.join(projectStateDir(cwd), "sessions");
34
+ }
35
+ export function projectMemoryPath(cwd = process.cwd()) {
36
+ return path.join(projectStateDir(cwd), "MEMORY.md");
37
+ }
38
+ // Any other per-project log or file that should live beside sessions and memory
39
+ // rather than inside the checkout (telemetry, review-debug traces).
40
+ export function projectStateFile(name, cwd = process.cwd()) {
41
+ return path.join(projectStateDir(cwd), name);
42
+ }
43
+ // Move a path only when the destination is absent, so a second run is a no-op
44
+ // and a newly written home file is never clobbered by an old checkout copy.
45
+ // rename works on one filesystem; cp+rm covers the home-on-another-volume case.
46
+ function moveIfAbsent(from, to) {
47
+ if (fs.existsSync(to) || !fs.existsSync(from))
48
+ return;
49
+ fs.mkdirSync(path.dirname(to), { recursive: true });
50
+ try {
51
+ fs.renameSync(from, to);
52
+ }
53
+ catch {
54
+ fs.cpSync(from, to, { recursive: true });
55
+ fs.rmSync(from, { recursive: true, force: true });
56
+ }
57
+ }
58
+ let migrated = false; // once per process; the check is idempotent anyway
59
+ // Older builds wrote sessions and memory into ./.mini-agent. Move them into the
60
+ // home bucket the first time anything touches the new location, so an upgrade
61
+ // keeps its history and the checkout ends up clean. Never throws: a failed
62
+ // migration must not break the CLI, it just leaves the old files in place.
63
+ export function migrateLegacyState(cwd = process.cwd()) {
64
+ if (migrated)
65
+ return;
66
+ migrated = true;
67
+ try {
68
+ moveIfAbsent(path.resolve(cwd, ".mini-agent", "sessions"), projectSessionsDir(cwd));
69
+ moveIfAbsent(path.resolve(cwd, ".mini-agent", "MEMORY.md"), projectMemoryPath(cwd));
70
+ // Logs are per-project too, and telemetry is usually the biggest file left
71
+ // behind by an older checkout.
72
+ moveIfAbsent(path.resolve(cwd, ".mini-agent", "telemetry.jsonl"), projectStateFile("telemetry.jsonl", cwd));
73
+ moveIfAbsent(path.resolve(cwd, ".mini-agent", "review-debug.jsonl"), projectStateFile("review-debug.jsonl", cwd));
74
+ }
75
+ catch {
76
+ /* leave the legacy files where they are */
77
+ }
78
+ }
package/dist/telemetry.js CHANGED
@@ -1,14 +1,20 @@
1
1
  import fs from "node:fs"; // the event log lives on disk
2
2
  import path from "node:path"; // path joining
3
- // LOCAL-ONLY telemetry. Events go to .mini-agent/telemetry.jsonl in the
4
- // project directory and NOWHERE else — nothing leaves the machine, ever.
5
- // It exists because "no data" means every optimization is a guess: which
6
- // errors actually happen, how often compaction fires, which tools get denied.
7
- // Opt out entirely with MINI_AGENT_NO_TELEMETRY=1.
3
+ import { migrateLegacyState, projectStateFile } from "./state.js"; // one bucket per cwd, kept out of the checkout
4
+ // LOCAL-ONLY telemetry. Events go to the project's home bucket
5
+ // (~/.config/mini-agent/projects/<cwd-slug>/telemetry.jsonl) and NOWHERE else —
6
+ // nothing leaves the machine, ever. It exists because "no data" means every
7
+ // optimization is a guess: which errors actually happen, how often compaction
8
+ // fires, which tools get denied. Opt out entirely with MINI_AGENT_NO_TELEMETRY=1.
8
9
  //
9
10
  // Naming follows the unified-prefix convention (agent_<domain>_<action>) so
10
11
  // the log stays greppable: `grep agent_api_error telemetry.jsonl | wc -l`.
11
- const TELEMETRY_FILE = path.resolve(".mini-agent", "telemetry.jsonl");
12
+ // Resolved per call so a chdir is honoured, and so the first write migrates an
13
+ // older build's ./.mini-agent/telemetry.jsonl.
14
+ const telemetryFile = () => {
15
+ migrateLegacyState();
16
+ return projectStateFile("telemetry.jsonl");
17
+ };
12
18
  let sessionId = null; // set by initTelemetry; emit() is a no-op before that
13
19
  const tallies = new Map(); // per-session event counts, for /stats
14
20
  // Arm telemetry for this session. Tests and the eval harness never call this,
@@ -25,8 +31,9 @@ export function emit(event, fields = {}) {
25
31
  if (!sessionId)
26
32
  return; // disarmed — counters only, no file
27
33
  try {
28
- fs.mkdirSync(path.dirname(TELEMETRY_FILE), { recursive: true }); // ensure the directory
29
- fs.appendFileSync(TELEMETRY_FILE, JSON.stringify({ ts: new Date().toISOString(), session: sessionId, event, ...fields }) + "\n"); // one JSON object per line
34
+ const file = telemetryFile();
35
+ fs.mkdirSync(path.dirname(file), { recursive: true }); // ensure the directory
36
+ fs.appendFileSync(file, JSON.stringify({ ts: new Date().toISOString(), session: sessionId, event, ...fields }) + "\n"); // one JSON object per line
30
37
  }
31
38
  catch {
32
39
  /* a full disk or a read-only checkout is not our problem to escalate */
@@ -39,5 +46,5 @@ export function statsReport() {
39
46
  const lines = [...tallies.entries()]
40
47
  .sort((a, b) => b[1] - a[1]) // busiest first
41
48
  .map(([k, n]) => ` ${String(n).padStart(5)} ${k}`); // aligned counts
42
- return ["events this session:", ...lines, `\nfull log: ${TELEMETRY_FILE} (local only — nothing leaves this machine)`].join("\n");
49
+ return ["events this session:", ...lines, `\nfull log: ${telemetryFile()} (local only — nothing leaves this machine)`].join("\n");
43
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-from-zero",
3
- "version": "0.35.7",
3
+ "version": "0.37.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mini-agent": "dist/agent.js"
@@ -17,7 +17,7 @@
17
17
  "auto:report": "tsx eval/auto-report.ts",
18
18
  "build": "tsc -p tsconfig.build.json",
19
19
  "prepare": "npm run build",
20
- "test": "export MINI_AGENT_REVIEW_DEBUG=0 && tsx tests/tools.test.ts && tsx tests/permissions.test.ts && tsx tests/context.test.ts && tsx tests/hooks.test.ts && tsx tests/mcp.test.ts && tsx tests/judge.test.ts && tsx tests/auto.test.ts && tsx tests/auto-context.test.ts && tsx tests/auto-providers.test.ts && tsx tests/auto-cascade.test.ts && tsx tests/auto-rules.test.ts && tsx tests/auto-rule-cascade.test.ts && tsx tests/auto-debug.test.ts && tsx tests/auto-report.test.ts && tsx tests/auto-clarification.test.ts && tsx tests/memory.test.ts && tsx tests/cost.test.ts && tsx tests/cli.test.ts && tsx tests/print.test.ts && tsx tests/status.test.ts && tsx tests/validate.test.ts && tsx tests/plan.test.ts && tsx tests/diff.test.ts && tsx tests/undo.test.ts && tsx tests/tiering.test.ts && tsx tests/mcp-http.test.ts && tsx tests/mcp-oauth.test.ts && tsx tests/changes.test.ts && tsx tests/mentions.test.ts && tsx tests/session.test.ts && tsx tests/title.test.ts && tsx tests/ui.test.ts && tsx tests/activity.test.ts && tsx tests/follow-up.test.ts && tsx tests/follow-up-ui.test.tsx && tsx tests/agents.test.ts && tsx tests/images.test.ts && tsx tests/approval.test.ts && tsx tests/form.test.ts && tsx tests/model.test.ts && tsx tests/reasoning.test.ts && tsx tests/effort.test.ts && tsx tests/completion.test.ts && tsx tests/pasted-text.test.ts && tsx tests/skills.test.ts && tsx tests/markdown.test.ts && tsx tests/editor.test.ts && tsx tests/todos.test.ts && tsx tests/background.test.ts && tsx tests/team.test.ts && tsx tests/peers.test.ts && tsx tests/suggestion.test.ts && tsx tests/board.test.ts && tsx tests/drop.test.ts && tsx tests/editline.test.ts && tsx tests/cron.test.ts && tsx tests/goal.test.ts"
20
+ "test": "export MINI_AGENT_REVIEW_DEBUG=0 && tsx tests/tools.test.ts && tsx tests/permissions.test.ts && tsx tests/context.test.ts && tsx tests/hooks.test.ts && tsx tests/mcp.test.ts && tsx tests/judge.test.ts && tsx tests/auto.test.ts && tsx tests/auto-context.test.ts && tsx tests/auto-providers.test.ts && tsx tests/auto-cascade.test.ts && tsx tests/auto-rules.test.ts && tsx tests/auto-rule-cascade.test.ts && tsx tests/auto-debug.test.ts && tsx tests/auto-report.test.ts && tsx tests/auto-clarification.test.ts && tsx tests/memory.test.ts && tsx tests/cost.test.ts && tsx tests/cli.test.ts && tsx tests/print.test.ts && tsx tests/status.test.ts && tsx tests/validate.test.ts && tsx tests/plan.test.ts && tsx tests/diff.test.ts && tsx tests/undo.test.ts && tsx tests/tiering.test.ts && tsx tests/mcp-http.test.ts && tsx tests/mcp-oauth.test.ts && tsx tests/changes.test.ts && tsx tests/mentions.test.ts && tsx tests/state.test.ts && tsx tests/session.test.ts && tsx tests/title.test.ts && tsx tests/ui.test.ts && tsx tests/activity.test.ts && tsx tests/follow-up.test.ts && tsx tests/follow-up-ui.test.tsx && tsx tests/agents.test.ts && tsx tests/images.test.ts && tsx tests/approval.test.ts && tsx tests/form.test.ts && tsx tests/model.test.ts && tsx tests/reasoning.test.ts && tsx tests/effort.test.ts && tsx tests/completion.test.ts && tsx tests/pasted-text.test.ts && tsx tests/skills.test.ts && tsx tests/markdown.test.ts && tsx tests/editor.test.ts && tsx tests/todos.test.ts && tsx tests/background.test.ts && tsx tests/team.test.ts && tsx tests/peers.test.ts && tsx tests/suggestion.test.ts && tsx tests/board.test.ts && tsx tests/drop.test.ts && tsx tests/editline.test.ts && tsx tests/cron.test.ts && tsx tests/goal.test.ts"
21
21
  },
22
22
  "engines": {
23
23
  "node": ">=20.6"