@semalt-ai/code 1.8.5 → 1.20.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.
Files changed (192) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/.github/workflows/ci.yml +69 -0
  3. package/ARCHITECTURE.md +6 -95
  4. package/CLAUDE.md +196 -316
  5. package/README.md +148 -4
  6. package/docs/ARCHITECTURE.md +1321 -0
  7. package/docs/CONFIG.md +340 -0
  8. package/docs/HISTORY.md +245 -0
  9. package/examples/embed.js +74 -0
  10. package/index.js +251 -10
  11. package/lib/agent.js +856 -120
  12. package/lib/api.js +239 -50
  13. package/lib/args.js +74 -2
  14. package/lib/audit.js +23 -1
  15. package/lib/background.js +584 -0
  16. package/lib/checkpoints.js +757 -0
  17. package/lib/commands/auth.js +94 -0
  18. package/lib/commands/chat-session.js +489 -0
  19. package/lib/commands/chat-slash.js +415 -0
  20. package/lib/commands/chat-turn.js +669 -0
  21. package/lib/commands/chat.js +407 -0
  22. package/lib/commands/custom.js +157 -0
  23. package/lib/commands/history-utils.js +66 -0
  24. package/lib/commands/index.js +268 -0
  25. package/lib/commands/mcp.js +113 -0
  26. package/lib/commands/oneshot.js +193 -0
  27. package/lib/commands/registry.js +269 -0
  28. package/lib/commands/tasks.js +89 -0
  29. package/lib/compact.js +87 -0
  30. package/lib/config.js +360 -11
  31. package/lib/constants.js +401 -3
  32. package/lib/deny.js +199 -0
  33. package/lib/doctor.js +160 -0
  34. package/lib/headless.js +202 -0
  35. package/lib/hooks.js +286 -0
  36. package/lib/images.js +270 -0
  37. package/lib/internals.js +49 -0
  38. package/lib/mcp/boundary.js +131 -0
  39. package/lib/mcp/client.js +270 -0
  40. package/lib/mcp/oauth.js +134 -0
  41. package/lib/memory.js +209 -0
  42. package/lib/metrics.js +37 -2
  43. package/lib/payload.js +54 -0
  44. package/lib/permission-rules.js +401 -0
  45. package/lib/permissions.js +123 -26
  46. package/lib/pricing.js +67 -0
  47. package/lib/proc.js +62 -0
  48. package/lib/prompts.js +99 -8
  49. package/lib/sandbox.js +568 -0
  50. package/lib/sdk.js +328 -0
  51. package/lib/secrets.js +211 -0
  52. package/lib/skills.js +223 -0
  53. package/lib/subagents.js +516 -0
  54. package/lib/tool_registry.js +2862 -0
  55. package/lib/tool_specs.js +263 -9
  56. package/lib/tools.js +352 -1039
  57. package/lib/ui/anim.js +86 -0
  58. package/lib/ui/ansi.js +17 -27
  59. package/lib/ui/chat-history.js +253 -71
  60. package/lib/ui/create-ui.js +67 -24
  61. package/lib/ui/diff.js +90 -25
  62. package/lib/ui/file-activity.js +236 -0
  63. package/lib/ui/format.js +195 -29
  64. package/lib/ui/input-field.js +21 -11
  65. package/lib/ui/md-stream.js +234 -0
  66. package/lib/ui/render-operation.js +113 -0
  67. package/lib/ui/select.js +1 -4
  68. package/lib/ui/status-bar.js +146 -36
  69. package/lib/ui/stream.js +20 -13
  70. package/lib/ui/theme.js +190 -44
  71. package/lib/ui/tool-operation.js +190 -0
  72. package/lib/ui/utils.js +9 -5
  73. package/lib/ui/web-activity.js +270 -0
  74. package/lib/ui/writer.js +159 -45
  75. package/lib/ui.js +1 -1
  76. package/lib/verify.js +229 -0
  77. package/lib/web-extract.js +213 -0
  78. package/lib/web-summarize.js +68 -0
  79. package/package.json +19 -4
  80. package/scripts/lint.js +57 -0
  81. package/test/agent-loop.test.js +389 -0
  82. package/test/anim-driver.test.js +153 -0
  83. package/test/ask-user-display.test.js +226 -0
  84. package/test/ask-user-gate.test.js +231 -0
  85. package/test/background.test.js +414 -0
  86. package/test/chat-history-nocolor.test.js +155 -0
  87. package/test/chat-relogin.test.js +207 -0
  88. package/test/chat.test.js +114 -0
  89. package/test/checkpoints-agent.test.js +181 -0
  90. package/test/checkpoints.test.js +650 -0
  91. package/test/command-registry.test.js +160 -0
  92. package/test/compact.test.js +116 -0
  93. package/test/completion-lazy.test.js +52 -0
  94. package/test/config-merge.test.js +324 -0
  95. package/test/config-quarantine.test.js +128 -0
  96. package/test/config-write-guard-allow-anywhere.test.js +56 -0
  97. package/test/config-write-guard-skip.test.js +46 -0
  98. package/test/config-write-guard.test.js +153 -0
  99. package/test/context-split.test.js +215 -0
  100. package/test/cost-doctor.test.js +142 -0
  101. package/test/custom-commands-chat.test.js +106 -0
  102. package/test/custom-commands.test.js +230 -0
  103. package/test/defer-detail-band.test.js +403 -0
  104. package/test/deny-windows.test.js +120 -0
  105. package/test/deny.test.js +83 -0
  106. package/test/detail-band-tab-flatten.test.js +242 -0
  107. package/test/download-allow-anywhere.test.js +66 -0
  108. package/test/download-confine.test.js +153 -0
  109. package/test/exec-diff.test.js +268 -0
  110. package/test/executors.test.js +599 -0
  111. package/test/extract-tool-calls.test.js +349 -0
  112. package/test/fetch-url-validation.test.js +219 -0
  113. package/test/file-activity.test.js +522 -0
  114. package/test/fixtures/tool-calls.js +57 -0
  115. package/test/fixtures/web-page.js +91 -0
  116. package/test/git-tools.test.js +384 -0
  117. package/test/grep-glob-serialize.test.js +242 -0
  118. package/test/grep-glob.test.js +268 -0
  119. package/test/grep-path-target.test.js +227 -0
  120. package/test/harness/README.md +57 -0
  121. package/test/harness/chat-harness.js +143 -0
  122. package/test/harness/memwarn-headless-child.js +65 -0
  123. package/test/harness/mock-llm.js +120 -0
  124. package/test/harness/mock-mcp-server.js +142 -0
  125. package/test/harness/sse-server.js +69 -0
  126. package/test/headless.test.js +348 -0
  127. package/test/history-utils.test.js +88 -0
  128. package/test/hooks-agent.test.js +238 -0
  129. package/test/hooks-verify-sandbox.test.js +232 -0
  130. package/test/hooks.test.js +216 -0
  131. package/test/http-get-user-agent.test.js +142 -0
  132. package/test/images-api.test.js +208 -0
  133. package/test/images.test.js +238 -0
  134. package/test/input-field-ctrl-o.test.js +37 -0
  135. package/test/live-height-physical.test.js +281 -0
  136. package/test/max-iterations.test.js +218 -0
  137. package/test/mcp-boundary.test.js +57 -0
  138. package/test/mcp-client.test.js +267 -0
  139. package/test/mcp-oauth.test.js +86 -0
  140. package/test/md-stream.test.js +183 -0
  141. package/test/memory-truncation-warning.test.js +222 -0
  142. package/test/memory.test.js +198 -0
  143. package/test/native-dispatch.test.js +409 -0
  144. package/test/native-live-narration.test.js +254 -0
  145. package/test/output-chokepoint.test.js +188 -0
  146. package/test/output-heredoc-leak.test.js +195 -0
  147. package/test/output-preview.test.js +245 -0
  148. package/test/path-guards.test.js +134 -0
  149. package/test/payload.test.js +99 -0
  150. package/test/permission-rules-agent.test.js +210 -0
  151. package/test/permission-rules.test.js +297 -0
  152. package/test/permissions.test.js +362 -0
  153. package/test/plan-mode.test.js +167 -0
  154. package/test/read-paginate.test.js +275 -0
  155. package/test/readonly-tools.test.js +177 -0
  156. package/test/render-operation.test.js +317 -0
  157. package/test/replay-descriptor-xml.test.js +216 -0
  158. package/test/replay-descriptor.test.js +189 -0
  159. package/test/replay-web-aggregate.test.js +291 -0
  160. package/test/replay-web-persist.test.js +241 -0
  161. package/test/result-cap.test.js +233 -0
  162. package/test/running-glyph-anim.test.js +111 -0
  163. package/test/sandbox-agent.test.js +147 -0
  164. package/test/sandbox-integration.test.js +216 -0
  165. package/test/sandbox.test.js +408 -0
  166. package/test/sdk.test.js +234 -0
  167. package/test/shell-output-cap.test.js +181 -0
  168. package/test/skills-chat.test.js +110 -0
  169. package/test/skills.test.js +295 -0
  170. package/test/smoke.test.js +68 -0
  171. package/test/status-bar-driver.test.js +93 -0
  172. package/test/status-bar-pause.test.js +164 -0
  173. package/test/status-bar-resync.test.js +188 -0
  174. package/test/stream-parser.test.js +171 -0
  175. package/test/subagents-agent.test.js +178 -0
  176. package/test/subagents.test.js +222 -0
  177. package/test/theme-palette.test.js +166 -0
  178. package/test/tool-registry.test.js +85 -0
  179. package/test/trim-budget.test.js +101 -0
  180. package/test/truncate-visible.test.js +78 -0
  181. package/test/verify-agent.test.js +317 -0
  182. package/test/verify.test.js +141 -0
  183. package/test/view-image.test.js +199 -0
  184. package/test/web-activity-ordering.test.js +203 -0
  185. package/test/web-activity.test.js +207 -0
  186. package/test/web-data-extraction-guidance.test.js +71 -0
  187. package/test/web-extract.test.js +185 -0
  188. package/test/web-fetch-agent.test.js +291 -0
  189. package/test/web-fetch-mode.test.js +193 -0
  190. package/test/web-search.test.js +380 -0
  191. package/lib/commands.js +0 -1438
  192. package/path +0 -1
