sharkcode 0.3.4 → 0.3.6

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 +178 -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]],
@@ -422,28 +502,33 @@ var GLYPHS = {
422
502
  };
423
503
  function renderWord(word, padLeft = 2) {
424
504
  const letters = word.toUpperCase().split("").map((c) => GLYPHS[c]);
505
+ const ON = chalk3.bgHex("#a855f7")(" ");
506
+ const OFF = " ";
425
507
  const rows = [];
426
508
  for (let row = 0; row < 5; row++) {
427
509
  let line = " ".repeat(padLeft);
428
510
  for (let i = 0; i < letters.length; i++) {
429
511
  const letter = letters[i];
430
512
  for (let col = 0; col < letter[row].length; col++) {
431
- line += letter[row][col] ? "\u2588\u2588" : " ";
513
+ line += letter[row][col] ? ON : OFF;
432
514
  }
433
- if (i < letters.length - 1) line += " ";
515
+ if (i < letters.length - 1) line += OFF;
434
516
  }
435
- rows.push(PURPLE2(line));
517
+ rows.push(line);
436
518
  }
437
519
  return rows;
438
520
  }
439
521
  var BANNER = ["", ...renderWord("shark", 2), "", ...renderWord("code", 8), ""].join("\n");
440
522
  async function showCommandMenu(multiConfig) {
441
523
  console.log();
524
+ const permMode = getPermissionMode();
525
+ 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
526
  try {
443
527
  const action = await select({
444
- message: PURPLE2("\u25C6 \u9009\u62E9\u64CD\u4F5C"),
528
+ message: PURPLE3("\u25C6 \u9009\u62E9\u64CD\u4F5C"),
445
529
  choices: [
446
530
  { name: "\u{1F50C} \u5207\u6362 / \u914D\u7F6E Provider", value: "provider" },
531
+ { name: permLabel, value: "permission" },
447
532
  { name: "\u{1F5D1}\uFE0F \u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", value: "clear" },
448
533
  { name: "\u{1F6AA} \u9000\u51FA", value: "exit" }
449
534
  ]
@@ -451,35 +536,54 @@ async function showCommandMenu(multiConfig) {
451
536
  switch (action) {
452
537
  case "provider":
453
538
  return showSetupFlow(multiConfig);
539
+ case "permission":
540
+ return togglePermissionMode(multiConfig);
454
541
  case "clear":
455
- console.log(GRAY("\n \u2713 \u5BF9\u8BDD\u5DF2\u6E05\u7A7A\n"));
542
+ console.log(GRAY2("\n \u2713 \u5BF9\u8BDD\u5DF2\u6E05\u7A7A\n"));
456
543
  return { multiConfig, config: resolveConfig(multiConfig), clearHistory: true };
457
544
  case "exit":
458
- console.log(GRAY("\nBye! \u{1F988}"));
545
+ console.log(GRAY2("\nBye! \u{1F988}"));
459
546
  return { multiConfig, config: resolveConfig(multiConfig), exit: true };
460
547
  }
461
548
  } catch {
462
- console.log(GRAY("\n \u53D6\u6D88\n"));
549
+ console.log(GRAY2("\n \u53D6\u6D88\n"));
463
550
  }
464
551
  return { multiConfig, config: resolveConfig(multiConfig) };
465
552
  }
553
+ async function togglePermissionMode(multiConfig) {
554
+ const current = getPermissionMode();
555
+ const next = current === "full-access" ? "prompt" : "full-access";
556
+ setPermissionMode(next);
557
+ const updated = { ...multiConfig, permissionMode: next };
558
+ saveMultiConfig(updated);
559
+ if (next === "full-access") {
560
+ console.log(
561
+ chalk3.yellow("\n \u26A1 Full Access \u5DF2\u5F00\u542F") + GRAY2(" \u2014 agent \u5C06\u81EA\u52A8\u6279\u51C6\u6240\u6709\u5DE5\u5177\u64CD\u4F5C\n")
562
+ );
563
+ } else {
564
+ console.log(
565
+ 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")
566
+ );
567
+ }
568
+ return { multiConfig: updated, config: resolveConfig(updated) };
569
+ }
466
570
  async function showSetupFlow(multiConfig) {
467
571
  console.log();
468
572
  try {
469
573
  const providerChoices = Object.entries(PROVIDERS).map(([id, meta]) => {
470
574
  const hasKey = !!multiConfig.providers[id]?.key;
471
- const badge = hasKey ? GREEN("\u2713 \u5DF2\u914D\u7F6E") : YELLOW("\u2717 \u672A\u914D\u7F6E");
575
+ const badge = hasKey ? GREEN2("\u2713 \u5DF2\u914D\u7F6E") : YELLOW2("\u2717 \u672A\u914D\u7F6E");
472
576
  return { name: `${meta.label} ${badge}`, value: id };
473
577
  });
474
578
  const selectedProvider = await select({
475
- message: PURPLE2("\u25C6 \u9009\u62E9 Provider"),
579
+ message: PURPLE3("\u25C6 \u9009\u62E9 Provider"),
476
580
  choices: providerChoices,
477
581
  default: multiConfig.activeProvider
478
582
  });
479
583
  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)");
584
+ const hint = currentKey ? GRAY2("(\u56DE\u8F66\u4FDD\u7559 " + currentKey.slice(0, 6) + "\u2022\u2022\u2022)") : GRAY2("(\u5FC5\u586B)");
481
585
  const rawKey = await input({
482
- message: PURPLE2("\u25C6 API Key ") + hint,
586
+ message: PURPLE3("\u25C6 API Key ") + hint,
483
587
  default: currentKey || void 0
484
588
  });
485
589
  const newKey = rawKey.trim() || currentKey;
@@ -500,14 +604,14 @@ async function showSetupFlow(multiConfig) {
500
604
  saveMultiConfig(updated);
501
605
  const newConfig = resolveConfig(updated);
502
606
  const keyMsg = newKey && newKey !== currentKey ? "\uFF0CAPI Key \u5DF2\u4FDD\u5B58" : "";
503
- console.log(GREEN(`
607
+ console.log(GREEN2(`
504
608
  \u2713 \u5DF2\u5207\u6362\u5230 ${PROVIDERS[selectedProvider].label}${keyMsg}`) + "\n");
505
609
  if (!newConfig.apiKey) {
506
- console.log(YELLOW(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\n"));
610
+ console.log(YELLOW2(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\n"));
507
611
  }
508
612
  return { multiConfig: updated, config: newConfig };
509
613
  } catch {
510
- console.log(GRAY("\n \u53D6\u6D88\n"));
614
+ console.log(GRAY2("\n \u53D6\u6D88\n"));
511
615
  return { multiConfig, config: resolveConfig(multiConfig) };
512
616
  }
513
617
  }
@@ -574,31 +678,33 @@ async function readLineRaw(promptStr) {
574
678
  }
575
679
  function statusLine(config) {
576
680
  const label = PROVIDERS[config.providerName]?.label ?? config.providerName;
577
- return PURPLE2(" \u25C6") + GRAY(` ${label}`) + CYAN(` [${config.model}]`) + GRAY(" \u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n");
681
+ const permMode = getPermissionMode();
682
+ const permBadge = permMode === "full-access" ? chalk3.yellow(" \u26A1 Full Access") : GRAY2(" \u{1F510} \u9ED8\u8BA4\u6743\u9650");
683
+ return PURPLE3(" \u25C6") + GRAY2(` ${label}`) + CYAN(` [${config.model}]`) + permBadge + GRAY2(" \u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n");
578
684
  }
579
685
  async function main() {
580
686
  const args = process.argv.slice(2);
581
687
  if (args[0] === "--help" || args[0] === "-h") {
582
688
  console.log(BANNER);
583
- console.log(PURPLE2(" Usage:"));
584
- console.log(" " + PURPLE2("sharkcode") + GRAY(" \u2014 \u4EA4\u4E92\u6A21\u5F0F\uFF08\u76F4\u63A5\u542F\u52A8\uFF09"));
585
- console.log(" " + PURPLE2("sharkcode") + YELLOW(' "prompt"') + GRAY(" \u2014 \u5355\u6B21\u6267\u884C"));
586
- console.log(GRAY("\n \u4EA4\u4E92\u6A21\u5F0F\u5185\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
689
+ console.log(PURPLE3(" Usage:"));
690
+ console.log(" " + PURPLE3("sharkcode") + GRAY2(" \u2014 \u4EA4\u4E92\u6A21\u5F0F\uFF08\u76F4\u63A5\u542F\u52A8\uFF09"));
691
+ console.log(" " + PURPLE3("sharkcode") + YELLOW2(' "prompt"') + GRAY2(" \u2014 \u5355\u6B21\u6267\u884C"));
692
+ console.log(GRAY2("\n \u4EA4\u4E92\u6A21\u5F0F\u5185\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
587
693
  return;
588
694
  }
589
695
  if (args[0] === "--version" || args[0] === "-v") {
590
- console.log("sharkcode v0.3.4");
696
+ console.log("sharkcode v0.3.6");
591
697
  return;
592
698
  }
593
699
  if (args.length > 0) {
594
700
  const mc = readMultiConfig();
595
701
  const config2 = resolveConfig(mc);
596
702
  if (!config2.apiKey) {
597
- console.error(RED("\u274C \u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C sharkcode \u5E76\u8F93\u5165 / \u914D\u7F6E Provider\u3002"));
703
+ console.error(RED2("\u274C \u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C sharkcode \u5E76\u8F93\u5165 / \u914D\u7F6E Provider\u3002"));
598
704
  process.exit(1);
599
705
  }
600
706
  console.log(
601
- PURPLE2("\n\u{1F988} SharkCode") + GRAY(` | ${PROVIDERS[config2.providerName]?.label ?? config2.providerName} | ${config2.model}
707
+ PURPLE3("\n\u{1F988} SharkCode") + GRAY2(` | ${PROVIDERS[config2.providerName]?.label ?? config2.providerName} | ${config2.model}
602
708
  `)
603
709
  );
604
710
  await runAgent([{ role: "user", content: args.join(" ") }], config2);
@@ -607,6 +713,7 @@ async function main() {
607
713
  console.log(BANNER);
608
714
  let multiConfig = readMultiConfig();
609
715
  let config = resolveConfig(multiConfig);
716
+ setPermissionMode(multiConfig.permissionMode ?? "prompt");
610
717
  try {
611
718
  process.stdin.setRawMode(true);
612
719
  process.stdin.resume();
@@ -615,20 +722,20 @@ async function main() {
615
722
  console.log(statusLine(config));
616
723
  if (!config.apiKey) {
617
724
  console.log(
618
- YELLOW(" \u26A0 \u5C1A\u672A\u914D\u7F6E API Key\u3002") + GRAY("\u8F93\u5165 / \u7136\u540E\u9009\u62E9\u300C\u5207\u6362 / \u914D\u7F6E Provider\u300D\n")
725
+ YELLOW2(" \u26A0 \u5C1A\u672A\u914D\u7F6E API Key\u3002") + GRAY2("\u8F93\u5165 / \u7136\u540E\u9009\u62E9\u300C\u5207\u6362 / \u914D\u7F6E Provider\u300D\n")
619
726
  );
620
727
  }
621
728
  let messages = [];
622
729
  while (true) {
623
- const raw = await readLineRaw(PURPLE2("\n\u25C6 "));
730
+ const raw = await readLineRaw(PURPLE3("\n\u25C6 "));
624
731
  if (raw === null) {
625
- console.log(GRAY("\nBye! \u{1F988}"));
732
+ console.log(GRAY2("\nBye! \u{1F988}"));
626
733
  break;
627
734
  }
628
735
  const trimmed = raw.trim();
629
736
  if (!trimmed) continue;
630
737
  if (trimmed === "exit" || trimmed === "quit") {
631
- console.log(GRAY("Bye! \u{1F988}"));
738
+ console.log(GRAY2("Bye! \u{1F988}"));
632
739
  break;
633
740
  }
634
741
  if (trimmed === "/") {
@@ -659,11 +766,11 @@ async function main() {
659
766
  continue;
660
767
  }
661
768
  if (trimmed.startsWith("/")) {
662
- console.log(GRAY(" \u672A\u77E5\u547D\u4EE4\u3002\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
769
+ console.log(GRAY2(" \u672A\u77E5\u547D\u4EE4\u3002\u8F93\u5165 / \u8C03\u51FA\u6307\u4EE4\u83DC\u5355\n"));
663
770
  continue;
664
771
  }
665
772
  if (!config.apiKey) {
666
- console.log(YELLOW(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\u3002\u8F93\u5165 / \u2192 \u5207\u6362 / \u914D\u7F6E Provider\n"));
773
+ console.log(YELLOW2(" \u26A0 \u8FD8\u672A\u586B\u5199 API Key\u3002\u8F93\u5165 / \u2192 \u5207\u6362 / \u914D\u7F6E Provider\n"));
667
774
  continue;
668
775
  }
669
776
  messages.push({ role: "user", content: trimmed });
@@ -675,7 +782,7 @@ async function main() {
675
782
  } catch {
676
783
  }
677
784
  } catch (err) {
678
- console.error(RED(`
785
+ console.error(RED2(`
679
786
  \u274C ${String(err)}
680
787
  `));
681
788
  messages.pop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sharkcode",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Local First, open-source AI Coding Agent",
5
5
  "type": "module",
6
6
  "bin": {