atom-lite 0.6.3 → 0.8.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 +25 -0
- package/README.md +3 -2
- package/dist/agent/turn-recorder.js +2 -0
- package/dist/agent/turn-recorder.js.map +1 -1
- package/dist/cli/app.js +186 -7
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands.d.ts +2 -0
- package/dist/cli/commands.js +19 -2
- package/dist/cli/commands.js.map +1 -1
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.js +10 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/load.js +5 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +20 -0
- package/dist/config/schema.js +13 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/sessions/events.js +4 -5
- package/dist/sessions/events.js.map +1 -1
- package/dist/sessions/store.js +0 -16
- package/dist/sessions/store.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/skills/code-review/SKILL.md +75 -32
- package/skills/code-review/agents/openai.yaml +3 -0
- package/skills/pr/CREDITS.md +3 -0
- package/skills/pr/SKILL.md +170 -0
- package/skills/pr/agents/openai.yaml +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,31 @@ All notable changes to this project are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.0] - 2026-11-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Configurable keyboard shortcuts via the `keybindings` config section.
|
|
12
|
+
- `/shortcuts` command to list active shortcuts.
|
|
13
|
+
- `/keybindings` command to open the keybindings config file.
|
|
14
|
+
- Input history on Up/Down using the editor's native history.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Arrow keys no longer break slash-command autocomplete navigation.
|
|
18
|
+
|
|
19
|
+
## [0.7.0] - 2026-11-06
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Clickable “↓ bottom” control above the status line to jump the transcript to the end.
|
|
23
|
+
- `/rename` command (replacing `/session`) for showing or renaming the current session.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- Resuming a session via `/sessions` now rebuilds rich transcript components (Markdown, collapsible tool boxes with output/diff/error state) instead of flattening to raw text.
|
|
27
|
+
- Thinking blocks are finalized before tool calls, so later thinking steps render as separate blocks.
|
|
28
|
+
- Session JSONL storage trimmed: removed redundant `tool_call_started` events and duplicated top-level message fields.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Session tool results now persist `isError` and `diff` for faithful resume rendering.
|
|
32
|
+
|
|
8
33
|
## [0.6.3] - 2026-11-06
|
|
9
34
|
|
|
10
35
|
### Added
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/atom-lite)
|
|
8
|
+
[](https://www.npmjs.com/package/atom-lite)
|
|
8
9
|
[](https://github.com/beast-ofcourse/atom-lite/actions/workflows/ci.yml)
|
|
9
10
|
[](https://nodejs.org)
|
|
10
11
|
[](https://www.typescriptlang.org)
|
|
@@ -170,7 +171,7 @@ Type `/help` for the grouped list, or press `ctrl+p` for the fuzzy command palet
|
|
|
170
171
|
| `/model [model]` | Show or switch the active model |
|
|
171
172
|
| `/provider [profile]` | Show or switch the active provider |
|
|
172
173
|
| `/effort [low\|medium\|high]` | Set reasoning effort |
|
|
173
|
-
| `/
|
|
174
|
+
| `/rename [rename <title>]` | Show or rename the current session |
|
|
174
175
|
| `/sessions [all]` | Search and resume a session |
|
|
175
176
|
| `/search <query>` | Search sessions by title or content |
|
|
176
177
|
| `/export [path]` | Export the session transcript |
|
|
@@ -189,7 +190,7 @@ Type `/help` for the grouped list, or press `ctrl+p` for the fuzzy command palet
|
|
|
189
190
|
|
|
190
191
|
## Sessions
|
|
191
192
|
|
|
192
|
-
Sessions are append-only JSONL event logs recording everything in one conversation. They are resumable across CLI restarts and grouped by workspace. The session index derives a title from the first user message unless `/
|
|
193
|
+
Sessions are append-only JSONL event logs recording everything in one conversation. They are resumable across CLI restarts and grouped by workspace. The session index derives a title from the first user message unless `/rename rename <title>` overrides it, and records the provider, update time, and message count. `/sessions` resumes a session in place: retained messages are replayed into the transcript and a `session_resumed` event is appended. `/search <query>` matches titles, message content, and workspace paths, ranking title hits first. `--list-sessions` and `--search-sessions` print the same index as stable tab-separated rows for scripts. Compaction summarizes older history to stay within the context budget while retaining the full transcript.
|
|
193
194
|
|
|
194
195
|
## Context management
|
|
195
196
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-recorder.js","sourceRoot":"","sources":["../../src/agent/turn-recorder.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"turn-recorder.js","sourceRoot":"","sources":["../../src/agent/turn-recorder.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadConfig } from "../config/load.js";
|
|
2
2
|
import { DEFAULT_SYSTEM_PROMPT } from "../agent/system-prompt.js";
|
|
3
|
-
import { defaultAgentDir, userConfigDir } from "../config/paths.js";
|
|
3
|
+
import { defaultAgentDir, defaultUserConfigPath, userConfigDir } from "../config/paths.js";
|
|
4
4
|
import { saveProviderSelection, saveTheme, } from "../config/write.js";
|
|
5
5
|
import { resolveApiKey, saveApiKey } from "../config/credentials.js";
|
|
6
6
|
import { join } from "node:path";
|
|
@@ -27,7 +27,7 @@ import { collectExtensionTools } from "../extensions/tool-adapter.js";
|
|
|
27
27
|
import { denyProject, trustProject } from "../extensions/trust.js";
|
|
28
28
|
import { ProjectTrustPrompt } from "./trust-prompt.js";
|
|
29
29
|
import { formatSessionList, formatSessionSearch, searchSessions, sessionTitleFromEvents, } from "../sessions/search.js";
|
|
30
|
-
import { providerSwitchNotice,
|
|
30
|
+
import { providerSwitchNotice, sessionSelectionFromEvents, } from "../sessions/history.js";
|
|
31
31
|
import { blockAtLine, createMouseCapture, handleMouseEvent, parseSgrMouse, shouldEnableMouse, } from "./mouse.js";
|
|
32
32
|
import { readTool, writeTool, editTool, bashTool, webfetchTool, websearchTool, grepTool, globTool, taskTool, } from "../tools/index.js";
|
|
33
33
|
import { McpManager, formatMcpStatus, formatMcpDoctor, createMcpTools, } from "../mcp/index.js";
|
|
@@ -342,7 +342,7 @@ export async function run(args) {
|
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
344
344
|
// ---- Interactive TUI (first-class) ----
|
|
345
|
-
const { TuiAltScreen, Text, Input, Editor, Container, Spacer, ScrollView, VStack, Loader, Markdown, Box, } = await import("@earendil-works/pi-tui");
|
|
345
|
+
const { TuiAltScreen, Text, Input, Editor, Container, Spacer, ScrollView, VStack, Loader, Markdown, Box, visibleWidth, } = await import("@earendil-works/pi-tui");
|
|
346
346
|
const mouseEnabled = shouldEnableMouse({
|
|
347
347
|
interactive,
|
|
348
348
|
configured: config.ui.mouse,
|
|
@@ -487,18 +487,37 @@ export async function run(args) {
|
|
|
487
487
|
}
|
|
488
488
|
originalHandleInput(data);
|
|
489
489
|
};
|
|
490
|
+
const jumpToBottomLabel = "↓ bottom";
|
|
491
|
+
const jumpToBottomView = {
|
|
492
|
+
render(width) {
|
|
493
|
+
const label = output.isFollowingEnd
|
|
494
|
+
? theme.tokens.dim(jumpToBottomLabel)
|
|
495
|
+
: theme.tokens.accent(jumpToBottomLabel);
|
|
496
|
+
const pad = Math.max(0, width - visibleWidth(jumpToBottomLabel));
|
|
497
|
+
return [" ".repeat(pad) + label];
|
|
498
|
+
},
|
|
499
|
+
invalidate() { },
|
|
500
|
+
};
|
|
490
501
|
const root = new VStack([]);
|
|
491
|
-
// Keep fixed chrome (spacer, input, status, header, dropdown)
|
|
492
|
-
// collapsed when the transcript grows; only the output region may
|
|
502
|
+
// Keep fixed chrome (spacer, input, jump-to-bottom, status, header, dropdown)
|
|
503
|
+
// from being collapsed when the transcript grows; only the output region may
|
|
504
|
+
// shrink.
|
|
493
505
|
root.addChild(output, { grow: 1, shrink: 1, minSize: 0 });
|
|
494
506
|
root.addChild(new Spacer(1), { grow: 0, shrink: 0, minSize: 1 });
|
|
495
507
|
root.addChild(input, { grow: 0, shrink: 0 });
|
|
508
|
+
root.addChild(jumpToBottomView, { grow: 0, shrink: 0, minSize: 1 });
|
|
496
509
|
root.addChild(statusBar, { grow: 0, shrink: 0 });
|
|
497
510
|
// folder:branch info below the status line, dimmed
|
|
498
511
|
root.addChild(header, { grow: 0, shrink: 0 });
|
|
499
512
|
const dropdownContainer = new Container();
|
|
500
513
|
root.addChild(dropdownContainer, { grow: 0, shrink: 0 });
|
|
501
514
|
tui.setLayoutRoot(root);
|
|
515
|
+
function jumpToBottomRow() {
|
|
516
|
+
const width = terminal.columns;
|
|
517
|
+
const outputHeight = Math.max(1, output.viewportHeight || output.render(width).length);
|
|
518
|
+
const inputHeight = Math.max(1, input.render(width).length);
|
|
519
|
+
return outputHeight + 1 + inputHeight;
|
|
520
|
+
}
|
|
502
521
|
tui.setFocus(input);
|
|
503
522
|
if (!noColor) {
|
|
504
523
|
try {
|
|
@@ -540,6 +559,8 @@ export async function run(args) {
|
|
|
540
559
|
let showThinking = config.ui.showThinking;
|
|
541
560
|
let expandTools = false;
|
|
542
561
|
let uiModalOpen = false;
|
|
562
|
+
const inputHistory = [];
|
|
563
|
+
let historyIndex = -1;
|
|
543
564
|
let closeActiveOverlay;
|
|
544
565
|
const toolBoxes = [];
|
|
545
566
|
/**
|
|
@@ -1320,6 +1341,34 @@ export async function run(args) {
|
|
|
1320
1341
|
openEffortPicker,
|
|
1321
1342
|
openThemePicker,
|
|
1322
1343
|
openSessionsPicker,
|
|
1344
|
+
openKeybindings: () => {
|
|
1345
|
+
const path = defaultUserConfigPath();
|
|
1346
|
+
appendLine(`keybindings config: ${path}`);
|
|
1347
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
1348
|
+
if (editor) {
|
|
1349
|
+
try {
|
|
1350
|
+
spawn(editor, [path], { stdio: "inherit" });
|
|
1351
|
+
}
|
|
1352
|
+
catch (error) {
|
|
1353
|
+
appendLine(`could not open editor: ${error instanceof Error ? error.message : String(error)}`);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
else if (process.platform === "linux") {
|
|
1357
|
+
try {
|
|
1358
|
+
spawn("xdg-open", [path], { detached: true, stdio: "ignore" }).unref();
|
|
1359
|
+
}
|
|
1360
|
+
catch {
|
|
1361
|
+
// Best effort.
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
tui.requestRender();
|
|
1365
|
+
},
|
|
1366
|
+
shortcutsText: () => {
|
|
1367
|
+
const kb = config.keybindings ?? {};
|
|
1368
|
+
return Object.entries(kb)
|
|
1369
|
+
.map(([action, key]) => `${action}: ${key ?? "(disabled)"}`)
|
|
1370
|
+
.join("\n");
|
|
1371
|
+
},
|
|
1323
1372
|
searchSessions: searchSessionsInStore,
|
|
1324
1373
|
renameSession,
|
|
1325
1374
|
listExtensions: () => {
|
|
@@ -1366,11 +1415,77 @@ export async function run(args) {
|
|
|
1366
1415
|
function restoreTranscript(next) {
|
|
1367
1416
|
streamText.finalize();
|
|
1368
1417
|
transcript.reset();
|
|
1418
|
+
// Drop stale references so toggles only affect the resumed transcript.
|
|
1419
|
+
toolBoxes.length = 0;
|
|
1369
1420
|
banner.setTheme(theme);
|
|
1370
1421
|
transcript.add(banner);
|
|
1371
1422
|
transcript.add(new Spacer(1));
|
|
1372
|
-
|
|
1373
|
-
|
|
1423
|
+
const messages = Array.isArray(next?.messages) ? next.messages : [];
|
|
1424
|
+
// Index tool results by their call id so each restored ToolBox can carry
|
|
1425
|
+
// its output and render as the same collapsible block used live.
|
|
1426
|
+
const resultsByCallId = new Map();
|
|
1427
|
+
for (const message of messages) {
|
|
1428
|
+
if (message?.role === "tool" && message.toolCallId) {
|
|
1429
|
+
resultsByCallId.set(String(message.toolCallId), message);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
const renderedToolCallIds = new Set();
|
|
1433
|
+
const textOf = (content) => {
|
|
1434
|
+
if (typeof content === "string")
|
|
1435
|
+
return content;
|
|
1436
|
+
if (Array.isArray(content)) {
|
|
1437
|
+
return content
|
|
1438
|
+
.map((part) => part?.type === "text" ? String(part.text ?? "") : "")
|
|
1439
|
+
.join("");
|
|
1440
|
+
}
|
|
1441
|
+
return "";
|
|
1442
|
+
};
|
|
1443
|
+
for (const message of messages) {
|
|
1444
|
+
if (!message || typeof message !== "object")
|
|
1445
|
+
continue;
|
|
1446
|
+
if (message.role === "system")
|
|
1447
|
+
continue;
|
|
1448
|
+
if (message.role === "user") {
|
|
1449
|
+
const text = textOf(message.content).trim();
|
|
1450
|
+
if (text) {
|
|
1451
|
+
transcript.add(new Text(theme.tokens.user(`> ${text}`)));
|
|
1452
|
+
}
|
|
1453
|
+
continue;
|
|
1454
|
+
}
|
|
1455
|
+
if (message.role === "assistant") {
|
|
1456
|
+
const text = textOf(message.content).trim();
|
|
1457
|
+
if (text) {
|
|
1458
|
+
transcript.add(new Markdown(text, 0, 0, markdownThemeFor(theme)));
|
|
1459
|
+
}
|
|
1460
|
+
for (const call of message.toolCalls ?? []) {
|
|
1461
|
+
const box = new ToolBox({
|
|
1462
|
+
id: String(call?.id ?? ""),
|
|
1463
|
+
name: String(call?.name ?? ""),
|
|
1464
|
+
args: call?.arguments ?? {},
|
|
1465
|
+
});
|
|
1466
|
+
box.setExpanded(expandTools);
|
|
1467
|
+
const result = resultsByCallId.get(String(call?.id ?? ""));
|
|
1468
|
+
if (result) {
|
|
1469
|
+
box.setResult(String(result.content ?? ""), {
|
|
1470
|
+
isError: result.isError === true,
|
|
1471
|
+
diff: Array.isArray(result.diff) ? result.diff : undefined,
|
|
1472
|
+
});
|
|
1473
|
+
renderedToolCallIds.add(String(call?.id ?? ""));
|
|
1474
|
+
}
|
|
1475
|
+
transcript.add(box);
|
|
1476
|
+
toolBoxes.push(box);
|
|
1477
|
+
}
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
if (message.role === "tool") {
|
|
1481
|
+
if (renderedToolCallIds.has(String(message.toolCallId ?? "")))
|
|
1482
|
+
continue;
|
|
1483
|
+
const text = String(message.content ?? "").trim();
|
|
1484
|
+
if (text) {
|
|
1485
|
+
transcript.add(new Text(theme.tokens.text(`[${message.name}] ${text}`)));
|
|
1486
|
+
}
|
|
1487
|
+
continue;
|
|
1488
|
+
}
|
|
1374
1489
|
}
|
|
1375
1490
|
tui.requestRender();
|
|
1376
1491
|
}
|
|
@@ -1702,6 +1817,13 @@ export async function run(args) {
|
|
|
1702
1817
|
return undefined;
|
|
1703
1818
|
if (!mouseEnabled)
|
|
1704
1819
|
return { consume: true };
|
|
1820
|
+
if (event.type === "press" &&
|
|
1821
|
+
event.button === "left" &&
|
|
1822
|
+
event.y === jumpToBottomRow()) {
|
|
1823
|
+
output.scrollToEnd();
|
|
1824
|
+
tui.requestRender();
|
|
1825
|
+
return { consume: true };
|
|
1826
|
+
}
|
|
1705
1827
|
handleMouseEvent(event, {
|
|
1706
1828
|
isModalOpen: () => uiModalOpen,
|
|
1707
1829
|
scrollBy: (lines) => output.scrollBy(lines),
|
|
@@ -1715,6 +1837,45 @@ export async function run(args) {
|
|
|
1715
1837
|
// Releases and repeats must not toggle modal shortcuts twice.
|
|
1716
1838
|
if (isKeyRelease(data) || isKeyRepeat(data))
|
|
1717
1839
|
return undefined;
|
|
1840
|
+
const keybindings = (config.keybindings ?? {});
|
|
1841
|
+
const matchesBinding = (action) => {
|
|
1842
|
+
const key = keybindings[action];
|
|
1843
|
+
return typeof key === "string" && matchesKey(data, key);
|
|
1844
|
+
};
|
|
1845
|
+
if (!uiModalOpen) {
|
|
1846
|
+
if (matchesBinding("jumpBottom")) {
|
|
1847
|
+
output.scrollToEnd();
|
|
1848
|
+
tui.requestRender();
|
|
1849
|
+
return { consume: true };
|
|
1850
|
+
}
|
|
1851
|
+
if (matchesBinding("newSession")) {
|
|
1852
|
+
session.messages.length = 0;
|
|
1853
|
+
content.clear();
|
|
1854
|
+
appendLine("started new session");
|
|
1855
|
+
tui.requestRender();
|
|
1856
|
+
return { consume: true };
|
|
1857
|
+
}
|
|
1858
|
+
if (matchesBinding("searchSessions")) {
|
|
1859
|
+
openSessionsPicker("workspace");
|
|
1860
|
+
return { consume: true };
|
|
1861
|
+
}
|
|
1862
|
+
if (matchesBinding("scrollUp")) {
|
|
1863
|
+
output.scrollBy(-5);
|
|
1864
|
+
tui.requestRender();
|
|
1865
|
+
return { consume: true };
|
|
1866
|
+
}
|
|
1867
|
+
if (matchesBinding("scrollDown")) {
|
|
1868
|
+
output.scrollBy(5);
|
|
1869
|
+
tui.requestRender();
|
|
1870
|
+
return { consume: true };
|
|
1871
|
+
}
|
|
1872
|
+
if (matchesBinding("toggleThinking")) {
|
|
1873
|
+
showThinking = !showThinking;
|
|
1874
|
+
appendLine(`thinking display: ${showThinking ? "shown" : "hidden"}`);
|
|
1875
|
+
tui.requestRender();
|
|
1876
|
+
return { consume: true };
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1718
1879
|
// Ctrl+P opens the command palette unless a modal owns the keyboard.
|
|
1719
1880
|
if (matchesKey(data, Key.ctrl("p")) && !uiModalOpen) {
|
|
1720
1881
|
openPalette();
|
|
@@ -1818,6 +1979,11 @@ export async function run(args) {
|
|
|
1818
1979
|
updateStatus();
|
|
1819
1980
|
}
|
|
1820
1981
|
else if (e.type === "tool_call") {
|
|
1982
|
+
if (thinkingText) {
|
|
1983
|
+
transcript.invalidate();
|
|
1984
|
+
thinkingText = null;
|
|
1985
|
+
thinkingBuffer = "";
|
|
1986
|
+
}
|
|
1821
1987
|
finalizeText();
|
|
1822
1988
|
activity.setPhase("working", e.name);
|
|
1823
1989
|
const box = new ToolBox({ id: e.id, name: e.name, args: e.args });
|
|
@@ -1845,6 +2011,11 @@ export async function run(args) {
|
|
|
1845
2011
|
}
|
|
1846
2012
|
}
|
|
1847
2013
|
else if (e.type === "final") {
|
|
2014
|
+
if (thinkingText) {
|
|
2015
|
+
transcript.invalidate();
|
|
2016
|
+
thinkingText = null;
|
|
2017
|
+
thinkingBuffer = "";
|
|
2018
|
+
}
|
|
1848
2019
|
finalizeText();
|
|
1849
2020
|
activity.stop();
|
|
1850
2021
|
}
|
|
@@ -2063,6 +2234,14 @@ export async function run(args) {
|
|
|
2063
2234
|
input.onSubmit = async (value) => {
|
|
2064
2235
|
const trimmed = value.trim();
|
|
2065
2236
|
input.setText("");
|
|
2237
|
+
if (trimmed) {
|
|
2238
|
+
try {
|
|
2239
|
+
input.addToHistory?.(trimmed);
|
|
2240
|
+
}
|
|
2241
|
+
catch {
|
|
2242
|
+
// Best effort; history is non-critical.
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2066
2245
|
if (!trimmed) {
|
|
2067
2246
|
tui.requestRender();
|
|
2068
2247
|
return;
|