@semalt-ai/code 1.8.1 → 1.8.4
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/.claude/settings.local.json +14 -1
- package/CLAUDE.md +2 -1
- package/index.js +29 -8
- package/lib/agent.js +725 -133
- package/lib/api.js +193 -59
- package/lib/commands.js +263 -201
- package/lib/config.js +33 -4
- package/lib/constants.js +52 -2
- package/lib/metrics.js +16 -3
- package/lib/permissions.js +73 -73
- package/lib/prompts.js +90 -86
- package/lib/tool_specs.js +499 -0
- package/lib/tools.js +418 -198
- package/lib/ui/ansi.js +13 -1
- package/lib/ui/chat-history.js +212 -61
- package/lib/ui/create-ui.js +145 -377
- package/lib/ui/diff.js +91 -78
- package/lib/ui/format.js +247 -0
- package/lib/ui/input-field.js +200 -107
- package/lib/ui/layout.js +0 -2
- package/lib/ui/messages.js +44 -0
- package/lib/ui/select.js +114 -0
- package/lib/ui/status-bar.js +179 -42
- package/lib/ui/stream.js +8 -12
- package/lib/ui/terminal.js +60 -0
- package/lib/ui/theme.js +99 -0
- package/lib/ui/utils.js +135 -6
- package/lib/ui/writer.js +603 -0
- package/lib/ui.js +11 -6
- package/package.json +1 -1
- package/lib/ui/legacy.js +0 -130
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
4
|
"Bash(grep -oP '.{0,120}chat:stash.{0,120}' /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js)",
|
|
5
|
-
"Bash(grep -oP '.{0,100}externalEditor.{0,100}' /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js)"
|
|
5
|
+
"Bash(grep -oP '.{0,100}externalEditor.{0,100}' /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js)",
|
|
6
|
+
"Bash(node *)",
|
|
7
|
+
"Bash(git -C /srv/www/ai/semalt-code diff lib/constants.js lib/agent.js lib/prompts.js lib/tools.js)",
|
|
8
|
+
"Bash(git *)",
|
|
9
|
+
"WebFetch(domain:api.github.com)",
|
|
10
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
11
|
+
"WebFetch(domain:github.com)",
|
|
12
|
+
"Bash(xargs -I{} sh -c 'head -c 3000 \"$1\"' _ {})",
|
|
13
|
+
"Bash(xargs -I{} sh -c 'echo \"=== $1 ===\"; head -c 500 \"$1\"; echo' _ {})",
|
|
14
|
+
"Bash(xargs -I{} sh -c 'echo \"=== $1 ===\"; python3 -c \"import json,sys; d=json.load\\(open\\(\\\\\"$1\\\\\"\\)\\); print\\(len\\(d.get\\(\\\\\"messages\\\\\",[]\\)\\), \\\\\"msgs; roles:\\\\\", [m.get\\(\\\\\"role\\\\\"\\) for m in d.get\\(\\\\\"messages\\\\\",[]\\)[:20]]\\)\"' _ {})",
|
|
15
|
+
"Bash(python3 *)",
|
|
16
|
+
"Read(//tmp/**)",
|
|
17
|
+
"Bash(sed -i \"s/addMessage\\('>>> AI MSG 2'.*$/addMessage\\('>>> AI MSG 2', ['response body 2a', 'response body 2b']\\);\\\\nfor \\(let k = 3; k <= 8; k++\\) { addMessage\\('>>> USER MSG ' + k, ['line body ' + k]\\); addMessage\\('>>> AI MSG ' + k, ['response body ' + k + 'a', 'response body ' + k + 'b']\\); }/\" scroll-capture.js)",
|
|
18
|
+
"Bash(echo \"exit=$?\")"
|
|
6
19
|
]
|
|
7
20
|
}
|
|
8
21
|
}
|
package/CLAUDE.md
CHANGED
|
@@ -299,7 +299,7 @@ Managed by `lib/config.js`. Normalized on every load. The config directory is cr
|
|
|
299
299
|
- `max_output_lines` caps shell and HTTP response lines returned to the agent (default 50).
|
|
300
300
|
- `show_token_count` controls whether token count is shown in the status bar.
|
|
301
301
|
- `show_cost` reserved for future cost-display feature.
|
|
302
|
-
- `context_length` / `models[].context_length` — token limit used for context-usage bar and
|
|
302
|
+
- `context_length` / `models[].context_length` — token limit used for context-usage bar, warnings, and proactive trimming. Self-calibrating: when a request triggers a context-overflow 400 (`"context length is only N"`), `api.js` parses the real window, persists it to `config.context_length` (and to the matching `models[]` entry), and trims to ~90% of it on subsequent calls. The value is never cached in memory only — a restart keeps the learned limit.
|
|
303
303
|
- Local `models[]` entries override dashboard models when selected.
|
|
304
304
|
|
|
305
305
|
---
|
|
@@ -311,6 +311,7 @@ Managed by `lib/config.js`. Normalized on every load. The config directory is cr
|
|
|
311
311
|
- **Streaming**: `api.js` manually parses `text/event-stream`. The parser in `chatStream()` handles partial JSON lines — be careful editing it.
|
|
312
312
|
- **Permissions are per-session**: `PermissionManager` resets on each CLI invocation. Approvals never persist to disk. In non-TTY mode all tool calls are auto-approved with a warning.
|
|
313
313
|
- **Token counting is approximate**: `estimateTokens()` divides char count by 4. It is used only for the `/compact` display — do not rely on it for hard limits.
|
|
314
|
+
- **Context trimming is proactive when a limit is known**: `chatStream()` uses the in-process `_sessionInputLimits` learned from a prior 400 overflow first, then falls back to `config.context_length * 0.9`. When neither is set, no pre-flight trim runs and the client relies on the reactive 400/413 handler (which then persists the discovered window). `Metrics.tokenLimitStatus()` returns `{ used, limit: null }` until a limit is learned, so the status bar shows "N tok · limit unknown" instead of hiding the line.
|
|
314
315
|
- **Tool output is truncated**: `tools.js` caps output at `max_output_lines` (default 50). Configurable via config.
|
|
315
316
|
- **Max 10 agent iterations**: hard-coded in `agent.js`. Prevents runaway loops.
|
|
316
317
|
- **Malformed tags are skipped**: each tool dispatch in the agent loop is wrapped in try/catch; errors emit a warning line and continue to the next tool call.
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const path = require('path');
|
|
|
8
8
|
const { PACKAGE_JSON } = require('./lib/constants');
|
|
9
9
|
const { loadConfig, saveConfig, configSet, configShow } = require('./lib/config');
|
|
10
10
|
const ui = require('./lib/ui');
|
|
11
|
+
const { registerTerminalCleanup } = require('./lib/ui/terminal');
|
|
11
12
|
const { createPermissionManager } = require('./lib/permissions');
|
|
12
13
|
const { createToolExecutor, extractToolCalls } = require('./lib/tools');
|
|
13
14
|
const { readFileContext } = require('./lib/context');
|
|
@@ -17,6 +18,12 @@ const { createCommands } = require('./lib/commands');
|
|
|
17
18
|
const { parseArgs } = require('./lib/args');
|
|
18
19
|
const { CONFIG_PATH } = require('./lib/constants');
|
|
19
20
|
const { AUDIT_LOG } = require('./lib/audit');
|
|
21
|
+
const writer = require('./lib/ui/writer');
|
|
22
|
+
|
|
23
|
+
// Install process-wide signal handlers so every exit path (normal, SIGINT,
|
|
24
|
+
// SIGHUP, SIGTERM, uncaught exception) restores the terminal. Safe to call
|
|
25
|
+
// from multiple entrypoints — the function is internally idempotent.
|
|
26
|
+
registerTerminalCleanup();
|
|
20
27
|
|
|
21
28
|
let config = loadConfig();
|
|
22
29
|
|
|
@@ -53,10 +60,14 @@ const apiClient = createApiClient({
|
|
|
53
60
|
});
|
|
54
61
|
const { runAgentLoop } = createAgentRunner({
|
|
55
62
|
chatStream: apiClient.chatStream,
|
|
56
|
-
extractToolCalls,
|
|
63
|
+
extractToolCalls: (reply, options = {}) => extractToolCalls(reply, {
|
|
64
|
+
repairMalformedXml: !!getConfig().repair_malformed_tool_xml,
|
|
65
|
+
...options,
|
|
66
|
+
}),
|
|
57
67
|
agentExecShell,
|
|
58
68
|
agentExecFile,
|
|
59
69
|
ui,
|
|
70
|
+
getConfig,
|
|
60
71
|
});
|
|
61
72
|
const commands = createCommands({
|
|
62
73
|
getConfig,
|
|
@@ -80,7 +91,7 @@ async function main() {
|
|
|
80
91
|
const command = rawArgs[0];
|
|
81
92
|
|
|
82
93
|
if (command === '--help' || command === '-h') {
|
|
83
|
-
|
|
94
|
+
writer.scrollback(`
|
|
84
95
|
Semalt.AI — Self-hosted AI Coding Assistant
|
|
85
96
|
|
|
86
97
|
Usage: semalt-code [command] [options]
|
|
@@ -113,17 +124,20 @@ Options:
|
|
|
113
124
|
--allow-exec Auto-approve shell command execution
|
|
114
125
|
--allow-net Auto-approve network operations
|
|
115
126
|
--allow-all Auto-approve everything (use carefully)
|
|
127
|
+
--allow-anywhere Allow writes outside the project CWD and in sensitive dirs
|
|
116
128
|
--readonly Block all write operations
|
|
117
129
|
--new Skip session resume prompt
|
|
118
130
|
-v, --version Show CLI version
|
|
119
131
|
|
|
120
132
|
Config: ${CONFIG_PATH}
|
|
121
133
|
`);
|
|
134
|
+
await writer.flush();
|
|
122
135
|
return;
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
if (command === '--version' || command === '-v') {
|
|
126
|
-
|
|
139
|
+
writer.scrollback(PACKAGE_JSON.version);
|
|
140
|
+
await writer.flush();
|
|
127
141
|
return;
|
|
128
142
|
}
|
|
129
143
|
|
|
@@ -159,20 +173,22 @@ Config: ${CONFIG_PATH}
|
|
|
159
173
|
try {
|
|
160
174
|
const entry = JSON.parse(line);
|
|
161
175
|
const icon = entry.approved ? `${ui.FG_GREEN}✓${ui.RST}` : `${ui.FG_RED}✗${ui.RST}`;
|
|
162
|
-
|
|
176
|
+
writer.scrollback(`${icon} ${line}`);
|
|
163
177
|
} catch {
|
|
164
|
-
|
|
178
|
+
writer.scrollback(line);
|
|
165
179
|
}
|
|
166
180
|
}
|
|
167
181
|
} catch {
|
|
168
|
-
|
|
182
|
+
writer.scrollback('No audit log found.');
|
|
169
183
|
}
|
|
184
|
+
await writer.flush();
|
|
170
185
|
} else if (command === 'config') {
|
|
171
186
|
const sub = rawArgs[1];
|
|
172
187
|
if (sub === 'set') {
|
|
173
188
|
const key = rawArgs[2];
|
|
174
189
|
const value = rawArgs[3];
|
|
175
190
|
if (!key || value === undefined) {
|
|
191
|
+
// audit: allowed — pre-UI argparse usage error to stderr; exits immediately.
|
|
176
192
|
process.stderr.write(`Usage: semalt-code config set <key> <value>\n`);
|
|
177
193
|
process.exit(1);
|
|
178
194
|
}
|
|
@@ -183,11 +199,12 @@ Config: ${CONFIG_PATH}
|
|
|
183
199
|
parsed = value;
|
|
184
200
|
}
|
|
185
201
|
configSet(key, parsed);
|
|
186
|
-
|
|
202
|
+
writer.scrollback(`Set ${key} = ${JSON.stringify(parsed)}`);
|
|
187
203
|
} else {
|
|
188
204
|
// default: "show" or bare "config"
|
|
189
|
-
|
|
205
|
+
writer.scrollback(configShow());
|
|
190
206
|
}
|
|
207
|
+
await writer.flush();
|
|
191
208
|
} else {
|
|
192
209
|
const { opts } = parseArgs(rawArgs);
|
|
193
210
|
await commands.cmdChat(opts);
|
|
@@ -195,6 +212,10 @@ Config: ${CONFIG_PATH}
|
|
|
195
212
|
}
|
|
196
213
|
|
|
197
214
|
main().catch((error) => {
|
|
215
|
+
// Tear down the TUI synchronously so the error message lands below the
|
|
216
|
+
// last scrollback line, not on top of a still-rendered live region.
|
|
217
|
+
try { ui.teardownTerminal(); } catch {}
|
|
218
|
+
// audit: allowed — fatal error message to stderr after writer teardown.
|
|
198
219
|
process.stderr.write(`\n ${ui.FG_RED}✗ Fatal: ${error.message}${ui.RST}\n\n`);
|
|
199
220
|
process.exit(1);
|
|
200
221
|
});
|