@@ -17,7 +17,13 @@
17
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
18
  "Bash(echo \"exit=$?\")",
19
19
  "Bash(echo \"---grep done, exit=$?---\")",
20
- "Bash(grep *)"
20
+ "Bash(grep *)",
21
+ "Bash(npm test *)",
22
+ "Read(//srv/www/ai/**)",
23
+ "Read(//srv/www/ai/cli.semalt.ai/**)",
24
+ "Bash(npm run *)",
25
+ "Bash(— normalized\\\\|mcp)",
26
+ "Bash(awk '{print $5, $9}')"
21
27
  ]
22
28
  }
23
29
  }
@@ -0,0 +1,69 @@
1
+ name: CI
2
+
3
+ # Green-pipeline gate: lint + tests must pass on every push and PR across the
4
+ # supported OS/Node matrix before changes can land.
5
+ #
6
+ # Supply-chain guardrails (Task 3.2): the project has runtime dependencies
7
+ # (`@modelcontextprotocol/sdk`; plus `@mozilla/readability` + `linkedom` +
8
+ # `turndown` for the web-fetch pipeline, Task W.1). Two checks protect that
9
+ # surface:
10
+ # * `npm ci` installs strictly from the committed package-lock.json and fails
11
+ # if package.json and the lockfile disagree — i.e. lockfile integrity.
12
+ # * `npm audit --omit=dev --audit-level=high` fails the build on a HIGH or
13
+ # CRITICAL advisory in the runtime dependency tree (dev deps excluded; there
14
+ # are none today). Audit-findings policy lives in CLAUDE.md
15
+ # › "Dependency & Supply-Chain Policy".
16
+
17
+ on:
18
+ push:
19
+ branches: [main, master]
20
+ pull_request:
21
+
22
+ jobs:
23
+ lint-and-test:
24
+ name: lint + test (Node ${{ matrix.node }} / ${{ matrix.os }})
25
+ runs-on: ${{ matrix.os }}
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ os: [ubuntu-latest, macos-latest, windows-latest]
30
+ node: [18, 20]
31
+
32
+ steps:
33
+ - name: Checkout
34
+ uses: actions/checkout@v4
35
+
36
+ - name: Set up Node.js ${{ matrix.node }}
37
+ uses: actions/setup-node@v4
38
+ with:
39
+ node-version: ${{ matrix.node }}
40
+ cache: npm
41
+
42
+ # Lockfile integrity: install strictly from package-lock.json. Fails the
43
+ # build if package.json and the lockfile have drifted apart.
44
+ - name: Install dependencies (npm ci)
45
+ run: npm ci
46
+
47
+ # Supply-chain audit: fail on HIGH/CRITICAL advisories in the runtime
48
+ # (production) dependency tree. See CLAUDE.md for how findings are handled.
49
+ - name: Security audit (npm audit)
50
+ run: npm audit --omit=dev --audit-level=high
51
+
52
+ # Install ripgrep so the grep rg-vs-Node parity tests (Task 2.1) execute
53
+ # rather than skip. ripgrep is an optional accelerator for the `grep`
54
+ # tool, never a runtime dependency — the suite still passes without it.
55
+ - name: Install ripgrep (Linux)
56
+ if: runner.os == 'Linux'
57
+ run: sudo apt-get update && sudo apt-get install -y ripgrep
58
+ - name: Install ripgrep (macOS)
59
+ if: runner.os == 'macOS'
60
+ run: brew install ripgrep
61
+ - name: Install ripgrep (Windows)
62
+ if: runner.os == 'Windows'
63
+ run: choco install ripgrep -y
64
+
65
+ - name: Lint (node --check across all sources)
66
+ run: npm run lint
67
+
68
+ - name: Test (node --test)
69
+ run: npm test
package/ARCHITECTURE.md CHANGED
@@ -1,99 +1,10 @@
1
- # semalt-code — Architecture Reference
1
+ # semalt-code — Architecture
2
2
 
