smolcoder 0.4.3 → 0.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/README.md +12 -1
- package/dist/agent.js +9 -0
- package/dist/config.js +72 -0
- package/dist/index.js +79 -390
- package/dist/session.js +480 -0
- package/dist/tools/tasks.js +15 -0
- package/dist/web/channel.js +222 -0
- package/dist/web/client.js +815 -0
- package/dist/web/hub.js +786 -0
- package/dist/web/page.js +73 -366
- package/dist/web/store.js +199 -0
- package/dist/web/styles.js +222 -0
- package/dist/web/terminal.js +190 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,12 +91,23 @@ smol --model qwen3 # pick a model by partial name
|
|
|
91
91
|
smol --effort off # no thinking: the fastest setting for long tool loops
|
|
92
92
|
smol --mode bypass # never ask for approval
|
|
93
93
|
smol --ctx 16384 # cap the context window
|
|
94
|
-
smol --web #
|
|
94
|
+
smol --web # browser UI with a workspace sidebar (see below)
|
|
95
95
|
smol -p "fix the failing test" # headless: run one prompt, print the transcript, exit
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
Headless mode is for scripts and automation. It suppresses reasoning noise and the exit code tells you whether the run succeeded.
|
|
99
99
|
|
|
100
|
+
## The web UI
|
|
101
|
+
|
|
102
|
+
`smol --web` serves a local browser UI and prints a private URL (it carries a random key, and the server only listens on localhost). You can run it from anywhere, including your home folder: the page has a sidebar of your workspaces, and every workspace keeps its own list of sessions.
|
|
103
|
+
|
|
104
|
+
- **Many projects, many sessions.** Open a folder from the sidebar, start as many sessions as you like, and switch between them while they work. A dot next to each session shows whether it is busy, idle, or waiting for you to approve a command. Sessions you are not looking at keep streaming in the background.
|
|
105
|
+
- **Sessions survive restarts.** Transcripts are saved under `~/.smolcoder/sessions/`, so past sessions stay in the sidebar and can be resumed with a click, model and all. Close a session to stop it, delete it to forget it.
|
|
106
|
+
- **One server for everything.** Running `smol --web` from a second folder adds that folder to the already-running UI instead of starting another server.
|
|
107
|
+
- **A browser panel.** The globe icon opens a resizable panel on the right with browser tabs. Dev servers the agent starts show up as suggestions, so previewing the app it is building is one click.
|
|
108
|
+
- **A terminal panel.** The terminal icon (or ctrl+`) opens a shell in the current workspace, right next to the chat. It streams output without a TTY, which means interactive programs such as `vim` will not work there, but `npm test`, `git status` and friends do. The terminal, browser tabs and chat all live in the same panel, in tabs.
|
|
109
|
+
- `ctrl+b` hides and shows the sidebar.
|
|
110
|
+
|
|
100
111
|
## Tips
|
|
101
112
|
|
|
102
113
|
**Turn thinking off for long tasks.** `/effort off` disables reasoning on qwen3-class models, which makes each step several times faster. Thinking helps with planning and tricky bugs, but for a twenty-step build the model rarely needs it. Models without a thinking switch fall back silently.
|
package/dist/agent.js
CHANGED
|
@@ -78,6 +78,15 @@ class Agent {
|
|
|
78
78
|
this.toolCtx.commandsRun.length = 0;
|
|
79
79
|
this.ctxMgr.resetAnchor();
|
|
80
80
|
}
|
|
81
|
+
/** Resume a saved session: the transcript (without its system message) and
|
|
82
|
+
* the two requests the compaction note is built around. */
|
|
83
|
+
restoreTranscript(messages, originalRequest, currentRequest) {
|
|
84
|
+
this.messages = [this.messages[0], ...messages];
|
|
85
|
+
this.originalRequest = originalRequest;
|
|
86
|
+
this.currentRequest = currentRequest;
|
|
87
|
+
this.planNudged = false;
|
|
88
|
+
this.ctxMgr.resetAnchor();
|
|
89
|
+
}
|
|
81
90
|
cancel() {
|
|
82
91
|
this.abort?.abort();
|
|
83
92
|
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// User config (~/.smolcoder.json) and the data directory (~/.smolcoder/) that
|
|
3
|
+
// holds saved web sessions and the workspace list. Shared by the CLI entry
|
|
4
|
+
// point, the session loop and the web hub.
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DATA_DIR = exports.CONFIG_PATH = void 0;
|
|
40
|
+
exports.loadConfig = loadConfig;
|
|
41
|
+
exports.saveConfig = saveConfig;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
exports.CONFIG_PATH = path.join(os.homedir(), ".smolcoder.json");
|
|
46
|
+
exports.DATA_DIR = path.join(os.homedir(), ".smolcoder");
|
|
47
|
+
function loadConfig() {
|
|
48
|
+
try {
|
|
49
|
+
const cfg = JSON.parse(fs.readFileSync(exports.CONFIG_PATH, "utf8"));
|
|
50
|
+
// Never let bypass be inherited implicitly from a past session — a single
|
|
51
|
+
// shift+tab into it would otherwise silently persist unattended, unchecked
|
|
52
|
+
// command execution into every later run, including headless -p in CI.
|
|
53
|
+
// Requires an explicit flag (-m bypass / --bypass) each time. Old configs
|
|
54
|
+
// saved "write"/"yolo" under the previous mode names.
|
|
55
|
+
if (cfg.lastMode === "write")
|
|
56
|
+
cfg.lastMode = "edit";
|
|
57
|
+
if (cfg.lastMode === "yolo" || cfg.lastMode === "bypass")
|
|
58
|
+
cfg.lastMode = "edit";
|
|
59
|
+
return cfg;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function saveConfig(cfg) {
|
|
66
|
+
try {
|
|
67
|
+
fs.writeFileSync(exports.CONFIG_PATH, JSON.stringify(cfg, null, 2));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* non-fatal */
|
|
71
|
+
}
|
|
72
|
+
}
|