sharkcode 0.3.3 → 0.3.5
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/dist/cli.mjs +189 -71
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -33,6 +33,7 @@ function serializeConfig(mc) {
|
|
|
33
33
|
"",
|
|
34
34
|
"[default]",
|
|
35
35
|
`provider = "${mc.activeProvider}"`,
|
|
36
|
+
`permission_mode = "${mc.permissionMode}"`,
|
|
36
37
|
"",
|
|
37
38
|
"[providers.deepseek]",
|
|
38
39
|
"# API key from https://platform.deepseek.com",
|
|
@@ -53,6 +54,7 @@ function ensureConfig() {
|
|
|
53
54
|
if (!existsSync(CONFIG_FILE)) {
|
|
54
55
|
const initial = {
|
|
55
56
|
activeProvider: "deepseek",
|
|
57
|
+
permissionMode: "prompt",
|
|
56
58
|
providers: {
|
|
57
59
|
deepseek: { key: "", model: PROVIDERS.deepseek.defaultModel },
|
|
58
60
|
ark: { key: "", model: PROVIDERS.ark.defaultModel }
|
|
@@ -75,8 +77,10 @@ function readMultiConfig() {
|
|
|
75
77
|
const deepseekKey = process.env.DEEPSEEK_API_KEY || providersRaw.deepseek?.key || legacy?.key || "";
|
|
76
78
|
const arkKey = process.env.ARK_API_KEY || providersRaw.ark?.key || "";
|
|
77
79
|
const activeProvider = defaultSection.provider || (legacy ? "deepseek" : "deepseek");
|
|
80
|
+
const permissionMode = defaultSection.permission_mode === "full-access" ? "full-access" : "prompt";
|
|
78
81
|
return {
|
|
79
82
|
activeProvider,
|
|
83
|
+
permissionMode,
|
|
80
84
|
providers: {
|
|
81
85
|
deepseek: {
|
|
82
86
|
key: deepseekKey,
|
|
@@ -200,19 +204,57 @@ import { exec } from "child_process";
|
|
|
200
204
|
|
|
201
205
|
// src/permission.ts
|
|
202
206
|
import chalk from "chalk";
|
|
207
|
+
var PURPLE = chalk.hex("#a855f7");
|
|
208
|
+
var GRAY = chalk.gray;
|
|
209
|
+
var GREEN = chalk.green;
|
|
210
|
+
var RED = chalk.red;
|
|
211
|
+
var YELLOW = chalk.yellow;
|
|
212
|
+
var DIM = chalk.dim;
|
|
213
|
+
var _permissionMode = "prompt";
|
|
214
|
+
function setPermissionMode(mode) {
|
|
215
|
+
_permissionMode = mode;
|
|
216
|
+
}
|
|
217
|
+
function getPermissionMode() {
|
|
218
|
+
return _permissionMode;
|
|
219
|
+
}
|
|
203
220
|
async function askPermission(command) {
|
|
221
|
+
if (_permissionMode === "full-access") {
|
|
222
|
+
process.stdout.write(
|
|
223
|
+
PURPLE(" \u25C6 ") + DIM("auto-approved") + GRAY(" \u203A ") + chalk.white(command) + "\n"
|
|
224
|
+
);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
const width = Math.min(72, process.stdout.columns ?? 80);
|
|
228
|
+
const innerWidth = width - 4;
|
|
229
|
+
const line = (s) => ` ${s}
|
|
230
|
+
`;
|
|
231
|
+
const bar = PURPLE("\u2500".repeat(width));
|
|
232
|
+
const label = YELLOW(" \u26A1 \u6267\u884C\u547D\u4EE4");
|
|
233
|
+
const cmd = chalk.white.bold(command.length > innerWidth ? command.slice(0, innerWidth - 1) + "\u2026" : command);
|
|
234
|
+
process.stderr.write("\n");
|
|
235
|
+
process.stderr.write(bar + "\n");
|
|
236
|
+
process.stderr.write(line(label));
|
|
237
|
+
process.stderr.write(line(" " + cmd));
|
|
238
|
+
process.stderr.write(bar + "\n");
|
|
204
239
|
process.stderr.write(
|
|
205
|
-
|
|
206
|
-
\u26A0\uFE0F Will execute: `) + chalk.white(command) + "\n"
|
|
240
|
+
" " + GREEN("[ y ] \u5141\u8BB8") + " " + RED("[ n ] \u62D2\u7EDD") + " " + DIM("[ a ] \u672C\u6B21\u5168\u90E8\u5141\u8BB8") + "\n\n"
|
|
207
241
|
);
|
|
208
|
-
process.stderr.write(
|
|
242
|
+
process.stderr.write(PURPLE(" \u25C6 ") + GRAY("\u6309\u952E\u51B3\u5B9A \u203A "));
|
|
209
243
|
return new Promise((resolve4) => {
|
|
210
244
|
const onData = (chunk) => {
|
|
211
|
-
const ch = chunk.toString("utf8")[0] ?? "";
|
|
245
|
+
const ch = chunk.toString("utf8")[0]?.toLowerCase() ?? "";
|
|
212
246
|
process.stdin.removeListener("data", onData);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
247
|
+
if (ch === "y") {
|
|
248
|
+
process.stderr.write(GREEN("y \u5141\u8BB8\n\n"));
|
|
249
|
+
resolve4(true);
|
|
250
|
+
} else if (ch === "a") {
|
|
251
|
+
process.stderr.write(YELLOW("a \u5DF2\u5207\u6362\u4E3A Full Access\uFF08\u672C\u6B21\u4F1A\u8BDD\uFF09\n\n"));
|
|
252
|
+
_permissionMode = "full-access";
|
|
253
|
+
resolve4(true);
|
|
254
|
+
} else {
|
|
255
|
+
process.stderr.write(RED("n \u62D2\u7EDD\n\n"));
|
|
256
|
+
resolve4(false);
|
|
257
|
+
}
|
|
216
258
|
};
|
|
217
259
|
process.stdin.once("data", onData);
|
|
218
260
|
});
|
|
@@ -272,8 +314,14 @@ function createProvider(config) {
|
|
|
272
314
|
}
|
|
273
315
|
|
|
274
316
|
// src/agent.ts
|
|
275
|
-
var
|
|
276
|
-
|
|
317
|
+
var PURPLE2 = chalk2.hex("#a855f7");
|
|
318
|
+
var TOOL_LABELS = {
|
|
319
|
+
read_file: { icon: "\u{1F4D6}", verb: "reading file" },
|
|
320
|
+
write_file: { icon: "\u270D\uFE0F ", verb: "writing file" },
|
|
321
|
+
edit_file: { icon: "\u270F\uFE0F ", verb: "editing file" },
|
|
322
|
+
bash: { icon: "\u2699\uFE0F ", verb: "running command" }
|
|
323
|
+
};
|
|
324
|
+
function createSpinner(label) {
|
|
277
325
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
278
326
|
let i = 0;
|
|
279
327
|
let timer = null;
|
|
@@ -282,10 +330,13 @@ function createSpinner() {
|
|
|
282
330
|
process.stdout.write("\n");
|
|
283
331
|
timer = setInterval(() => {
|
|
284
332
|
process.stdout.write(
|
|
285
|
-
`\r${
|
|
333
|
+
`\r${PURPLE2(frames[i++ % frames.length])} ${chalk2.gray(label)}`
|
|
286
334
|
);
|
|
287
335
|
}, 80);
|
|
288
336
|
},
|
|
337
|
+
update(newLabel) {
|
|
338
|
+
label = newLabel;
|
|
339
|
+
},
|
|
289
340
|
stop() {
|
|
290
341
|
if (timer) {
|
|
291
342
|
clearInterval(timer);
|
|
@@ -325,36 +376,54 @@ async function runAgent(messages, config) {
|
|
|
325
376
|
stopWhen: stepCountIs(30)
|
|
326
377
|
});
|
|
327
378
|
let currentStep = 0;
|
|
328
|
-
const
|
|
329
|
-
let
|
|
330
|
-
|
|
379
|
+
const thinkingSpinner = createSpinner("thinking...");
|
|
380
|
+
let thinkingDone = false;
|
|
381
|
+
let toolSpinner = null;
|
|
382
|
+
let currentToolName = "";
|
|
383
|
+
let currentToolArgs = null;
|
|
384
|
+
thinkingSpinner.start();
|
|
331
385
|
for await (const event of result.fullStream) {
|
|
332
|
-
if (!
|
|
333
|
-
|
|
334
|
-
|
|
386
|
+
if (!thinkingDone && (event.type === "text-delta" || event.type === "tool-call" || event.type === "error")) {
|
|
387
|
+
thinkingSpinner.stop();
|
|
388
|
+
thinkingDone = true;
|
|
335
389
|
}
|
|
336
390
|
switch (event.type) {
|
|
337
391
|
case "text-delta":
|
|
338
392
|
process.stdout.write(event.text);
|
|
339
393
|
break;
|
|
340
|
-
case "tool-call":
|
|
394
|
+
case "tool-call": {
|
|
395
|
+
const meta = TOOL_LABELS[event.toolName] ?? { icon: "\u{1F527}", verb: "running" };
|
|
396
|
+
currentToolName = event.toolName;
|
|
397
|
+
currentToolArgs = event.input;
|
|
398
|
+
const argHint = getArgHint(event.toolName, event.input);
|
|
399
|
+
const spinLabel = `${meta.verb}${argHint ? ` \u203A ${argHint}` : ""}`;
|
|
341
400
|
process.stdout.write(
|
|
342
|
-
chalk2.cyan(`
|
|
343
|
-
\u{1F527} ${event.toolName}`) + chalk2.gray(`(${formatArgs(event.input)})
|
|
344
|
-
`)
|
|
401
|
+
"\n" + chalk2.cyan(`${meta.icon} ${event.toolName}`) + chalk2.gray(argHint ? ` ${argHint}` : "") + "\n"
|
|
345
402
|
);
|
|
403
|
+
toolSpinner = createSpinner(spinLabel);
|
|
404
|
+
toolSpinner.start();
|
|
346
405
|
break;
|
|
347
|
-
|
|
406
|
+
}
|
|
407
|
+
case "tool-result": {
|
|
408
|
+
if (toolSpinner) {
|
|
409
|
+
toolSpinner.stop();
|
|
410
|
+
toolSpinner = null;
|
|
411
|
+
}
|
|
412
|
+
const meta = TOOL_LABELS[currentToolName] ?? { icon: "\u{1F527}", verb: "done" };
|
|
413
|
+
const summary = truncate(String(event.output), 100);
|
|
348
414
|
process.stdout.write(
|
|
349
|
-
chalk2.green(
|
|
350
|
-
|
|
351
|
-
`)
|
|
415
|
+
chalk2.green(` \u2713 done`) + chalk2.gray(` ${summary}`) + "\n\n"
|
|
352
416
|
);
|
|
353
417
|
break;
|
|
418
|
+
}
|
|
354
419
|
case "tool-error":
|
|
420
|
+
if (toolSpinner) {
|
|
421
|
+
toolSpinner.stop();
|
|
422
|
+
toolSpinner = null;
|
|
423
|
+
}
|
|
355
424
|
process.stderr.write(
|
|
356
425
|
chalk2.red(`
|
|
357
|
-
\
|
|
426
|
+
\u2717 Tool error [${event.toolName}]: ${String(event.error)}
|
|
358
427
|
`)
|
|
359
428
|
);
|
|
360
429
|
break;
|
|
@@ -362,22 +431,25 @@ async function runAgent(messages, config) {
|
|
|
362
431
|
currentStep++;
|
|
363
432
|
break;
|
|
364
433
|
case "error":
|
|
434
|
+
if (toolSpinner) {
|
|
435
|
+
toolSpinner.stop();
|
|
436
|
+
toolSpinner = null;
|
|
437
|
+
}
|
|
438
|
+
thinkingSpinner.stop();
|
|
365
439
|
process.stderr.write(chalk2.red(`
|
|
366
440
|
\u274C Error: ${String(event.error)}
|
|
367
441
|
`));
|
|
368
442
|
break;
|
|
369
443
|
}
|
|
370
444
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
445
|
+
thinkingSpinner.stop();
|
|
446
|
+
if (toolSpinner) toolSpinner.stop();
|
|
374
447
|
process.stdout.write("\n");
|
|
375
448
|
const usage = await result.totalUsage;
|
|
376
449
|
if (usage) {
|
|
377
450
|
process.stderr.write(
|
|
378
451
|
chalk2.gray(
|
|
379
|
-
|
|
380
|
-
\u{1F4CA} Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out | Steps: ${currentStep}
|
|
452
|
+
`\u{1F4CA} ${usage.inputTokens} in / ${usage.outputTokens} out | steps: ${currentStep}
|
|
381
453
|
`
|
|
382
454
|
)
|
|
383
455
|
);
|
|
@@ -389,25 +461,33 @@ async function runAgent(messages, config) {
|
|
|
389
461
|
return messages;
|
|
390
462
|
}
|
|
391
463
|
}
|
|
392
|
-
function
|
|
393
|
-
if (typeof args !== "object" || args === null) return
|
|
464
|
+
function getArgHint(toolName, args) {
|
|
465
|
+
if (typeof args !== "object" || args === null) return "";
|
|
394
466
|
const obj = args;
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
467
|
+
switch (toolName) {
|
|
468
|
+
case "read_file":
|
|
469
|
+
case "write_file":
|
|
470
|
+
case "edit_file":
|
|
471
|
+
return truncate(String(obj.path ?? obj.file_path ?? ""), 50);
|
|
472
|
+
case "bash":
|
|
473
|
+
return truncate(String(obj.command ?? ""), 50);
|
|
474
|
+
default: {
|
|
475
|
+
const first = Object.values(obj).find((v) => typeof v === "string");
|
|
476
|
+
return first ? truncate(first, 50) : "";
|
|
477
|
+
}
|
|
478
|
+
}
|
|
399
479
|
}
|
|
400
480
|
function truncate(str, max) {
|
|
401
|
-
const oneLine = str.replace(/\n/g, "
|
|
481
|
+
const oneLine = str.replace(/\n/g, "\u21B5");
|
|
402
482
|
return oneLine.length > max ? oneLine.slice(0, max) + "\u2026" : oneLine;
|
|
403
483
|
}
|
|
404
484
|
|
|
405
485
|
// src/cli.ts
|
|
406
|
-
var
|
|
407
|
-
var
|
|
408
|
-
var
|
|
409
|
-
var
|
|
410
|
-
var
|
|
486
|
+
var PURPLE3 = chalk3.hex("#a855f7");
|
|
487
|
+
var GRAY2 = chalk3.gray;
|
|
488
|
+
var YELLOW2 = chalk3.yellow;
|
|
489
|
+
var GREEN2 = chalk3.green;
|
|
490
|
+
var RED2 = chalk3.red;
|
|
411
491
|
var CYAN = chalk3.cyan;
|
|
412
492
|
var GLYPHS = {
|
|
413
493
|
S: [[0, 1, 1, 1, 1], [1, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 1], [1, 1, 1, 1, 0]],
|
|
@@ -432,18 +512,21 @@ function renderWord(word, padLeft = 2) {
|
|
|
432
512
|
}
|
|
433
513
|
if (i < letters.length - 1) line += " ";
|
|
434
514
|
}
|
|
435
|
-
rows.push(
|
|
515
|
+
rows.push(PURPLE3(line));
|
|
436
516
|
}
|
|
437
517
|
return rows;
|
|
438
518
|
}
|
|
439
519
|
var BANNER = ["", ...renderWord("shark", 2), "", ...renderWord("code", 8), ""].join("\n");
|
|
440
520
|
async function showCommandMenu(multiConfig) {
|
|
441
521
|
console.log();
|
|
522
|
+
const permMode = getPermissionMode();
|
|
523
|
+
const permLabel = permMode === "full-access" ? "\u26A1 \u6743\u9650\u6A21\u5F0F\uFF1AFull Access " + chalk3.dim("(\u70B9\u51FB\u5207\u6362\u56DE\u9ED8\u8BA4)") : "\u{1F510} \u6743\u9650\u6A21\u5F0F\uFF1A\u9ED8\u8BA4 " + chalk3.dim("(\u70B9\u51FB\u5F00\u542F Full Access)");
|
|
442
524
|
try {
|
|
443
525
|
const action = await select({
|
|
444
|
-
message:
|
|
526
|
+
message: PURPLE3("\u25C6 \u9009\u62E9\u64CD\u4F5C"),
|
|
445
527
|
choices: [
|
|
446
528
|
{ name: "\u{1F50C} \u5207\u6362 / \u914D\u7F6E Provider", value: "provider" },
|
|
529
|
+
{ name: permLabel, value: "permission" },
|
|
447
530
|
{ name: "\u{1F5D1}\uFE0F \u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", value: "clear" },
|
|
448
531
|
{ name: "\u{1F6AA} \u9000\u51FA", value: "exit" }
|
|
449
532
|
]
|
|
@@ -451,35 +534,54 @@ async function showCommandMenu(multiConfig) {
|
|
|
451
534
|
switch (action) {
|
|
452
535
|
case "provider":
|
|
453
536
|
return showSetupFlow(multiConfig);
|
|
537
|
+
case "permission":
|
|
538
|
+
return togglePermissionMode(multiConfig);
|
|
454
539
|
case "clear":
|
|
455
|
-
console.log(
|
|
540
|
+
console.log(GRAY2("\n \u2713 \u5BF9\u8BDD\u5DF2\u6E05\u7A7A\n"));
|
|
456
541
|
return { multiConfig, config: resolveConfig(multiConfig), clearHistory: true };
|
|
457
542
|
case "exit":
|
|
458
|
-
console.log(
|
|
543
|
+
console.log(GRAY2("\nBye! \u{1F988}"));
|
|
459
544
|
return { multiConfig, config: resolveConfig(multiConfig), exit: true };
|
|
460
545
|
}
|
|
461
546
|
} catch {
|
|
462
|
-
console.log(
|
|
547
|
+
console.log(GRAY2("\n \u53D6\u6D88\n"));
|
|
463
548
|
}
|
|
464
549
|
return { multiConfig, config: resolveConfig(multiConfig) };
|
|
465
550
|
}
|
|
551
|
+
async function togglePermissionMode(multiConfig) {
|
|
552
|
+
const current = getPermissionMode();
|
|
553
|
+
const next = current === "full-access" ? "prompt" : "full-access";
|
|
554
|
+
setPermissionMode(next);
|
|
555
|
+
const updated = { ...multiConfig, permissionMode: next };
|
|
556
|
+
saveMultiConfig(updated);
|
|
557
|
+
if (next === "full-access") {
|
|
558
|
+
console.log(
|
|
559
|
+
chalk3.yellow("\n \u26A1 Full Access \u5DF2\u5F00\u542F") + GRAY2(" \u2014 agent \u5C06\u81EA\u52A8\u6279\u51C6\u6240\u6709\u5DE5\u5177\u64CD\u4F5C\n")
|
|
560
|
+
);
|
|
561
|
+
} else {
|
|
562
|
+
console.log(
|
|
563
|
+
chalk3.green("\n \u{1F510} \u5DF2\u6062\u590D\u9ED8\u8BA4\u6743\u9650") + GRAY2(" \u2014 \u6BCF\u6B21\u5DE5\u5177\u8C03\u7528\u524D\u4F1A\u8BE2\u95EE\n")
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
return { multiConfig: updated, config: resolveConfig(updated) };
|
|
567
|
+
}
|
|
466
568
|
async function showSetupFlow(multiConfig) {
|
|
467
569
|
console.log();
|
|
468
570
|
try {
|
|
469
571
|
const providerChoices = Object.entries(PROVIDERS).map(([id, meta]) => {
|
|
470
572
|
const hasKey = !!multiConfig.providers[id]?.key;
|
|
471
|
-
const badge = hasKey ?
|
|
573
|
+
const badge = hasKey ? GREEN2("\u2713 \u5DF2\u914D\u7F6E") : YELLOW2("\u2717 \u672A\u914D\u7F6E");
|
|
472
574
|
return { name: `${meta.label} ${badge}`, value: id };
|
|
473
575
|
});
|
|
474
576
|
const selectedProvider = await select({
|
|
475
|
-
message:
|
|
577
|
+
message: PURPLE3("\u25C6 \u9009\u62E9 Provider"),
|
|
476
578
|
choices: providerChoices,
|
|
477
579
|
default: multiConfig.activeProvider
|
|
478
580
|
});
|
|
479
581
|
const currentKey = multiConfig.providers[selectedProvider]?.key ?? "";
|
|
480
|
-
const hint = currentKey ?
|
|
582
|
+
const hint = currentKey ? GRAY2("(\u56DE\u8F66\u4FDD\u7559 " + currentKey.slice(0, 6) + "\u2022\u2022\u2022)") : GRAY2("(\u5FC5\u586B)");
|
|
481
583
|
const rawKey = await input({
|
|
482
|
-
message:
|
|
584
|
+
message: PURPLE3("\u25C6 API Key ") + hint,
|
|
483
585
|
default: currentKey || void 0
|
|
484
586
|
});
|
|
485
587
|
const newKey = rawKey.trim() || currentKey;
|
|
@@ -500,17 +602,29 @@ async function showSetupFlow(multiConfig) {
|
|
|
500
602
|
saveMultiConfig(updated);
|
|
501
603
|
const newConfig = resolveConfig(updated);
|
|
502
604
|
const keyMsg = newKey && newKey !== currentKey ? "\uFF0CAPI Key \u5DF2\u4FDD\u5B58" : "";
|
|
503
|
-
console.log(
|
|
605
|
+
console.log(GREEN2(`
|
|
504
606
|
\u2713 \u5DF2\u5207\u6362\u5230 ${PROVIDERS[selectedProvider].label}${keyMsg}`) + "\n");
|
|
505
607
|
if (!newConfig.apiKey) {
|
|
506
|
-
console.log(
|
|
608
|
+
console.log(YELLOW2(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\n"));
|
|
507
609
|
}
|
|
508
610
|
return { multiConfig: updated, config: newConfig };
|
|
509
611
|
} catch {
|
|
510
|
-
console.log(
|
|
612
|
+
console.log(GRAY2("\n \u53D6\u6D88\n"));
|
|
511
613
|
return { multiConfig, config: resolveConfig(multiConfig) };
|
|
512
614
|
}
|
|
513
615
|
}
|
|
616
|
+
function charDisplayWidth(ch) {
|
|
617
|
+
const cp = ch.codePointAt(0);
|
|
618
|
+
if (cp >= 4352 && cp <= 4447 || // Hangul Jamo
|
|
619
|
+
cp >= 11904 && cp <= 12350 || // CJK Radicals Supplement, Kangxi, etc.
|
|
620
|
+
cp >= 12353 && cp <= 13311 || // Hiragana, Katakana, CJK Symbols
|
|
621
|
+
cp >= 13312 && cp <= 40959 || // CJK Unified Ideographs (+ Ext A)
|
|
622
|
+
cp >= 44032 && cp <= 55215 || // Hangul Syllables
|
|
623
|
+
cp >= 63744 && cp <= 64255 || // CJK Compatibility Ideographs
|
|
624
|
+
cp >= 65281 && cp <= 65376 || // Fullwidth Latin / Punctuation
|
|
625
|
+
cp >= 65504 && cp <= 65510) return 2;
|
|
626
|
+
return 1;
|
|
627
|
+
}
|
|
514
628
|
async function readLineRaw(promptStr) {
|
|
515
629
|
process.stdout.write(promptStr);
|
|
516
630
|
return new Promise((resolve4) => {
|
|
@@ -540,9 +654,10 @@ async function readLineRaw(promptStr) {
|
|
|
540
654
|
if (code === 127 || code === 8) {
|
|
541
655
|
if (buffer.length > 0) {
|
|
542
656
|
const chars = [...buffer];
|
|
543
|
-
chars.pop();
|
|
657
|
+
const removed = chars.pop();
|
|
544
658
|
buffer = chars.join("");
|
|
545
|
-
|
|
659
|
+
const w = charDisplayWidth(removed);
|
|
660
|
+
process.stdout.write("\b".repeat(w) + " ".repeat(w) + "\b".repeat(w));
|
|
546
661
|
}
|
|
547
662
|
continue;
|
|
548
663
|
}
|
|
@@ -561,31 +676,33 @@ async function readLineRaw(promptStr) {
|
|
|
561
676
|
}
|
|
562
677
|
function statusLine(config) {
|
|
563
678
|
const label = PROVIDERS[config.providerName]?.label ?? config.providerName;
|
|
564
|
-
|
|
679
|
+
const permMode = getPermissionMode();
|
|
680
|
+
const permBadge = permMode === "full-access" ? chalk3.yellow(" \u26A1 Full Access") : GRAY2(" \u{1F510} \u9ED8\u8BA4\u6743\u9650");
|
|
681
|
+
return PURPLE3(" \u25C6") + GRAY2(` ${label}`) + CYAN(` [${config.model}]`) + permBadge + GRAY2(" \u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n");
|
|
565
682
|
}
|
|
566
683
|
async function main() {
|
|
567
684
|
const args = process.argv.slice(2);
|
|
568
685
|
if (args[0] === "--help" || args[0] === "-h") {
|
|
569
686
|
console.log(BANNER);
|
|
570
|
-
console.log(
|
|
571
|
-
console.log(" " +
|
|
572
|
-
console.log(" " +
|
|
573
|
-
console.log(
|
|
687
|
+
console.log(PURPLE3(" Usage:"));
|
|
688
|
+
console.log(" " + PURPLE3("sharkcode") + GRAY2(" \u2014 \u4EA4\u4E92\u6A21\u5F0F\uFF08\u76F4\u63A5\u542F\u52A8\uFF09"));
|
|
689
|
+
console.log(" " + PURPLE3("sharkcode") + YELLOW2(' "prompt"') + GRAY2(" \u2014 \u5355\u6B21\u6267\u884C"));
|
|
690
|
+
console.log(GRAY2("\n \u4EA4\u4E92\u6A21\u5F0F\u5185\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
|
|
574
691
|
return;
|
|
575
692
|
}
|
|
576
693
|
if (args[0] === "--version" || args[0] === "-v") {
|
|
577
|
-
console.log("sharkcode v0.3.
|
|
694
|
+
console.log("sharkcode v0.3.5");
|
|
578
695
|
return;
|
|
579
696
|
}
|
|
580
697
|
if (args.length > 0) {
|
|
581
698
|
const mc = readMultiConfig();
|
|
582
699
|
const config2 = resolveConfig(mc);
|
|
583
700
|
if (!config2.apiKey) {
|
|
584
|
-
console.error(
|
|
701
|
+
console.error(RED2("\u274C \u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C sharkcode \u5E76\u8F93\u5165 / \u914D\u7F6E Provider\u3002"));
|
|
585
702
|
process.exit(1);
|
|
586
703
|
}
|
|
587
704
|
console.log(
|
|
588
|
-
|
|
705
|
+
PURPLE3("\n\u{1F988} SharkCode") + GRAY2(` | ${PROVIDERS[config2.providerName]?.label ?? config2.providerName} | ${config2.model}
|
|
589
706
|
`)
|
|
590
707
|
);
|
|
591
708
|
await runAgent([{ role: "user", content: args.join(" ") }], config2);
|
|
@@ -594,6 +711,7 @@ async function main() {
|
|
|
594
711
|
console.log(BANNER);
|
|
595
712
|
let multiConfig = readMultiConfig();
|
|
596
713
|
let config = resolveConfig(multiConfig);
|
|
714
|
+
setPermissionMode(multiConfig.permissionMode ?? "prompt");
|
|
597
715
|
try {
|
|
598
716
|
process.stdin.setRawMode(true);
|
|
599
717
|
process.stdin.resume();
|
|
@@ -602,20 +720,20 @@ async function main() {
|
|
|
602
720
|
console.log(statusLine(config));
|
|
603
721
|
if (!config.apiKey) {
|
|
604
722
|
console.log(
|
|
605
|
-
|
|
723
|
+
YELLOW2(" \u26A0 \u5C1A\u672A\u914D\u7F6E API Key\u3002") + GRAY2("\u8F93\u5165 / \u7136\u540E\u9009\u62E9\u300C\u5207\u6362 / \u914D\u7F6E Provider\u300D\n")
|
|
606
724
|
);
|
|
607
725
|
}
|
|
608
726
|
let messages = [];
|
|
609
727
|
while (true) {
|
|
610
|
-
const raw = await readLineRaw(
|
|
728
|
+
const raw = await readLineRaw(PURPLE3("\n\u25C6 "));
|
|
611
729
|
if (raw === null) {
|
|
612
|
-
console.log(
|
|
730
|
+
console.log(GRAY2("\nBye! \u{1F988}"));
|
|
613
731
|
break;
|
|
614
732
|
}
|
|
615
733
|
const trimmed = raw.trim();
|
|
616
734
|
if (!trimmed) continue;
|
|
617
735
|
if (trimmed === "exit" || trimmed === "quit") {
|
|
618
|
-
console.log(
|
|
736
|
+
console.log(GRAY2("Bye! \u{1F988}"));
|
|
619
737
|
break;
|
|
620
738
|
}
|
|
621
739
|
if (trimmed === "/") {
|
|
@@ -646,11 +764,11 @@ async function main() {
|
|
|
646
764
|
continue;
|
|
647
765
|
}
|
|
648
766
|
if (trimmed.startsWith("/")) {
|
|
649
|
-
console.log(
|
|
767
|
+
console.log(GRAY2(" \u672A\u77E5\u547D\u4EE4\u3002\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
|
|
650
768
|
continue;
|
|
651
769
|
}
|
|
652
770
|
if (!config.apiKey) {
|
|
653
|
-
console.log(
|
|
771
|
+
console.log(YELLOW2(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\u3002\u8F93\u5165 / \u2192 \u5207\u6362 / \u914D\u7F6E Provider\n"));
|
|
654
772
|
continue;
|
|
655
773
|
}
|
|
656
774
|
messages.push({ role: "user", content: trimmed });
|
|
@@ -662,7 +780,7 @@ async function main() {
|
|
|
662
780
|
} catch {
|
|
663
781
|
}
|
|
664
782
|
} catch (err) {
|
|
665
|
-
console.error(
|
|
783
|
+
console.error(RED2(`
|
|
666
784
|
\u274C ${String(err)}
|
|
667
785
|
`));
|
|
668
786
|
messages.pop();
|