atom-agent 1.3.0 → 1.5.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 +62 -0
- package/README.md +220 -224
- package/dist/App.js +922 -341
- package/dist/adapters.js +127 -14
- package/dist/agent/goal-evaluator.js +3 -0
- package/dist/agent/loop.js +211 -430
- package/dist/agent/tool-pipeline.js +398 -0
- package/dist/agent/turn-events.js +12 -0
- package/dist/cli.js +57 -8
- package/dist/compact.js +72 -8
- package/dist/config.js +19 -0
- package/dist/context-manager.js +6 -2
- package/dist/extensions.js +6 -0
- package/dist/file-diffs.js +108 -0
- package/dist/kilo.js +1 -1
- package/dist/local-discovery.js +2 -2
- package/dist/media.js +276 -0
- package/dist/overflow.js +140 -0
- package/dist/policy.js +8 -0
- package/dist/scheduler.js +38 -9
- package/dist/session-revert.js +125 -0
- package/dist/sessions.js +101 -0
- package/dist/snapshots.js +69 -0
- package/dist/system.js +2 -89
- package/dist/telemetry.js +26 -1
- package/dist/todos.js +241 -0
- package/dist/tools/filesystem.js +102 -22
- package/dist/tools/registry.js +184 -45
- package/dist/tools/ripgrep.js +7 -6
- package/dist/tools/search.js +172 -17
- package/dist/tools/shared.js +6 -0
- package/dist/tools.js +7 -39
- package/dist/ui/diff-panel.js +5 -5
- package/dist/ui/diff-view.js +16 -7
- package/dist/ui/diff.js +73 -51
- package/dist/ui/errors.js +20 -6
- package/dist/ui/input.js +24 -20
- package/dist/ui/live-tail.js +36 -1
- package/dist/ui/markdown.js +9 -4
- package/dist/ui/modals.js +6 -4
- package/dist/ui/paint-scheduler.js +120 -0
- package/dist/ui/palette.js +4 -2
- package/dist/ui/pickers.js +4 -1
- package/dist/ui/side-by-side.js +88 -27
- package/dist/ui/status-bar.js +63 -8
- package/dist/ui/stream-store.js +7 -0
- package/dist/ui/theme.js +23 -1
- package/dist/ui/todo-panel.js +5 -2
- package/dist/ui/tool-inspector.js +33 -4
- package/dist/ui/transcript.js +9 -6
- package/dist/web/events.js +93 -0
- package/dist/web/runtime.js +790 -0
- package/dist/web/server.js +570 -0
- package/dist/web/ui/app.js +1925 -0
- package/dist/web/ui/index.html +135 -0
- package/dist/web/ui/styles.css +515 -0
- package/dist/zen.js +115 -4
- package/documentation/cli.md +5 -5
- package/documentation/configuration.md +11 -6
- package/documentation/development.md +4 -3
- package/documentation/extensions.md +1 -1
- package/documentation/goals.md +1 -1
- package/documentation/index.md +4 -4
- package/documentation/providers.md +2 -3
- package/documentation/skills.md +3 -3
- package/documentation/tools.md +8 -3
- package/documentation/troubleshooting.md +1 -1
- package/examples/extensions/01-audit-gate.js +2 -2
- package/examples/extensions/02-notes-tool.js +2 -2
- package/examples/extensions/03-custom-command.js +2 -2
- package/package.json +3 -2
package/dist/ui/transcript.js
CHANGED
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
// All paint comes from ui/theme tokens — no literal colors or glyphs here.
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Box, Static, Text } from "ink";
|
|
8
|
-
import { SideBySideDiffView
|
|
8
|
+
import { SideBySideDiffView } from "./side-by-side.js";
|
|
9
9
|
import { ErrorCard, classifyToolError } from "./errors.js";
|
|
10
10
|
import { MarkdownText, ToolLine } from "./markdown.js";
|
|
11
11
|
import { theme } from "./theme.js";
|
|
@@ -53,10 +53,13 @@ export function renderTranscriptItem(item) {
|
|
|
53
53
|
return _jsx(StartupBanner, {}, item.id);
|
|
54
54
|
const t = item.turn;
|
|
55
55
|
const i = item.id;
|
|
56
|
-
// Committed thinking blocks read as
|
|
57
|
-
// with answers): dim
|
|
56
|
+
// Committed thinking blocks read as one grouped unit (never confused
|
|
57
|
+
// with answers): dim labeled header plus quoteBar-prefixed body lines —
|
|
58
|
+
// the same visual language as the live thinking block. The divider lives
|
|
59
|
+
// inside this row's own box (no extra Static rows), all dim per theme law.
|
|
58
60
|
if (t.thinking === true) {
|
|
59
|
-
|
|
61
|
+
const bodyLines = t.content.split("\n");
|
|
62
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [theme.symbol.thinking, " thinking"] }), bodyLines.map((line, idx) => (_jsx(Text, { dimColor: true, children: `${theme.symbol.quoteBar} ${line}` }, idx)))] }, i));
|
|
60
63
|
}
|
|
61
64
|
// Conversation turns (user/assistant) breathe: one blank line after each,
|
|
62
65
|
// so the eye lands on the next turn. Tool/status lines stay dense — they
|
|
@@ -73,9 +76,9 @@ export function renderTranscriptItem(item) {
|
|
|
73
76
|
// write/edit label swallowed by pairing (success line immediately
|
|
74
77
|
// followed by an error line) keeps its committed diff above the card.
|
|
75
78
|
const labelDiff = item.label?.diff;
|
|
76
|
-
return (_jsxs(React.Fragment, { children: [item.label ? _jsx(ToolLine, { content: item.label.content, ms: item.label.ms }) : null, labelDiff && !item.label?.error ? (_jsx(SideBySideDiffView, { oldText: labelDiff.oldText, newText: labelDiff.newText, lang: labelDiff.lang,
|
|
79
|
+
return (_jsxs(React.Fragment, { children: [item.label ? _jsx(ToolLine, { content: item.label.content, ms: item.label.ms, via: item.label.approvalVia }) : null, labelDiff && !item.label?.error ? (_jsx(SideBySideDiffView, { oldText: labelDiff.oldText, newText: labelDiff.newText, lang: labelDiff.lang, path: labelDiff.path })) : null, _jsx(ErrorCard, { classified: classified })] }, i));
|
|
77
80
|
}
|
|
78
|
-
return (_jsxs(React.Fragment, { children: [_jsx(ToolLine, { content: t.content, error: t.error, ms: t.ms }), t.diff && !t.error ? (_jsx(SideBySideDiffView, { oldText: t.diff.oldText, newText: t.diff.newText, lang: t.diff.lang,
|
|
81
|
+
return (_jsxs(React.Fragment, { children: [_jsx(ToolLine, { content: t.content, error: t.error, ms: t.ms, via: t.approvalVia }), t.diff && !t.error ? (_jsx(SideBySideDiffView, { oldText: t.diff.oldText, newText: t.diff.newText, lang: t.diff.lang, path: t.diff.path })) : null] }, i));
|
|
79
82
|
}
|
|
80
83
|
return (_jsxs(Box, { flexDirection: "column", marginBottom: theme.spacing.turnGap, children: [_jsx(Text, { children: _jsxs(Text, { color: theme.color.assistant, bold: true, children: [theme.symbol.speakerAssistant, " "] }) }), _jsx(MarkdownText, { text: t.content })] }, i));
|
|
81
84
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// WebUI event protocol: the SSE vocabulary the browser consumes.
|
|
2
|
+
//
|
|
3
|
+
// Every kind maps 1:1 to an existing ATOM callback or sink — nothing is
|
|
4
|
+
// invented. The runtime (./runtime.js) translates, this module only defines
|
|
5
|
+
// and serializes:
|
|
6
|
+
//
|
|
7
|
+
// - token / thinking ← StreamCallbacks.onToken / onThinking (accumulated
|
|
8
|
+
// text, same value the TUI renders in its live tail)
|
|
9
|
+
// - phase ← StreamCallbacks.onPhase ("thinking" | "streaming" |
|
|
10
|
+
// "tool" | "retry" | "done", detail carries the tool name / retry summary)
|
|
11
|
+
// - tool_delta ← StreamCallbacks.onToolDelta (name revealed mid-stream)
|
|
12
|
+
// - tool_started /
|
|
13
|
+
// tool_finished ← TurnEventsSink.onToolStarted / onToolFinished
|
|
14
|
+
// (stable toolCallId + name + index / isError — never display labels)
|
|
15
|
+
// - tool_call ← the approve() gate decision (name + effective args +
|
|
16
|
+
// description + decision + provenance — the only pre-execution arg source)
|
|
17
|
+
// - tool_activity ← AgenticOpts.onToolActivity (label + result + isError)
|
|
18
|
+
// - tool_result ← AgenticOpts.onToolResult (name + effective args +
|
|
19
|
+
// result + isError for EVERY committed call, including read-only tools
|
|
20
|
+
// that never consult approve; result text capped, see truncateEventText)
|
|
21
|
+
// - file_diff ← write/edit commits only: op (created/modified) +
|
|
22
|
+
// pre-computed unified hunks + side-by-side rows from src/ui/diff.ts
|
|
23
|
+
// (the same engine the TUI approval preview uses), all text-capped.
|
|
24
|
+
// ATOM has no delete tool and bash side effects are opaque by design
|
|
25
|
+
// (see src/rollback.ts), so deletions never appear as file events.
|
|
26
|
+
// - usage ← AgenticOpts.onUsage (API-reported tokens only)
|
|
27
|
+
// - reasoning ← AgenticOpts.onReasoning (per-POST reasoning label)
|
|
28
|
+
// - warning ← StreamCallbacks.onWarning
|
|
29
|
+
// - approval_request /
|
|
30
|
+
// approval_resolved ← the approve() gate (write/edit/bash in normal mode;
|
|
31
|
+
// the turn blocks until the browser POSTs a decision)
|
|
32
|
+
// - question_request /
|
|
33
|
+
// question_resolved ← the askUser() hook (ask_question tool; same blocking
|
|
34
|
+
// contract as approvals)
|
|
35
|
+
// - message ← committed transcript turns (user/assistant/tool rows)
|
|
36
|
+
// - error ← failed POST / tool-throw abort (caller rolls back)
|
|
37
|
+
// - done / cancelled ← clean turn end / LoopCancelledError rollback
|
|
38
|
+
//
|
|
39
|
+
// Pure module: types + SSE serialization only. No I/O, no loop imports.
|
|
40
|
+
export function createWebEvent(seq, kind, data) {
|
|
41
|
+
return {
|
|
42
|
+
seq,
|
|
43
|
+
at: new Date().toISOString(),
|
|
44
|
+
kind,
|
|
45
|
+
data: data ?? {},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Serialize one event as an SSE frame. `id:` carries the sequence so an
|
|
49
|
+
// EventSource client resumes without gaps; `event:` carries the kind so the
|
|
50
|
+
// browser dispatches without parsing the body first.
|
|
51
|
+
export function formatSSE(event) {
|
|
52
|
+
return `id: ${event.seq}\nevent: ${event.kind}\ndata: ${JSON.stringify(event)}\n\n`;
|
|
53
|
+
}
|
|
54
|
+
// SSE response headers shared by every event stream on the server.
|
|
55
|
+
export function sseHeaders() {
|
|
56
|
+
return {
|
|
57
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
58
|
+
"Cache-Control": "no-store",
|
|
59
|
+
"X-Content-Type-Options": "nosniff",
|
|
60
|
+
Connection: "keep-alive",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Parse one SSE frame back (tests + future resumable clients). Returns null
|
|
64
|
+
// for heartbeats/comments or malformed frames — never throws.
|
|
65
|
+
export function parseSSEFrame(frame) {
|
|
66
|
+
try {
|
|
67
|
+
const lines = frame.split("\n");
|
|
68
|
+
const dataLine = lines.find((l) => l.startsWith("data:"));
|
|
69
|
+
if (!dataLine)
|
|
70
|
+
return null;
|
|
71
|
+
const parsed = JSON.parse(dataLine.slice("data:".length).trim());
|
|
72
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
73
|
+
return null;
|
|
74
|
+
const o = parsed;
|
|
75
|
+
if (typeof o["seq"] !== "number" || typeof o["kind"] !== "string")
|
|
76
|
+
return null;
|
|
77
|
+
return parsed;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Reconnect replay: events after the client's last seen id, oldest first.
|
|
84
|
+
// Pure (unit-tested); the runtime and the SSE route share it.
|
|
85
|
+
export function eventsAfter(log, lastEventId) {
|
|
86
|
+
if (typeof lastEventId !== "number" || !Number.isFinite(lastEventId))
|
|
87
|
+
return [];
|
|
88
|
+
return log.filter((e) => e.seq > lastEventId);
|
|
89
|
+
}
|
|
90
|
+
// Heartbeat comment (keeps proxies/load-balancers from closing idle turns).
|
|
91
|
+
export function sseHeartbeat() {
|
|
92
|
+
return `: ping\n\n`;
|
|
93
|
+
}
|