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.
Files changed (2) hide show
  1. package/dist/cli.mjs +189 -71
  2. 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
- chalk.yellow(`
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(chalk.yellow(" Allow? [y/N] "));
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
- const yes = ch.toLowerCase() === "y";
214
- process.stderr.write(yes ? "y\n" : "N\n");
215
- resolve4(yes);
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 PURPLE = chalk2.hex("#a855f7");
276
- function createSpinner() {
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${PURPLE(frames[i++ % frames.length])} ${chalk2.gray("thinking...")}`
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 spinner = createSpinner();
329
- let spinnerStopped = false;
330
- spinner.start();
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 (!spinnerStopped && (event.type === "text-delta" || event.type === "tool-call" || event.type === "error")) {
333
- spinner.stop();
334
- spinnerStopped = true;
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
- case "tool-result":
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(`\u2705 done`) + chalk2.gray(` \u2192 ${truncate(String(event.output), 120)}
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
- \u274C Tool error [${event.toolName}]: ${String(event.error)}
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
- if (!spinnerStopped) {
372
- spinner.stop();
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 formatArgs(args) {
393
- if (typeof args !== "object" || args === null) return String(args);
464
+ function getArgHint(toolName, args) {
465
+ if (typeof args !== "object" || args === null) return "";
394
466
  const obj = args;
395
- return Object.entries(obj).map(([k, v]) => {
396
- const val = typeof v === "string" ? truncate(v, 60) : String(v);
397
- return `${k}: ${val}`;
398
- }).join(", ");
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, "\\n");
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 PURPLE2 = chalk3.hex("#a855f7");
407
- var GRAY = chalk3.gray;
408
- var YELLOW = chalk3.yellow;
409
- var GREEN = chalk3.green;
410
- var RED = chalk3.red;
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(PURPLE2(line));
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: PURPLE2("\u25C6 \u9009\u62E9\u64CD\u4F5C"),
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(GRAY("\n \u2713 \u5BF9\u8BDD\u5DF2\u6E05\u7A7A\n"));
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(GRAY("\nBye! \u{1F988}"));
543
+ console.log(GRAY2("\nBye! \u{1F988}"));
459
544
  return { multiConfig, config: resolveConfig(multiConfig), exit: true };
460
545
  }
461
546
  } catch {
462
- console.log(GRAY("\n \u53D6\u6D88\n"));
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 ? GREEN("\u2713 \u5DF2\u914D\u7F6E") : YELLOW("\u2717 \u672A\u914D\u7F6E");
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: PURPLE2("\u25C6 \u9009\u62E9 Provider"),
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 ? GRAY("(\u56DE\u8F66\u4FDD\u7559 " + currentKey.slice(0, 6) + "\u2022\u2022\u2022)") : GRAY("(\u5FC5\u586B)");
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: PURPLE2("\u25C6 API Key ") + hint,
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(GREEN(`
605
+ console.log(GREEN2(`
504
606
  \u2713 \u5DF2\u5207\u6362\u5230 ${PROVIDERS[selectedProvider].label}${keyMsg}`) + "\n");
505
607
  if (!newConfig.apiKey) {
506
- console.log(YELLOW(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\n"));
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(GRAY("\n \u53D6\u6D88\n"));
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
- process.stdout.write("\b \b");
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
- return PURPLE2(" \u25C6") + GRAY(` ${label}`) + CYAN(` [${config.model}]`) + GRAY(" \u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n");
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(PURPLE2(" Usage:"));
571
- console.log(" " + PURPLE2("sharkcode") + GRAY(" \u2014 \u4EA4\u4E92\u6A21\u5F0F\uFF08\u76F4\u63A5\u542F\u52A8\uFF09"));
572
- console.log(" " + PURPLE2("sharkcode") + YELLOW(' "prompt"') + GRAY(" \u2014 \u5355\u6B21\u6267\u884C"));
573
- console.log(GRAY("\n \u4EA4\u4E92\u6A21\u5F0F\u5185\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
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.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(RED("\u274C \u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C sharkcode \u5E76\u8F93\u5165 / \u914D\u7F6E Provider\u3002"));
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
- PURPLE2("\n\u{1F988} SharkCode") + GRAY(` | ${PROVIDERS[config2.providerName]?.label ?? config2.providerName} | ${config2.model}
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
- YELLOW(" \u26A0 \u5C1A\u672A\u914D\u7F6E API Key\u3002") + GRAY("\u8F93\u5165 / \u7136\u540E\u9009\u62E9\u300C\u5207\u6362 / \u914D\u7F6E Provider\u300D\n")
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(PURPLE2("\n\u25C6 "));
728
+ const raw = await readLineRaw(PURPLE3("\n\u25C6 "));
611
729
  if (raw === null) {
612
- console.log(GRAY("\nBye! \u{1F988}"));
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(GRAY("Bye! \u{1F988}"));
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(GRAY(" \u672A\u77E5\u547D\u4EE4\u3002\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
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(YELLOW(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\u3002\u8F93\u5165 / \u2192 \u5207\u6362 / \u914D\u7F6E Provider\n"));
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(RED(`
783
+ console.error(RED2(`
666
784
  \u274C ${String(err)}
667
785
  `));
668
786
  messages.pop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sharkcode",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Local First, open-source AI Coding Agent",
5
5
  "type": "module",
6
6
  "bin": {