atom-agent 0.3.0 → 1.1.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/CHANGELOG.md +82 -0
- package/README.md +83 -32
- package/dist/App.js +2178 -318
- package/dist/adapters.js +146 -15
- package/dist/agent/gates.js +153 -0
- package/dist/agent/loop-guard.js +184 -0
- package/dist/agent/loop.js +908 -0
- package/dist/agent/normalize.js +144 -0
- package/dist/agent/types.js +1 -0
- package/dist/auth.js +2 -1
- package/dist/cli.js +68 -6
- package/dist/compact.js +6 -48
- package/dist/config.js +171 -0
- package/dist/context-manager.js +564 -0
- package/dist/kilo.js +343 -0
- package/dist/local-discovery.js +308 -0
- package/dist/policy.js +286 -0
- package/dist/prompt-cache.js +99 -0
- package/dist/providers.js +183 -2
- package/dist/rollback.js +21 -0
- package/dist/scheduler.js +247 -0
- package/dist/session.js +35 -3
- package/dist/skills.js +214 -43
- package/dist/snapshots.js +57 -2
- package/dist/system.js +8 -1
- package/dist/telemetry-dashboard.js +589 -0
- package/dist/telemetry-server.js +301 -0
- package/dist/telemetry.js +1056 -0
- package/dist/tools/dir-cache.js +207 -0
- package/dist/tools/filesystem.js +149 -0
- package/dist/tools/fingerprints.js +33 -0
- package/dist/tools/overflow.js +76 -0
- package/dist/tools/read-cache.js +160 -0
- package/dist/tools/registry.js +802 -0
- package/dist/tools/search.js +242 -0
- package/dist/tools/shared.js +31 -0
- package/dist/tools/shell.js +273 -0
- package/dist/tools/todo.js +191 -0
- package/dist/tools/web.js +454 -0
- package/dist/tools.js +17 -1863
- package/dist/ui/activity.js +51 -0
- package/dist/ui/diff-panel.js +55 -0
- package/dist/ui/diff-view.js +112 -0
- package/dist/ui/diff.js +422 -0
- package/dist/ui/errors.js +129 -0
- package/dist/ui/highlight.js +120 -0
- package/dist/ui/input-model.js +115 -0
- package/dist/ui/input.js +40 -0
- package/dist/ui/live-tail.js +15 -0
- package/dist/ui/markdown.js +525 -0
- package/dist/ui/modals.js +47 -0
- package/dist/ui/palette.js +70 -0
- package/dist/ui/pickers.js +32 -0
- package/dist/ui/side-by-side.js +144 -0
- package/dist/ui/status-bar.js +75 -0
- package/dist/ui/theme.js +128 -0
- package/dist/ui/todo-panel.js +30 -0
- package/dist/ui/tool-inspector.js +59 -0
- package/dist/ui/transcript.js +128 -0
- package/dist/zen.js +145 -666
- package/package.json +1 -1
package/dist/snapshots.js
CHANGED
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
//
|
|
9
9
|
// Session-scoped and in-memory (small files stay as Buffers; files over
|
|
10
10
|
// SNAPSHOT_OVERFLOW_BYTES spill a copy under the OS temp dir — never the
|
|
11
|
-
// repo itself).
|
|
11
|
+
// repo itself). Checkpoints are bound to the history lineage they were
|
|
12
|
+
// captured in: any history replacement (/clear, /new, /resume, compaction)
|
|
13
|
+
// drops them via clearSnapshots (see src/rollback.ts) — disk files are
|
|
14
|
+
// unaffected, only the undo evidence goes. Restores are byte-exact and hash-verified (sha256 of the
|
|
12
15
|
// bytes on disk must equal the pre-mutation hash, not a model rewrite).
|
|
13
16
|
// Shell side effects (bash) are explicitly out of scope: commands are never
|
|
14
17
|
// snapshotted and cannot be undone — the /rewind UI says so outright.
|
|
15
18
|
import { createHash, randomBytes } from "node:crypto";
|
|
19
|
+
import * as fs from "node:fs";
|
|
16
20
|
import { promises as fsp } from "node:fs";
|
|
17
21
|
import * as os from "node:os";
|
|
18
22
|
import * as path from "node:path";
|
|
@@ -47,8 +51,12 @@ function currentMarks() {
|
|
|
47
51
|
}
|
|
48
52
|
return { history: 0, turns: 0 };
|
|
49
53
|
}
|
|
50
|
-
/** Test isolation (plus
|
|
54
|
+
/** Test isolation (plus history-lineage resets): drops every checkpoint.
|
|
55
|
+
* Returns the number dropped so callers can report discarded undo evidence.
|
|
56
|
+
* Disk files are untouched — only the in-memory evidence (and its temp
|
|
57
|
+
* overflow copies) goes. */
|
|
51
58
|
export function clearSnapshots() {
|
|
59
|
+
const dropped = checkpoints.length;
|
|
52
60
|
for (const cp of checkpoints) {
|
|
53
61
|
for (const f of cp.files) {
|
|
54
62
|
if (f.overflowPath) {
|
|
@@ -58,6 +66,7 @@ export function clearSnapshots() {
|
|
|
58
66
|
}
|
|
59
67
|
checkpoints = [];
|
|
60
68
|
seq = 0;
|
|
69
|
+
return dropped;
|
|
61
70
|
}
|
|
62
71
|
/** Newest-last copy for the picker and tests (the stored entries stay private). */
|
|
63
72
|
export function listCheckpoints() {
|
|
@@ -69,6 +78,43 @@ export function getCheckpoint(id) {
|
|
|
69
78
|
function snapshotDir() {
|
|
70
79
|
return path.join(os.tmpdir(), SNAPSHOT_DIR);
|
|
71
80
|
}
|
|
81
|
+
// Crash-leftover overflow copies (a killed process never runs its eviction)
|
|
82
|
+
// would leak in the temp dir forever: prune files older than maxAgeMs on
|
|
83
|
+
// every new spill, mirroring the tool overflow-file precedent. Synchronous
|
|
84
|
+
// and best-effort, never throws. Returns the number removed (for tests).
|
|
85
|
+
export const SNAPSHOT_OVERFLOW_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
86
|
+
export function pruneStaleSnapshotOverflow(maxAgeMs = SNAPSHOT_OVERFLOW_MAX_AGE_MS) {
|
|
87
|
+
try {
|
|
88
|
+
const dir = snapshotDir();
|
|
89
|
+
let entries;
|
|
90
|
+
try {
|
|
91
|
+
entries = fs.readdirSync(dir);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return 0; // nothing spilled yet — nothing to prune
|
|
95
|
+
}
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
let removed = 0;
|
|
98
|
+
for (const name of entries) {
|
|
99
|
+
if (!name.startsWith("snapshot-"))
|
|
100
|
+
continue;
|
|
101
|
+
try {
|
|
102
|
+
const p = path.join(dir, name);
|
|
103
|
+
if (now - fs.statSync(p).mtimeMs > maxAgeMs) {
|
|
104
|
+
fs.rmSync(p, { force: true });
|
|
105
|
+
removed += 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// ignore per-file failures (a stale spill is harmless)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return removed;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
72
118
|
function newCheckpointId(nextSeq) {
|
|
73
119
|
return `${Date.now().toString(36)}-${nextSeq.toString(36)}${randomBytes(3).toString("hex")}`;
|
|
74
120
|
}
|
|
@@ -83,6 +129,7 @@ async function readPrior(abs) {
|
|
|
83
129
|
const hash = createHash("sha256").update(bytes).digest("hex");
|
|
84
130
|
if (bytes.byteLength > SNAPSHOT_OVERFLOW_BYTES) {
|
|
85
131
|
try {
|
|
132
|
+
pruneStaleSnapshotOverflow();
|
|
86
133
|
const dir = snapshotDir();
|
|
87
134
|
await fsp.mkdir(dir, { recursive: true });
|
|
88
135
|
const name = `snapshot-${process.pid}-${Date.now().toString(36)}-${randomBytes(4).toString("hex")}.bin`;
|
|
@@ -179,6 +226,12 @@ export async function restoreCheckpointFiles(id, onRestored) {
|
|
|
179
226
|
const prior = await priorBytesOf(f);
|
|
180
227
|
if (prior === null)
|
|
181
228
|
return `Error: rewind failed: snapshot for ${f.abs} is unreadable`;
|
|
229
|
+
// Pre-write verification: the snapshot bytes in hand must hash to the
|
|
230
|
+
// pre-mutation hash BEFORE anything touches disk, so a corrupt snapshot
|
|
231
|
+
// fails loudly while leaving the live file exactly as it was.
|
|
232
|
+
if (createHash("sha256").update(prior).digest("hex") !== f.hash) {
|
|
233
|
+
return `Error: rewind failed: hash mismatch restoring ${f.abs}`;
|
|
234
|
+
}
|
|
182
235
|
try {
|
|
183
236
|
await fsp.mkdir(path.dirname(f.abs), { recursive: true });
|
|
184
237
|
await fsp.writeFile(f.abs, prior);
|
|
@@ -186,6 +239,8 @@ export async function restoreCheckpointFiles(id, onRestored) {
|
|
|
186
239
|
catch {
|
|
187
240
|
return `Error: rewind failed: cannot restore ${f.abs}`;
|
|
188
241
|
}
|
|
242
|
+
// Post-write re-read: guards a concurrent modification racing the
|
|
243
|
+
// restore itself (the bytes just written must still hash correctly).
|
|
189
244
|
let check;
|
|
190
245
|
try {
|
|
191
246
|
check = await fsp.readFile(f.abs);
|
package/dist/system.js
CHANGED
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
// add project/repo instructions, edit AGENTS.md.
|
|
8
8
|
//
|
|
9
9
|
// NOTE: the first line is pinned — tests/app.test.tsx asserts the prompt
|
|
10
|
-
// starts with it. Keep it stable.
|
|
10
|
+
// starts with it. Keep it stable. The last line orients the model to the
|
|
11
|
+
// harness contract (single copy — tool descriptions must NOT repeat it):
|
|
12
|
+
// every executor returns a string and never throws, so failures always
|
|
13
|
+
// arrive as `Error: ...` text inside the result (invalid args say how to
|
|
14
|
+
// fix; a denial means replan, never retry).
|
|
11
15
|
export const SYSTEM_PROMPT = [
|
|
12
16
|
"You are ATOM, a long-horizon coding agent that works through tools.",
|
|
13
17
|
"",
|
|
@@ -17,6 +21,9 @@ export const SYSTEM_PROMPT = [
|
|
|
17
21
|
"Prefer the smallest correct change. Fix root causes. Handle errors and edge cases. Remove dead code.",
|
|
18
22
|
"Ground every claim in tool output, never in memory. Run commands to check facts.",
|
|
19
23
|
"After each tool result, reflect briefly, then take the best next action toward the goal.",
|
|
24
|
+
"Batch independent work in one block: parallel-safe reads and searches in the same response run concurrently and finish in a single round-trip — one call per response is the slow path.",
|
|
20
25
|
"Keep calling tools until verified done. Never end on an unverified summary or a guess.",
|
|
21
26
|
"Done means tests and typecheck pass, or the blocker is named with its evidence.",
|
|
27
|
+
"",
|
|
28
|
+
"Harness contract: tools never throw — results are strings, failures arrive as `Error: ...` text. Read the error and adapt: invalid args say how to fix, a denial means replan around it, never retry it.",
|
|
22
29
|
].join("\n");
|