3
- ## lib/ File Responsibilities
3
+ The architecture documentation has moved. The current, maintained reference lives at:
4
4
 
5
- | File | Responsibility |
6
- |------|----------------|
7
- | `lib/agent.js` | Agent loop: iterates up to 10 times, streams LLM response, extracts tool calls, dispatches execution, accumulates results back into the message history |
8
- | `lib/api.js` | HTTP client for both OpenAI-compatible inference (`chatStream`, `chatSync`) and dashboard REST calls (auth, models, chat history); manually parses `text/event-stream` |
9
- | `lib/args.js` | CLI argument parser; maps flags (`-m`, `-f`, `--dry-run`, …) to an `opts` object and collects positional args |
10
- | `lib/commands.js` | All top-level command handlers: `cmdChat`, `cmdCode`, `cmdEdit`, `cmdShell`, `cmdLogin`, `cmdLogout`, `cmdWhoAmI`, `cmdModels`, `cmdInit` |
11
- | `lib/config.js` | Read/write `~/.semalt-ai/config.json`; `normalizeConfig` merges defaults, migrates legacy keys, validates types |
12
- | `lib/constants.js` | `DEFAULT_CONFIG`, `DEFAULT_API_TIMEOUT_MS`, `CONFIG_PATH`, `PACKAGE_JSON` |
13
- | `lib/context.js` | Loads file or directory trees into a prompt context string; caps directory walks at 50 files, single files at 10 000 chars |
14
- | `lib/permissions.js` | Per-session approval tracking; interactive yes/always/no prompt before each tool action; `toggleAll` for `/approve` |
15
- | `lib/prompts.js` | Returns the system prompt string that instructs the LLM which XML tool tags to use and how |
16
- | `lib/tools.js` | Implements `agentExecShell` and `agentExecFile` (16 file/env/network actions) plus `extractToolCalls` regex parser |
17
- | `lib/ui.js` | All terminal rendering: ANSI constants, `StreamRenderer` (markdown + tool-call display + inline diff), `readInteractiveInput`, `interactiveSelect`, `printBanner`, `printStatusBar` |
5
+ **[docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md)** per-subsystem internals (MCP, checkpoints, sandbox, web-fetch pipeline, SDK, subagents, hooks, git tools, …).
18
6
 
