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/dist/repl.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { bold, dim, hex } from "./ansi.js";
|
|
4
|
+
import { runAgent } from "./agent.js";
|
|
5
|
+
import { ProviderError, errorMessage } from "./provider/types.js";
|
|
6
|
+
import { runSetup } from "./setup.js";
|
|
7
|
+
import { loadConfig, modelLabel, saveConfig } from "./config.js";
|
|
8
|
+
import { DEFAULT_MODEL_ID, MODELS, findModel } from "./models.js";
|
|
9
|
+
import { launchKeysPage } from "./keysPage.js";
|
|
10
|
+
const PROMPT = "🦈 ";
|
|
11
|
+
function replClosed(rl) {
|
|
12
|
+
return Boolean(rl.closed);
|
|
13
|
+
}
|
|
14
|
+
function briefArgs(args) {
|
|
15
|
+
const s = JSON.stringify(args);
|
|
16
|
+
return s.length > 90 ? s.slice(0, 90) + "…" : s;
|
|
17
|
+
}
|
|
18
|
+
function printHelp() {
|
|
19
|
+
console.log([
|
|
20
|
+
"",
|
|
21
|
+
bold(" CodeShark commands"),
|
|
22
|
+
dim(" /help show this help"),
|
|
23
|
+
dim(" /model show the active model and the full catalog"),
|
|
24
|
+
dim(" /model <name> switch model, e.g. /model glm or /model kimi-k3"),
|
|
25
|
+
dim(" /keys open the password-protected local API key page"),
|
|
26
|
+
dim(" /key-status show masked key status in the terminal"),
|
|
27
|
+
dim(" /setup guided setup wizard (providers / keys)"),
|
|
28
|
+
dim(" /clear clear the screen"),
|
|
29
|
+
dim(" /quit exit (Ctrl+C also works)"),
|
|
30
|
+
"",
|
|
31
|
+
].join("\n"));
|
|
32
|
+
}
|
|
33
|
+
export function printModelInfo() {
|
|
34
|
+
const cfg = loadConfig();
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log(` Active: ${bold(hex("#4ade80", modelLabel(cfg)))}`);
|
|
37
|
+
console.log("");
|
|
38
|
+
console.log(bold(" Model catalog"));
|
|
39
|
+
for (const m of MODELS) {
|
|
40
|
+
const active = m.id === (findModel(cfg.model ?? "")?.id ?? DEFAULT_MODEL_ID);
|
|
41
|
+
const marker = active ? hex("#4ade80", "●") : dim("○");
|
|
42
|
+
console.log(` ${marker} ${m.label.padEnd(28)} ${dim(m.context.padEnd(5))} ${m.notes}`);
|
|
43
|
+
}
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log(dim(" Switch with: /model <name> e.g. /model glm, /model kimi, /model gpt"));
|
|
46
|
+
console.log("");
|
|
47
|
+
}
|
|
48
|
+
export function switchModel(query) {
|
|
49
|
+
const q = query.trim();
|
|
50
|
+
if (!q) {
|
|
51
|
+
printModelInfo();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const cfg = loadConfig();
|
|
55
|
+
const entry = findModel(q) ??
|
|
56
|
+
MODELS.find((m) => m.id.toLowerCase().includes(q.toLowerCase()) || m.label.toLowerCase().includes(q.toLowerCase()));
|
|
57
|
+
if (!entry) {
|
|
58
|
+
console.log(hex("#f87171", ` ✗ No model matches "${q}".`));
|
|
59
|
+
console.log(dim(" Available: " + MODELS.map((m) => m.label).join(", ")));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
cfg.model = entry.id;
|
|
63
|
+
saveConfig(cfg);
|
|
64
|
+
console.log(` ${hex("#4ade80", "✓")} Switched to ${bold(entry.label)} ${dim(`(${entry.context} context)`)}`);
|
|
65
|
+
console.log(dim(" Applies immediately — just start chatting."));
|
|
66
|
+
console.log("");
|
|
67
|
+
}
|
|
68
|
+
function printKeys() {
|
|
69
|
+
const cfg = loadConfig();
|
|
70
|
+
console.log("");
|
|
71
|
+
console.log(bold(" API keys"));
|
|
72
|
+
const ur = Boolean(cfg.unorouterApiKey ?? process.env.UNOROUTER_API_KEY);
|
|
73
|
+
const or = Boolean(cfg.openrouterApiKey ?? process.env.OPENROUTER_API_KEY);
|
|
74
|
+
const nv = Boolean(cfg.nvidiaApiKey ?? process.env.NVIDIA_API_KEY);
|
|
75
|
+
const gm = Boolean(cfg.geminiApiKey ?? process.env.GEMINI_API_KEY);
|
|
76
|
+
console.log(` ${ur ? hex("#4ade80", "✓") : dim("○")} UnoRouter ${ur ? dim("(configured)") : dim("(not set)")} → https://unorouter.com/en/tokens ${dim("key: shown once")}`);
|
|
77
|
+
console.log(` ${or ? hex("#4ade80", "✓") : dim("○")} OpenRouter ${or ? dim("(configured)") : dim("(not set)")} → https://openrouter.ai/keys ${dim("key: sk-or-v1-…")}`);
|
|
78
|
+
console.log(` ${nv ? hex("#4ade80", "✓") : dim("○")} NVIDIA NIM ${nv ? dim("(configured)") : dim("(not set)")} → https://build.nvidia.com ${dim("key: nvapi-…")}`);
|
|
79
|
+
console.log(` ${gm ? hex("#4ade80", "✓") : dim("○")} Google AI Studio ${gm ? dim("(configured)") : dim("(not set)")} → https://aistudio.google.com/apikey ${dim("key: AIza…")}`);
|
|
80
|
+
console.log("");
|
|
81
|
+
console.log(dim(" Add one: run /setup, or paste it into ~/.codeshark.json like:"));
|
|
82
|
+
console.log(dim(' { "unorouterApiKey": "ur-…", "openrouterApiKey": "sk-or-v1-…" }'));
|
|
83
|
+
console.log(dim(" Or set env vars: UNOROUTER_API_KEY, OPENROUTER_API_KEY, NVIDIA_API_KEY, GEMINI_API_KEY"));
|
|
84
|
+
console.log("");
|
|
85
|
+
}
|
|
86
|
+
export async function startRepl(opts) {
|
|
87
|
+
const rl = createInterface({ input, output });
|
|
88
|
+
rl.setPrompt(PROMPT);
|
|
89
|
+
let history = [];
|
|
90
|
+
console.log(dim(" Type a message and press Enter. /help for commands · Ctrl+C to quit."));
|
|
91
|
+
rl.prompt();
|
|
92
|
+
rl.on("SIGINT", () => {
|
|
93
|
+
console.log("");
|
|
94
|
+
console.log(dim("Bye! 🦈"));
|
|
95
|
+
process.exit(0);
|
|
96
|
+
});
|
|
97
|
+
rl.on("line", async (raw) => {
|
|
98
|
+
const line = raw.trim();
|
|
99
|
+
if (!line) {
|
|
100
|
+
if (!replClosed(rl))
|
|
101
|
+
rl.prompt();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Commands
|
|
105
|
+
if (line.startsWith("/")) {
|
|
106
|
+
const [cmd, ...rest] = line.slice(1).split(/\s+/);
|
|
107
|
+
switch (cmd) {
|
|
108
|
+
case "help":
|
|
109
|
+
case "h":
|
|
110
|
+
printHelp();
|
|
111
|
+
break;
|
|
112
|
+
case "model":
|
|
113
|
+
case "m":
|
|
114
|
+
if (rest.length)
|
|
115
|
+
switchModel(rest.join(" "));
|
|
116
|
+
else
|
|
117
|
+
printModelInfo();
|
|
118
|
+
break;
|
|
119
|
+
case "keys":
|
|
120
|
+
case "key":
|
|
121
|
+
console.log(dim(` Opening local key vault… ${await launchKeysPage()}`));
|
|
122
|
+
console.log(dim(" The browser page asks for a password before showing keys."));
|
|
123
|
+
break;
|
|
124
|
+
case "key-status":
|
|
125
|
+
case "keystatus":
|
|
126
|
+
printKeys();
|
|
127
|
+
break;
|
|
128
|
+
case "clear":
|
|
129
|
+
history = [];
|
|
130
|
+
process.stdout.write("\u001b[2J\u001b[H");
|
|
131
|
+
break;
|
|
132
|
+
case "setup":
|
|
133
|
+
rl.pause();
|
|
134
|
+
await runSetup();
|
|
135
|
+
rl.resume();
|
|
136
|
+
console.log(dim(" Provider chain reloaded."));
|
|
137
|
+
break;
|
|
138
|
+
case "quit":
|
|
139
|
+
case "exit":
|
|
140
|
+
case "q":
|
|
141
|
+
console.log(dim("Bye! 🦈"));
|
|
142
|
+
process.exit(0);
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
console.log(dim(` Unknown command "${cmd}". Try /help.`));
|
|
146
|
+
}
|
|
147
|
+
if (!replClosed(rl))
|
|
148
|
+
rl.prompt();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Agent run
|
|
152
|
+
rl.pause();
|
|
153
|
+
console.log("");
|
|
154
|
+
const events = {
|
|
155
|
+
onText: (delta) => process.stdout.write(delta),
|
|
156
|
+
onToolCall: (call) => {
|
|
157
|
+
console.log(dim(` ⚙ ${call.name}(${briefArgs(call.args)})`));
|
|
158
|
+
},
|
|
159
|
+
onDebug: (msg) => console.log(dim(msg)),
|
|
160
|
+
};
|
|
161
|
+
try {
|
|
162
|
+
const result = await runAgent(line, {
|
|
163
|
+
clients: opts.getClients(),
|
|
164
|
+
registry: opts.registry,
|
|
165
|
+
cwd: opts.cwd,
|
|
166
|
+
debug: opts.debug,
|
|
167
|
+
initialMessages: history,
|
|
168
|
+
}, events);
|
|
169
|
+
history = result.history;
|
|
170
|
+
if (result.streamedText) {
|
|
171
|
+
if (!result.streamedText.endsWith("\n"))
|
|
172
|
+
process.stdout.write("\n");
|
|
173
|
+
}
|
|
174
|
+
else if (result.text) {
|
|
175
|
+
process.stdout.write(result.text.endsWith("\n") ? result.text : result.text + "\n");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
console.log("");
|
|
180
|
+
if (e instanceof ProviderError) {
|
|
181
|
+
console.log(hex("#f87171", ` ✗ ${e.message}`));
|
|
182
|
+
if (e.kind === "network") {
|
|
183
|
+
console.log(dim(" The provider is unreachable. Run /keys to configure your own key."));
|
|
184
|
+
}
|
|
185
|
+
else if (e.kind === "auth" || e.kind === "rate_limit") {
|
|
186
|
+
console.log(dim(" Run /setup to fix this, or /model to pick a different model."));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(hex("#f87171", ` ✗ ${errorMessage(e)}`));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
console.log("");
|
|
194
|
+
if (!replClosed(rl)) {
|
|
195
|
+
rl.resume();
|
|
196
|
+
rl.prompt();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
await new Promise(() => {
|
|
200
|
+
// Keep the interface alive; SIGINT handles exit.
|
|
201
|
+
});
|
|
202
|
+
}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { exec } from "node:child_process";
|
|
4
|
+
import { bold, dim, hex } from "./ansi.js";
|
|
5
|
+
import { configPath, hasApiKey, loadConfig, saveConfig } from "./config.js";
|
|
6
|
+
import { createUnoRouterClient } from "./provider/unorouter.js";
|
|
7
|
+
import { createGeminiClient } from "./provider/gemini.js";
|
|
8
|
+
import { ollamaAvailable } from "./provider/ollama.js";
|
|
9
|
+
import { MODELS } from "./models.js";
|
|
10
|
+
import { errorMessage } from "./provider/types.js";
|
|
11
|
+
function openBrowser(url) {
|
|
12
|
+
try {
|
|
13
|
+
const cmd = process.platform === "win32"
|
|
14
|
+
? `cmd /c start "" "${url}"`
|
|
15
|
+
: process.platform === "darwin"
|
|
16
|
+
? `open "${url}"`
|
|
17
|
+
: `xdg-open "${url}"`;
|
|
18
|
+
exec(cmd, () => { });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// ignore — we print the URL anyway
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Ask for a secret WITHOUT echoing it to the terminal, so pasting an API
|
|
26
|
+
* key never leaves it visible on screen (or in terminal scrollback).
|
|
27
|
+
*/
|
|
28
|
+
function secretQuestion(rl) {
|
|
29
|
+
return async (prompt) => {
|
|
30
|
+
const anyRl = rl;
|
|
31
|
+
const original = anyRl._writeToOutput;
|
|
32
|
+
anyRl._writeToOutput = () => { }; // swallow the echo of typed characters
|
|
33
|
+
process.stdout.write(prompt);
|
|
34
|
+
const answer = await rl.question("");
|
|
35
|
+
anyRl._writeToOutput = original;
|
|
36
|
+
process.stdout.write("\n");
|
|
37
|
+
return answer.trim();
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function testClient(label, client) {
|
|
41
|
+
process.stdout.write(` Testing ${label}… `);
|
|
42
|
+
try {
|
|
43
|
+
await client.chat([{ role: "user", content: "Reply with exactly: OK" }], []);
|
|
44
|
+
console.log(hex("#4ade80", "✓ works"));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.log(hex("#f87171", `✗ ${errorMessage(e)}`));
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** After keys are saved, offer a numbered model picker and save the choice. */
|
|
53
|
+
async function pickModel(rl, cfg) {
|
|
54
|
+
const available = MODELS.filter((m) => hasApiKey(cfg, m.provider));
|
|
55
|
+
if (!available.length)
|
|
56
|
+
return;
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log(bold(" Pick your default model:"));
|
|
59
|
+
available.forEach((m, i) => {
|
|
60
|
+
console.log(` [${i + 1}] ${m.label.padEnd(30)} ${dim(m.context.padEnd(5))}`);
|
|
61
|
+
console.log(` ${dim(m.notes)}`);
|
|
62
|
+
});
|
|
63
|
+
console.log("");
|
|
64
|
+
const answer = await rl.question(` Choose [1-${available.length}] (default 1): `);
|
|
65
|
+
const idx = (parseInt(answer.trim(), 10) || 1) - 1;
|
|
66
|
+
const chosen = available[Math.max(0, Math.min(idx, available.length - 1))] ?? available[0];
|
|
67
|
+
if (!chosen)
|
|
68
|
+
return;
|
|
69
|
+
cfg.model = chosen.id;
|
|
70
|
+
console.log(` ${hex("#4ade80", "✓")} Default model: ${bold(chosen.label)}`);
|
|
71
|
+
}
|
|
72
|
+
function saveDone(cfg) {
|
|
73
|
+
saveConfig(cfg);
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(hex("#4ade80", ` ✓ Saved to ${configPath()}`));
|
|
76
|
+
console.log("");
|
|
77
|
+
}
|
|
78
|
+
/** The `codeshark setup` command: guided provider / key configuration. */
|
|
79
|
+
export async function runSetup() {
|
|
80
|
+
const rl = createInterface({ input, output });
|
|
81
|
+
try {
|
|
82
|
+
await runSetupFlow(loadConfig(), rl, { title: "🦈 CodeShark setup" });
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
rl.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The provider/key configuration flow, shared by `codeshark setup` and the
|
|
90
|
+
* first-run prompt at CLI startup. Returns true when a choice was saved.
|
|
91
|
+
*/
|
|
92
|
+
export async function runSetupFlow(cfg, rl, opts = {}) {
|
|
93
|
+
const askSecret = secretQuestion(rl);
|
|
94
|
+
console.log("");
|
|
95
|
+
console.log(bold(hex("#d96b43", opts.title ?? "🦈 CodeShark setup")));
|
|
96
|
+
console.log("");
|
|
97
|
+
console.log(bold(" How do you want to talk to the models?"));
|
|
98
|
+
console.log(dim(" [1] Shared CodeShark gateway — zero setup. No key on this computer;"));
|
|
99
|
+
console.log(dim(" the gateway's keys stay private on the server."));
|
|
100
|
+
console.log(dim(" [2] My own API key (recommended) — your own rate limits and privacy;"));
|
|
101
|
+
console.log(dim(" typed hidden, stored only on this computer, never shown on screen."));
|
|
102
|
+
console.log(dim(" [3] Local Ollama — fully offline, runs on your machine."));
|
|
103
|
+
console.log(dim(" [4] Cancel — change nothing"));
|
|
104
|
+
console.log("");
|
|
105
|
+
const choice = (await rl.question(" Choose [1-4]: ")).trim();
|
|
106
|
+
const is = (v, ...words) => choice === v || words.some((w) => choice.toLowerCase() === w);
|
|
107
|
+
if (is("4", "cancel", "c", "skip", "s")) {
|
|
108
|
+
console.log(dim(" Skipped — no changes saved."));
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (is("3", "ollama", "o")) {
|
|
112
|
+
cfg.provider = "ollama";
|
|
113
|
+
if (await ollamaAvailable(cfg)) {
|
|
114
|
+
console.log(hex("#4ade80", " ✓ Ollama reachable"));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.log(hex("#f87171", " ✗ Ollama not reachable — install from https://ollama.com and run `ollama serve`."));
|
|
118
|
+
}
|
|
119
|
+
saveDone(cfg);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (is("1", "gateway", "g")) {
|
|
123
|
+
cfg.provider = "gateway";
|
|
124
|
+
saveDone(cfg);
|
|
125
|
+
console.log(dim(" Zero setup — you're ready. Switch anytime with /setup."));
|
|
126
|
+
console.log("");
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
// Choice 2 — the user's own key (typed into the terminal, never echoed).
|
|
130
|
+
console.log(bold(" Step 1 — UnoRouter key (unlocks all 5 models)"));
|
|
131
|
+
console.log(dim(" 1. Open https://unorouter.com/en/tokens (sign up with Discord/GitHub, no card)"));
|
|
132
|
+
console.log(dim(" 2. Create an API key on the Tokens page — it is shown exactly once — and copy it"));
|
|
133
|
+
console.log(dim(" Your key is typed hidden: it will not appear on screen."));
|
|
134
|
+
openBrowser("https://unorouter.com/en/tokens");
|
|
135
|
+
const urKey = await askSecret(" Paste your UnoRouter key (Enter to skip): ");
|
|
136
|
+
if (urKey) {
|
|
137
|
+
cfg.unorouterApiKey = urKey;
|
|
138
|
+
cfg.provider = "unorouter";
|
|
139
|
+
await testClient("UnoRouter (GLM 5.3 Flash Thinking)", createUnoRouterClient(cfg, urKey));
|
|
140
|
+
await pickModel(rl, cfg);
|
|
141
|
+
saveDone(cfg);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
console.log(bold(" Step 2 — Google Gemini key (optional)"));
|
|
145
|
+
console.log(dim(" Get a key at https://aistudio.google.com/apikey (AIza…)."));
|
|
146
|
+
const gk = await askSecret(" Paste your Gemini key (Enter to skip): ");
|
|
147
|
+
if (gk) {
|
|
148
|
+
cfg.geminiApiKey = gk;
|
|
149
|
+
cfg.provider = "gemini";
|
|
150
|
+
await testClient("Gemini", createGeminiClient(cfg, gk));
|
|
151
|
+
saveDone(cfg);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
// No key pasted: loop back to the provider choice.
|
|
155
|
+
console.log(dim(" No keys pasted."));
|
|
156
|
+
console.log("");
|
|
157
|
+
console.log(dim(" [1] Use shared CodeShark gateway (zero setup) [2] Use local Ollama [3] Cancel"));
|
|
158
|
+
const fallback = await rl.question(" Choose: ");
|
|
159
|
+
if (fallback.trim() === "2") {
|
|
160
|
+
cfg.provider = "ollama";
|
|
161
|
+
if (await ollamaAvailable(cfg)) {
|
|
162
|
+
console.log(hex("#4ade80", " ✓ Ollama reachable"));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.log(hex("#f87171", " ✗ Ollama not reachable — install from https://ollama.com and run `ollama serve`."));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (fallback.trim() === "3") {
|
|
169
|
+
console.log(dim(" Cancelled — nothing changed."));
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
cfg.provider = "gateway";
|
|
174
|
+
console.log(dim(" Using the shared gateway — zero setup. You can add your own key later with /setup."));
|
|
175
|
+
}
|
|
176
|
+
saveDone(cfg);
|
|
177
|
+
return true;
|
|
178
|
+
}
|
package/dist/system.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function defaultSystemPrompt(cwd) {
|
|
2
|
+
return `You are CodeShark, a friendly, capable coding agent running inside the user's terminal. Your mascot is a pixel-art shark.
|
|
3
|
+
|
|
4
|
+
Working directory: ${cwd}
|
|
5
|
+
|
|
6
|
+
Rules:
|
|
7
|
+
- Use your tools to inspect the project before making changes. Prefer reading the relevant files over guessing.
|
|
8
|
+
- For existing files, make surgical edits with edit_file (oldString must match exactly once). Use write_file only to create new files or fully replace tiny ones.
|
|
9
|
+
- Use run_command for anything a shell can do: tests, builds, git status, package installs. Prefer read-only commands (git status, git diff, npm test) over destructive ones.
|
|
10
|
+
- After editing code, verify it: run the typecheck/tests if the project has them, and report the result honestly.
|
|
11
|
+
- Be concise. Answer in the user's language unless asked otherwise.
|
|
12
|
+
- Work step by step. If a step fails, diagnose with tools and retry with a different approach.
|
|
13
|
+
- Never claim you ran a command or edited a file unless you actually did through your tools.
|
|
14
|
+
- When the task is complete, call the "finish" tool with a one or two sentence summary instead of typing it as chat text.
|
|
15
|
+
|
|
16
|
+
If the user's request is a simple question that needs no tools, just answer it directly.`;
|
|
17
|
+
}
|
|
18
|
+
/** Render the file-change hooks into a nice footer for context. */
|
|
19
|
+
export function withCwd(prompt, cwd) {
|
|
20
|
+
return `${prompt}\n\n(Working directory: ${cwd})`;
|
|
21
|
+
}
|
package/dist/terms.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
/** Read the bundled TERMS.md (shipped in the npm package next to dist/). */
|
|
4
|
+
export function readTerms() {
|
|
5
|
+
try {
|
|
6
|
+
return readFileSync(fileURLToPath(new URL("../TERMS.md", import.meta.url)), "utf8");
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return [
|
|
10
|
+
"CodeShark Terms of Service",
|
|
11
|
+
"",
|
|
12
|
+
"CodeShark is provided AS IS, without warranty of any kind.",
|
|
13
|
+
"The shared gateway is a free, best-effort service with rate limits and queues.",
|
|
14
|
+
"You are responsible for your prompts, your files, and the commands you run.",
|
|
15
|
+
"See TERMS.md in the repository or package for the full terms.",
|
|
16
|
+
].join("\n");
|
|
17
|
+
}
|
|
18
|
+
}
|