codeshark-cli 0.1.1
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/LICENSE +21 -0
- package/README.md +260 -0
- package/TERMS.md +72 -0
- package/dist/agent.js +77 -0
- package/dist/ansi.js +52 -0
- package/dist/banner.js +94 -0
- package/dist/config.js +126 -0
- package/dist/index.js +190 -0
- package/dist/keysPage.js +233 -0
- package/dist/loading.js +63 -0
- package/dist/models.js +54 -0
- package/dist/project.js +56 -0
- package/dist/provider/gateway.js +19 -0
- package/dist/provider/gemini.js +184 -0
- package/dist/provider/index.js +94 -0
- package/dist/provider/nvidia.js +19 -0
- package/dist/provider/ollama.js +22 -0
- package/dist/provider/openaiCompat.js +198 -0
- package/dist/provider/openrouter.js +21 -0
- package/dist/provider/types.js +35 -0
- package/dist/provider/unorouter.js +25 -0
- package/dist/repl.js +202 -0
- package/dist/setup.js +178 -0
- package/dist/system.js +21 -0
- package/dist/terms.js +18 -0
- package/dist/tools/files.js +288 -0
- package/dist/tools/index.js +16 -0
- package/dist/tools/registry.js +34 -0
- package/dist/tools/search.js +154 -0
- package/dist/tools/shell.js +105 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CodeShark contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# CodeShark ๐ฆ
|
|
2
|
+
|
|
3
|
+
An open-source **terminal coding agent** with a pixel-shark mascot โ five
|
|
4
|
+
frontier models (GPT-5.6 Sol, DeepSeek-V4 Flash, GLM 5.3 Flash Thinking,
|
|
5
|
+
Kimi-K3, Gemini 3.6 Flash) behind one OpenAI-compatible endpoint.
|
|
6
|
+
|
|
7
|
+
Run `codeshark banner --plain` to see the live mascot in your terminal: a dark
|
|
8
|
+
grey head with black eyes, white teeth, and a red mouth.
|
|
9
|
+
|
|
10
|
+
## How it works
|
|
11
|
+
|
|
12
|
+
Everything routes through **UnoRouter** (`https://api.unorouter.com/v1`), one
|
|
13
|
+
OpenAI-compatible endpoint. CodeShark ships with a zero-setup **community
|
|
14
|
+
gateway**, so you can start without configuring anything; bring your own
|
|
15
|
+
UnoRouter key whenever you want your own rate limits and private prompts.
|
|
16
|
+
|
|
17
|
+
The gateway strictly serves only UnoRouter's `:free` lane identifiers โ any
|
|
18
|
+
other identifier is refused, so there is no paid path through the gateway.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
CodeShark is intentionally **project-folder-only**. You must select the folder
|
|
23
|
+
that the agent is allowed to work in with `--folder` (or `--cwd`). It refuses to
|
|
24
|
+
start chat, setup, model switching, key management, or a prompt without a real
|
|
25
|
+
project folder.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# From a cloned checkout:
|
|
29
|
+
npm install
|
|
30
|
+
npm run build
|
|
31
|
+
npm install -g .
|
|
32
|
+
|
|
33
|
+
# Start CodeShark in the project folder:
|
|
34
|
+
codeshark --folder .
|
|
35
|
+
codeshark --folder . "explain this project"
|
|
36
|
+
|
|
37
|
+
# Or select another folder from anywhere:
|
|
38
|
+
codeshark --folder path/to/your-project
|
|
39
|
+
codeshark --cwd path/to/your-project "fix the tests"
|
|
40
|
+
|
|
41
|
+
# After the package is published:
|
|
42
|
+
npx codeshark-cli # run from any folder without a global install
|
|
43
|
+
npm install -g codeshark-cli
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Out of the box, CodeShark talks to the community gateway (which routes through
|
|
47
|
+
UnoRouter), so there is **nothing to configure**. If you installed from a
|
|
48
|
+
checkout and `codeshark` is not recognized yet, use `node dist/index.js
|
|
49
|
+
--folder .` or run `npm install -g .`. All file edits, searches, and commands
|
|
50
|
+
stay inside the selected project folder.
|
|
51
|
+
|
|
52
|
+
By using CodeShark you agree to the [Terms of Service](TERMS.md) โ the first
|
|
53
|
+
interactive start asks you to accept them once, and `codeshark terms` prints
|
|
54
|
+
them anytime.
|
|
55
|
+
|
|
56
|
+
### Setup: shared gateway or your own key?
|
|
57
|
+
|
|
58
|
+
On first launch the CLI asks how you want to connect โ and you can re-run it
|
|
59
|
+
anytime with `codeshark setup`:
|
|
60
|
+
|
|
61
|
+
- **My own API key (recommended)** โ typed into the terminal **hidden (never
|
|
62
|
+
echoed)**, stored only on your computer in a locked config file (`0600`
|
|
63
|
+
permissions), and never printed by CodeShark. Your own key means your own
|
|
64
|
+
rate limits and private prompts. One UnoRouter key unlocks all 5 models.
|
|
65
|
+
- **Shared gateway** โ no key on your computer at all; the gateway's keys live
|
|
66
|
+
as server-side secrets. Shared free lanes are rate-limited, so the gateway
|
|
67
|
+
**queues** bursts (you wait a moment instead of erroring) and fails over
|
|
68
|
+
between UnoRouter โ OpenRouter โ NVIDIA automatically.
|
|
69
|
+
- **Local Ollama** โ fully offline on your own machine.
|
|
70
|
+
|
|
71
|
+
Your local keys are protected further by the password-locked key vault
|
|
72
|
+
(`codeshark keys`) โ scrypt-hashed password, session + CSRF tokens, and keys
|
|
73
|
+
never appear in the page's HTML or the terminal.
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
codeshark --folder . interactive chat for this folder
|
|
79
|
+
codeshark --folder . "fix the tests" one-shot prompt for this folder
|
|
80
|
+
codeshark banner just the mascot (no folder needed)
|
|
81
|
+
codeshark --folder . setup providers / keys wizard
|
|
82
|
+
codeshark --folder . model list the catalog and active model
|
|
83
|
+
codeshark --folder . keys open the local key vault
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
REPL commands: `/help` `/model` `/keys` `/key-status` `/setup` `/clear` `/quit`
|
|
87
|
+
(Ctrl+C also quits). Read the terms anytime with `codeshark terms`. The `/keys` page listens only on `127.0.0.1`, requires a
|
|
88
|
+
local password, and keeps key values hidden in password-style fields; the
|
|
89
|
+
terminal status command only shows masked values.
|
|
90
|
+
|
|
91
|
+
## Tools the agent can use
|
|
92
|
+
|
|
93
|
+
- `read_file` / `write_file` / `edit_file` (strict: `oldString` must match **exactly once** or the edit is rejected)
|
|
94
|
+
- `list_directory` / `glob` (`**`, `*`, `?`, `{a,b}`)
|
|
95
|
+
- `code_search` (ripgrep when installed, dependency-free fallback otherwise)
|
|
96
|
+
- `run_command` (bash / cmd, 30s timeout, output capped) โ with a built-in
|
|
97
|
+
danger blocklist: `rm -rf`, `git push`, `sudo`, `curl | sh`, โฆ are refused
|
|
98
|
+
unless you set `CODESHARK_ALLOW_DANGEROUS=1`
|
|
99
|
+
- `finish` โ the model signals completion with a summary
|
|
100
|
+
|
|
101
|
+
## Providers & models
|
|
102
|
+
|
|
103
|
+
Everything runs through **UnoRouter** (`https://api.unorouter.com/v1`), one
|
|
104
|
+
OpenAI-compatible endpoint that routes to 45+ upstream providers โ all five
|
|
105
|
+
catalog models are served on its `:free` lanes. Switch anytime with
|
|
106
|
+
`/model <name>` in the REPL (or `codeshark model <name>`).
|
|
107
|
+
|
|
108
|
+
| Model | API identifier | Context | |
|
|
109
|
+
| --- | --- | --- | --- |
|
|
110
|
+
| Chat-GPT 5.6 Sol | `gpt-5.6-sol:free` | 400K | |
|
|
111
|
+
| DeepSeek-V4 Flash | `deepseek-v4-flash-0731:free` | 256K | |
|
|
112
|
+
| GLM 5.3 Flash Thinking | `glm-5.3-flash-thinking:free` | 1M | default |
|
|
113
|
+
| Kimi-K3 | `kimi-k3:free` | 256K | |
|
|
114
|
+
| Gemini 3.6 Flash | `gemini-3.6-flash:free` | 1M | |
|
|
115
|
+
|
|
116
|
+
\* All models run through the zero-setup gateway without any key โ nothing to
|
|
117
|
+
configure.
|
|
118
|
+
|
|
119
|
+
**Keys:**
|
|
120
|
+
- UnoRouter โ https://unorouter.com/en/tokens (one key, 200+ models โ the only key you really need)
|
|
121
|
+
- Google AI Studio โ https://aistudio.google.com/apikey (`AIzaโฆ`)
|
|
122
|
+
|
|
123
|
+
Run `codeshark setup` to paste a key and pick a default model โ it tests the key
|
|
124
|
+
live before saving.
|
|
125
|
+
|
|
126
|
+
**Rate limits:** shared lanes throttle (~20 req/min, ~200/day). If you hit
|
|
127
|
+
a 429, the agent tells you โ wait a moment or switch models with `/model`.
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
`~/.codeshark.json` (env vars override):
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"provider": "unorouter",
|
|
136
|
+
"model": "unorouter/glm-5.3-flash-thinking",
|
|
137
|
+
"unorouterApiKey": "ur-โฆ",
|
|
138
|
+
"openrouterApiKey": "sk-โฆ",
|
|
139
|
+
"nvidiaApiKey": "nvapi-โฆ",
|
|
140
|
+
"geminiApiKey": "AIzaโฆ",
|
|
141
|
+
"gatewayUrl": "https://your-gateway.workers.dev",
|
|
142
|
+
"ollamaBaseUrl": "http://127.0.0.1:11434/v1",
|
|
143
|
+
"ollamaModel": "qwen3-coder:30b",
|
|
144
|
+
"maxIterations": 25
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Env vars: `CODESHARK_MODEL`, `UNOROUTER_API_KEY`, `OPENROUTER_API_KEY`,
|
|
149
|
+
`GEMINI_API_KEY`, `CODESHARK_GATEWAY_URL`, `CODESHARK_GATEWAY_KEY`,
|
|
150
|
+
`CODESHARK_NO_COLOR`, `CODESHARK_NO_BANNER`, `CODESHARK_NO_LOADING`,
|
|
151
|
+
`CODESHARK_ALLOW_DANGEROUS`.
|
|
152
|
+
|
|
153
|
+
## Run your own community gateway
|
|
154
|
+
|
|
155
|
+
Anyone can fork the repo and deploy their own gateway โ the URL is configurable,
|
|
156
|
+
so your users hit *your* gateway:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
cd worker
|
|
160
|
+
npx wrangler secret put UNOROUTER_API_KEY # your UnoRouter key (primary), stays server-side
|
|
161
|
+
npx wrangler secret put OPENROUTER_API_KEY # optional: OpenRouter fallback key
|
|
162
|
+
npx wrangler secret put NVIDIA_API_KEY # optional: NVIDIA NIM fallback key (nvapi-โฆ)
|
|
163
|
+
npx wrangler deploy
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Then point CodeShark at it:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
codeshark setup # or edit ~/.codeshark.json: "gatewayUrl": "https://<you>.workers.dev"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The gateway serves only `:free` model identifiers โ it never routes anything
|
|
173
|
+
paid โ rate-limits per IP, adds CORS, and refuses any non-`:free` identifier.
|
|
174
|
+
When a provider rate-limits (429), the gateway **waits and retries**, then
|
|
175
|
+
hands off to the next configured provider (UnoRouter โ OpenRouter โ NVIDIA),
|
|
176
|
+
and per-IP bursts **queue** (wait for a slot) instead of failing. Your keys are
|
|
177
|
+
Worker secrets: never logged, never returned, never visible to users. Clients
|
|
178
|
+
also retry 429s with backoff, so shared lanes feel smooth.
|
|
179
|
+
|
|
180
|
+
## Architecture
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
โโโโโโโโโโโโโโ messages/tools โโโโโโโโโโโโโโโโโโโโ OpenAI-compatible โโโโโโโโโโโโโโโโ
|
|
184
|
+
โ terminal โ โโโโโโโโโโโโโโโโโโถ โ agent loop โ โโโโโโโโโโโโโโโโโโโโถ โ provider โ
|
|
185
|
+
โ (repl/cli) โ โโโโโโโโโโโโโโโโโโ โ (tools, guard) โ โโโโโโโโโโโโโโโโโโโโ โ chain โ
|
|
186
|
+
โโโโโโโโโโโโโโ streamed text โโโโโโโโโโโโโโโโโโโโ SSE stream โโโโโโโโฌโโโโโโโโ
|
|
187
|
+
โ
|
|
188
|
+
gateway (Cloudflare Worker, :free only) โโโโโโโโโโโค
|
|
189
|
+
unorouter (:free, your key) โโโโโโโโโโโโโโโโโโโโโโค
|
|
190
|
+
gemini โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
191
|
+
ollama (local) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- `src/provider/` โ canonical `ChatClient` interface + adapters (OpenAI-compatible
|
|
195
|
+
shared core, UnoRouter, OpenRouter, NVIDIA NIM, Gemini conversion, Ollama)
|
|
196
|
+
- `src/agent.ts` โ the loop: model โ tool calls โ results โ repeat (25-iteration guard)
|
|
197
|
+
- `src/tools/` โ file, search, and shell tools (zero dependencies)
|
|
198
|
+
- `src/banner.ts` โ the mascot, defined as a character grid
|
|
199
|
+
- `worker/` โ the Cloudflare Worker gateway
|
|
200
|
+
|
|
201
|
+
## Share it with other computers
|
|
202
|
+
|
|
203
|
+
Other people run your CodeShark the exact same way you do โ through npm.
|
|
204
|
+
Publish once, and anyone with Node.js 18+ can run it from any computer.
|
|
205
|
+
|
|
206
|
+
The package name is `codeshark-cli` (npm's anti-squatting rules reserve the
|
|
207
|
+
bare `codeshark` name, which is too similar to the existing `code-shark`
|
|
208
|
+
package). The command you type stays `codeshark`:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm login # once per computer (create an npm account first)
|
|
212
|
+
npm run typecheck && npm test
|
|
213
|
+
npm pack --dry-run # preview exactly what ships: dist/, README, LICENSE
|
|
214
|
+
npm publish --access public # publish version 0.1.0
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Bump the version for every release: `npm version patch` (or `minor`/`major`),
|
|
218
|
+
then `npm publish` again.
|
|
219
|
+
|
|
220
|
+
From that moment, on **any computer** with Node.js 18+:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npx codeshark-cli --folder . # run instantly โ no install needed
|
|
224
|
+
npm install -g codeshark-cli # or install it like a real CLI
|
|
225
|
+
codeshark --folder . # then use it anywhere
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The person on the other computer needs no API key and no account โ the model
|
|
229
|
+
provider stays server-side, so it works out of the box. The agent only works
|
|
230
|
+
inside the folder they open with `--folder`; it edits, searches, and runs
|
|
231
|
+
commands there and nowhere else.
|
|
232
|
+
|
|
233
|
+
Not ready to publish? `npm pack` produces a single `codeshark-<version>.tgz`
|
|
234
|
+
file โ send that one file and the receiver runs `npm install -g
|
|
235
|
+
./codeshark-0.1.0.tgz`.
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
npm install
|
|
241
|
+
npm run typecheck # tsc --noEmit
|
|
242
|
+
npm test # build + node:test (agent loop, tools, parsers, banner)
|
|
243
|
+
npm run worker:build # typecheck the gateway worker
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Roadmap
|
|
247
|
+
|
|
248
|
+
- [x] Mascot banner, REPL, one-shot mode, setup wizard
|
|
249
|
+
- [x] UnoRouter provider: 5 frontier models, one key
|
|
250
|
+
- [x] Agent loop with streaming + tool calling (UnoRouter/Gemini/Ollama/gateway)
|
|
251
|
+
- [x] File, search, and shell tools with safety blocklist
|
|
252
|
+
- [x] Cloudflare Worker gateway (`:free`-only, UnoRouter-routed)
|
|
253
|
+
- [ ] Session memory / project context
|
|
254
|
+
- [x] npm package metadata and `npx codeshark-cli`/global-install support (publish manually)
|
|
255
|
+
- [ ] Approval prompts for sensitive commands
|
|
256
|
+
- [ ] More providers (Groq, Cerebras, โฆ)
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT. ๐ฆ
|
package/TERMS.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# CodeShark Terms of Service
|
|
2
|
+
|
|
3
|
+
*Last updated: September 4, 2026*
|
|
4
|
+
|
|
5
|
+
By installing, downloading, or using CodeShark (the "Software"), you agree to
|
|
6
|
+
these Terms of Service. If you do not agree, do not use the Software.
|
|
7
|
+
|
|
8
|
+
## 1. What CodeShark is
|
|
9
|
+
|
|
10
|
+
CodeShark is an open-source terminal coding agent. It can read, create, and
|
|
11
|
+
edit files, run searches, and execute commands **inside the project folder you
|
|
12
|
+
explicitly open with `--folder`**. It is a tool you operate โ you are
|
|
13
|
+
responsible for choosing when and how it acts.
|
|
14
|
+
|
|
15
|
+
## 2. No warranty
|
|
16
|
+
|
|
17
|
+
The Software and the shared gateway service are provided **"AS IS" and "AS
|
|
18
|
+
AVAILABLE"**, without warranty of any kind, express or implied, including
|
|
19
|
+
merchantability, fitness for a particular purpose, and non-infringement. Model
|
|
20
|
+
responses may be incorrect, incomplete, or harmful; verify all output before
|
|
21
|
+
relying on it. The shared gateway is a free, best-effort service โ uptime,
|
|
22
|
+
speed, and model availability are not guaranteed.
|
|
23
|
+
|
|
24
|
+
## 3. Fair use of the shared gateway
|
|
25
|
+
|
|
26
|
+
When you use the shared gateway (the default "zero setup" path), requests are
|
|
27
|
+
routed through shared free-tier provider lanes. You agree to:
|
|
28
|
+
|
|
29
|
+
- **Not** resell, redistribute, or grant access to the gateway to third parties.
|
|
30
|
+
- **Not** scrape, stress-test, or otherwise abuse the gateway or its providers.
|
|
31
|
+
- **Not** use the Software for unlawful purposes, spam, or generating harmful
|
|
32
|
+
content.
|
|
33
|
+
- Accept that rate limits and queues apply to keep the service usable by
|
|
34
|
+
everyone. Requests may be delayed, queued, or refused to protect the shared
|
|
35
|
+
free tier.
|
|
36
|
+
|
|
37
|
+
## 4. Your content
|
|
38
|
+
|
|
39
|
+
You retain all rights to the prompts you enter and the files you edit. You are
|
|
40
|
+
solely responsible for them. Do not paste passwords, API keys, or other secrets
|
|
41
|
+
into prompts โ they may pass through third-party providers. Prompts and
|
|
42
|
+
generated content are not private; treat them accordingly.
|
|
43
|
+
|
|
44
|
+
## 5. Limitation of liability
|
|
45
|
+
|
|
46
|
+
To the maximum extent permitted by law, the authors and maintainers of
|
|
47
|
+
CodeShark are **not liable** for any damages arising from use of the Software,
|
|
48
|
+
including lost data, lost profits, corrupted files, or harm caused by generated
|
|
49
|
+
content or executed commands. You use the Software entirely at your own risk.
|
|
50
|
+
|
|
51
|
+
## 6. API keys
|
|
52
|
+
|
|
53
|
+
If you paste your own provider key, it is stored locally on your computer in a
|
|
54
|
+
locked configuration file and is never printed by CodeShark. Keys configured on
|
|
55
|
+
the shared gateway are stored as server-side secrets and are never exposed,
|
|
56
|
+
logged, or returned to clients. You are responsible for protecting your own
|
|
57
|
+
keys.
|
|
58
|
+
|
|
59
|
+
## 7. Changes
|
|
60
|
+
|
|
61
|
+
These Terms may be updated at any time. Continued use of the Software after
|
|
62
|
+
changes constitutes acceptance of the revised Terms.
|
|
63
|
+
|
|
64
|
+
## 8. Termination
|
|
65
|
+
|
|
66
|
+
We may refuse or terminate access to the shared gateway at any time, with or
|
|
67
|
+
without notice, for any reason โ including violation of these Terms. The
|
|
68
|
+
open-source Software itself remains available under its MIT license.
|
|
69
|
+
|
|
70
|
+
## 9. Contact
|
|
71
|
+
|
|
72
|
+
For questions about these Terms, open an issue in the CodeShark repository.
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { errorMessage } from "./provider/types.js";
|
|
2
|
+
import { defaultSystemPrompt } from "./system.js";
|
|
3
|
+
import { DEFAULT_MAX_ITERATIONS } from "./config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Run the agent loop for one user prompt:
|
|
6
|
+
* model โ tool calls โ execute โ feed results back โ โฆ until the model
|
|
7
|
+
* answers (or calls finish) without further tool calls.
|
|
8
|
+
*/
|
|
9
|
+
export async function runAgent(input, opts, events) {
|
|
10
|
+
const maxIterations = opts.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
11
|
+
const messages = opts.initialMessages ? [...opts.initialMessages] : [];
|
|
12
|
+
const systemPrompt = opts.systemPrompt ?? defaultSystemPrompt(opts.cwd);
|
|
13
|
+
if (!messages.some((message) => message.role === "system")) {
|
|
14
|
+
messages.unshift({ role: "system", content: systemPrompt });
|
|
15
|
+
}
|
|
16
|
+
messages.push({ role: "user", content: input });
|
|
17
|
+
const ctx = { cwd: opts.cwd, log: opts.debug };
|
|
18
|
+
let lastError = null;
|
|
19
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
20
|
+
let assistant = null;
|
|
21
|
+
let streamedText = "";
|
|
22
|
+
for (const client of opts.clients) {
|
|
23
|
+
let clientStreamedText = "";
|
|
24
|
+
const clientEvents = events
|
|
25
|
+
? {
|
|
26
|
+
onText: (delta) => {
|
|
27
|
+
clientStreamedText += delta;
|
|
28
|
+
events.onText?.(delta);
|
|
29
|
+
},
|
|
30
|
+
onToolCall: events.onToolCall,
|
|
31
|
+
onDebug: events.onDebug,
|
|
32
|
+
}
|
|
33
|
+
: undefined;
|
|
34
|
+
try {
|
|
35
|
+
assistant = await client.chat(messages, opts.registry.schemas(), clientEvents);
|
|
36
|
+
streamedText = clientStreamedText;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
41
|
+
opts.debug?.(`[provider] ${client.provider} failed: ${lastError.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!assistant) {
|
|
45
|
+
throw lastError ?? new Error("No provider available.");
|
|
46
|
+
}
|
|
47
|
+
const assistantMsg = assistant;
|
|
48
|
+
messages.push(assistantMsg);
|
|
49
|
+
const calls = assistantMsg.toolCalls ?? [];
|
|
50
|
+
if (!calls.length) {
|
|
51
|
+
return {
|
|
52
|
+
text: assistantMsg.content,
|
|
53
|
+
iterations: i + 1,
|
|
54
|
+
streamedText: streamedText || undefined,
|
|
55
|
+
history: messages,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
for (const call of calls) {
|
|
59
|
+
if (call.name === "finish") {
|
|
60
|
+
const summary = typeof call.args.summary === "string" && call.args.summary.trim() ? call.args.summary.trim() : "Task complete.";
|
|
61
|
+
return { text: summary, iterations: i + 1, history: messages };
|
|
62
|
+
}
|
|
63
|
+
opts.debug?.(`[tool] ${call.name}`);
|
|
64
|
+
events?.onToolCall?.(call);
|
|
65
|
+
const result = await opts.registry.execute(call.name, call.args, ctx);
|
|
66
|
+
messages.push({
|
|
67
|
+
role: "tool",
|
|
68
|
+
content: result.content,
|
|
69
|
+
toolCallId: call.id,
|
|
70
|
+
toolName: call.name,
|
|
71
|
+
isError: result.isError,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`Agent exceeded ${maxIterations} iterations without finishing. The model may be looping on tool calls โ try rephrasing, or set a higher maxIterations in ~/.codeshark.json.`);
|
|
76
|
+
}
|
|
77
|
+
export { errorMessage };
|
package/dist/ansi.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal ANSI escape-code helpers โ zero dependencies.
|
|
3
|
+
*/
|
|
4
|
+
export const ESC = "\u001b[";
|
|
5
|
+
export const RESET = `${ESC}0m`;
|
|
6
|
+
/** True when the current terminal is likely to support color. */
|
|
7
|
+
export function supportsColor() {
|
|
8
|
+
if (process.env.NO_COLOR !== undefined)
|
|
9
|
+
return false;
|
|
10
|
+
if (process.env.CODESHARK_NO_COLOR !== undefined)
|
|
11
|
+
return false;
|
|
12
|
+
if (process.env.TERM === "dumb")
|
|
13
|
+
return false;
|
|
14
|
+
if (process.platform === "win32" && !process.env.TERM)
|
|
15
|
+
return false;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
/** Style `text` with a foreground RGB color: hex("#d96b43", "x"). */
|
|
19
|
+
export function hex(hexColor, text) {
|
|
20
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hexColor.trim());
|
|
21
|
+
if (!m)
|
|
22
|
+
throw new Error(`Invalid hex color: ${hexColor}`);
|
|
23
|
+
const n = parseInt(m[1], 16);
|
|
24
|
+
const r = (n >> 16) & 0xff;
|
|
25
|
+
const g = (n >> 8) & 0xff;
|
|
26
|
+
const b = n & 0xff;
|
|
27
|
+
return `${ESC}38;2;${r};${g};${b}m${text}${RESET}`;
|
|
28
|
+
}
|
|
29
|
+
/** Style `text` with a background RGB color. */
|
|
30
|
+
export function hexBg(hexColor, text) {
|
|
31
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hexColor.trim());
|
|
32
|
+
if (!m)
|
|
33
|
+
throw new Error(`Invalid hex color: ${hexColor}`);
|
|
34
|
+
const n = parseInt(m[1], 16);
|
|
35
|
+
const r = (n >> 16) & 0xff;
|
|
36
|
+
const g = (n >> 8) & 0xff;
|
|
37
|
+
const b = n & 0xff;
|
|
38
|
+
return `${ESC}48;2;${r};${g};${b}m${text}${RESET}`;
|
|
39
|
+
}
|
|
40
|
+
export function bold(text) {
|
|
41
|
+
return `${ESC}1m${text}${RESET}`;
|
|
42
|
+
}
|
|
43
|
+
export function dim(text) {
|
|
44
|
+
return `${ESC}2m${text}${RESET}`;
|
|
45
|
+
}
|
|
46
|
+
export function underline(text) {
|
|
47
|
+
return `${ESC}4m${text}${RESET}`;
|
|
48
|
+
}
|
|
49
|
+
/** Remove ANSI escape sequences (useful for tests / piping). */
|
|
50
|
+
export function stripAnsi(text) {
|
|
51
|
+
return text.replace(/\u001b\[[0-9;]*m/g, "");
|
|
52
|
+
}
|
package/dist/banner.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { hex, bold, dim, stripAnsi } from "./ansi.js";
|
|
2
|
+
import { modelLabel, loadConfig, activeModelId } from "./config.js";
|
|
3
|
+
import { findModel } from "./models.js";
|
|
4
|
+
/**
|
|
5
|
+
* A front-facing pixel shark head, reproduced from the 16ร16 mascot artwork:
|
|
6
|
+
* a rounded dome, two eyes, and one open mouth with pointy zigzag teeth โ
|
|
7
|
+
* white triangular points separated by red gaps, over a white lower jaw.
|
|
8
|
+
* There is no badge background; the sprite floats directly on the terminal's
|
|
9
|
+
* own background.
|
|
10
|
+
*/
|
|
11
|
+
const SPRITE_WIDTH = 16;
|
|
12
|
+
function spriteRow(value) {
|
|
13
|
+
if (value.length !== SPRITE_WIDTH) {
|
|
14
|
+
throw new Error(`Mascot row is ${value.length} cells; expected ${SPRITE_WIDTH}`);
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Character grid:
|
|
20
|
+
* '.' transparent (terminal background)
|
|
21
|
+
* 'D' head
|
|
22
|
+
* 'E' eye
|
|
23
|
+
* 'W' teeth
|
|
24
|
+
* 'R' mouth interior
|
|
25
|
+
*/
|
|
26
|
+
export const SPRITE = [
|
|
27
|
+
spriteRow(".......D........"),
|
|
28
|
+
spriteRow("......DDDD......"),
|
|
29
|
+
spriteRow("....DDDDDDDD...."),
|
|
30
|
+
spriteRow("...DDDDDDDDDD..."),
|
|
31
|
+
spriteRow("...DDDDDDDDDD..."),
|
|
32
|
+
spriteRow("..DDDDDDDDDDDD.."),
|
|
33
|
+
spriteRow(".DDDDDDDDDDDDDD."),
|
|
34
|
+
spriteRow(".DDEDDWWWWDDEDD."),
|
|
35
|
+
spriteRow(".DDWDWWWWWWDWDD."),
|
|
36
|
+
spriteRow(".DWWDWRRRRWDWWD."),
|
|
37
|
+
spriteRow("DDWDWRRRRRRWDWDD"),
|
|
38
|
+
spriteRow("DDWDRRRRRRRRDWDD"),
|
|
39
|
+
spriteRow("DDWWWRWRWRWWWWDD"),
|
|
40
|
+
spriteRow("DDWWWRWWRWWRWWDD"),
|
|
41
|
+
spriteRow("DDWWWWWWWWWWWWDD"),
|
|
42
|
+
spriteRow("DDWWWWWWWWWWWWDD"),
|
|
43
|
+
];
|
|
44
|
+
const COLORS = {
|
|
45
|
+
D: { fg: "#4a5a68" },
|
|
46
|
+
E: { fg: "#0b1220" },
|
|
47
|
+
W: { fg: "#f8fafc" },
|
|
48
|
+
R: { fg: "#e5484d" },
|
|
49
|
+
};
|
|
50
|
+
function renderSpriteCell(ch, plain) {
|
|
51
|
+
if (ch === ".")
|
|
52
|
+
return " ";
|
|
53
|
+
if (plain) {
|
|
54
|
+
if (ch === "E")
|
|
55
|
+
return "โ ";
|
|
56
|
+
if (ch === "W")
|
|
57
|
+
return "โโ";
|
|
58
|
+
if (ch === "R")
|
|
59
|
+
return "โโ";
|
|
60
|
+
return "โโ";
|
|
61
|
+
}
|
|
62
|
+
return hex(COLORS[ch]?.fg ?? "#4a5a68", "โโ");
|
|
63
|
+
}
|
|
64
|
+
export function renderBanner(opts = {}) {
|
|
65
|
+
const plain = opts.plain ?? false;
|
|
66
|
+
const cfg = loadConfig();
|
|
67
|
+
const entry = findModel(activeModelId(cfg));
|
|
68
|
+
const baseLabel = modelLabel(cfg);
|
|
69
|
+
const modelLine = opts.modelLine ?? (entry ? `${baseLabel} ยท ${entry.context} context` : baseLabel);
|
|
70
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
71
|
+
const title = plain ? "CodeShark" : bold("CodeShark");
|
|
72
|
+
const sub = plain ? modelLine : hex("#8ba3ba", modelLine);
|
|
73
|
+
const dir = plain ? cwd : dim(cwd);
|
|
74
|
+
const lines = [];
|
|
75
|
+
const textLines = [title, sub, dir];
|
|
76
|
+
for (let i = 0; i < SPRITE.length; i++) {
|
|
77
|
+
let line = " ";
|
|
78
|
+
for (const ch of SPRITE[i])
|
|
79
|
+
line += renderSpriteCell(ch, plain);
|
|
80
|
+
const text = textLines[i];
|
|
81
|
+
if (text !== undefined)
|
|
82
|
+
line += " " + text;
|
|
83
|
+
lines.push(line);
|
|
84
|
+
}
|
|
85
|
+
if (opts.footer)
|
|
86
|
+
lines.push("", opts.footer);
|
|
87
|
+
return lines.join("\n") + "\n";
|
|
88
|
+
}
|
|
89
|
+
export function printBanner(opts = {}) {
|
|
90
|
+
process.stdout.write(renderBanner(opts));
|
|
91
|
+
}
|
|
92
|
+
export function bannerHasTitle(text) {
|
|
93
|
+
return stripAnsi(text).includes("CodeShark");
|
|
94
|
+
}
|