19
- ---
7
+ See also:
20
8
 
21
- ## Agent Loop Flow
22
-
23
- 1. `runAgentLoop(messages, model)` is called with the current message array (max 10 iterations).
24
- 2. `chatStream(messages, { model })` sends the array to the LLM and streams tokens through `StreamRenderer` to the terminal.
25
- 3. The full assistant text is appended to `messages` as `{ role: 'assistant', content }`.
26
- 4. `extractToolCalls(reply)` scans the text for XML tool tags and fenced shell blocks; returns an ordered list of `[action, ...args]` tuples.
27
- 5. If no tool calls are found, the loop ends.
28
- 6. For each tool call, `permissionManager.askPermission(type, description)` prompts the user (yes / yes-always / no).
29
- 7. Approved shell calls go to `agentExecShell`; all other calls go to `agentExecFile`.
30
- 8. Results (or denial messages) are concatenated and pushed to `messages` as a `user` turn: `"Tool execution results:\n\n…\n\nContinue with the task."`.
31
- 9. If any call was denied, a warning is printed and the loop continues with partial results.
32
- 10. Go to step 2.
33
-
34
- ---
35
-
36
- ## Tool Tags
37
-
38
- All tags are parsed by `extractToolCalls` in `lib/tools.js` and displayed by `StreamRenderer` in `lib/ui.js`.
39
-
40
- | Tag | Syntax | Action dispatched |
41
- |-----|--------|-------------------|
42
- | `exec` | `<exec>command</exec>` | `shell` |
43
- | `shell` | `<shell>command</shell>` | `shell` (alias) |
44
- | `run_command` | `<run_command>command</run_command>` | `shell` (alias) |
45
- | `run` | `<run>command</run>` | `shell` (alias) |
46
- | Fenced shell block | ` ```shell\ncommand\n``` ` | `shell` (one call per non-comment line) |
47
- | `read_file` (content) | `<read_file>/path</read_file>` | `read` |
48
- | `read_file` (attribute) | `<read_file path="/path"/>` | `read` |
49
- | `write_file` | `<write_file path="/path">content</write_file>` | `write` |
50
- | `append_file` | `<append_file path="/path">content</append_file>` | `append` |
51
- | `list_dir` | `<list_dir>/path</list_dir>` | `list_dir` |
52
- | `search_files` | `<search_files>pattern</search_files>` | `search_files` |
53
- | `delete_file` | `<delete_file>/path</delete_file>` | `delete_file` |
54
- | `make_dir` | `<make_dir>/path</make_dir>` | `make_dir` |
55
- | `remove_dir` | `<remove_dir>/path</remove_dir>` | `remove_dir` |
56
- | `get_env` | `<get_env>VAR_NAME</get_env>` | `get_env` |
57
- | `set_env` | `<set_env name="VAR" value="val"/>` | `set_env` |
58
- | `move_file` | `<move_file src="/src" dst="/dst"/>` | `move_file` |
59
- | `copy_file` | `<copy_file src="/src" dst="/dst"/>` | `copy_file` |
60
- | `edit_file` | `<edit_file path="/path" line="N">new line content</edit_file>` | `edit_file` |
61
- | `search_in_file` | `<search_in_file path="/path">regex</search_in_file>` | `search_in_file` |
62
- | `replace_in_file` | `<replace_in_file path="/path" search="old" replace="new"></replace_in_file>` | `replace_in_file` |
63
- | `download` | `<download>https://url</download>` | `download` |
64
- | `upload` | `<upload path="/path">base64content</upload>` | `upload` |
65
-
66
- ---
67
-
68
- ## DEFAULT_CONFIG Keys
69
-
70
- Defined in `lib/constants.js` and merged/validated by `lib/config.js`.
71
-
72
- | Key | Default | Description |
73
- |-----|---------|-------------|
74
- | `api_base` | `"http://127.0.0.1:8800"` | OpenAI-compatible inference base URL (normalized to include `/v1`) |
75
- | `api_key` | `"any"` | API key sent as `Authorization: Bearer` to the inference endpoint |
76
- | `dashboard_url` | `"https://cli.semalt.ai"` | Base URL for the web dashboard (auth, models, chat history) |
77
- | `auth_token` | `""` | Bearer token written by `semalt login`, cleared by `logout` |
78
- | `default_model` | `"default"` | Model identifier sent in chat completions payloads |
79
- | `dashboard_model_id` | `null` | Integer PK of the active model in `available_models`; required for chat history sync |
80
- | `temperature` | `0.7` | Sampling temperature passed to the LLM |
81
- | `request_timeout_ms` | `900000` | HTTP request timeout for inference calls (ms) |
82
- | `stream` | `true` | Whether to use streaming (`text/event-stream`) for inference |
83
- | `models` | `[]` | Local model profile overrides (each: `api_base`, `api_key`, `model`) |
84
- | `theme` | `"dark"` | Terminal color theme |
85
- | `max_file_size_kb` | `512` | Maximum file size the agent will read (KB) |
86
- | `command_timeout_ms` | `30000` | Timeout for shell command execution (ms) |
87
- | `max_output_lines` | `50` | Maximum lines of tool output shown before truncation |
88
- | `show_token_count` | `true` | Display token usage in the status line after each turn |
89
- | `show_cost` | `false` | Display estimated cost alongside token count |
90
-
91
- ---
92
-
93
- ## Planned Additions
94
-
95
- | File | Intended Responsibility |
96
- |------|------------------------|
97
- | `lib/audit.js` | Persistent log of all tool calls executed per session (command, args, exit code, timestamp); used for replay and compliance review |
98
- | `lib/storage.js` | Local SQLite or JSON-lines store for offline chat history, message deduplication, and cache of dashboard responses |
99
- | `lib/metrics.js` | Collects per-session telemetry (token counts, latency, tool-call frequency) and exposes summary output for `/compact` and future analytics export |
9
+ - [docs/CONFIG.md](./docs/CONFIG.md) config keys, CLI flags/commands, slash commands, tool tags.
10
+ - [docs/HISTORY.md](./docs/HISTORY.md) — design rationale, dependency policy, and roadmap.