arona-agent 1.0.6 → 1.0.8

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ARONA Agent
2
2
 
3
- [English](README_en.md) | [简体中文](README.md)
3
+ [English](https://github.com/SRC114514/arona-agent/blob/main/README_en.md)
4
4
 
5
5
  ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)
6
6
 
@@ -17,11 +17,17 @@
17
17
  ```bash
18
18
  npm i -g arona-agent
19
19
 
20
- # 初始化配置文件
21
- arona setup
22
-
23
- # 初始化后可直接启动
20
+ # 首次运行自动进入初始化向导
24
21
  arona
22
+ ```
23
+
24
+ ---
25
+
26
+ ## 扩展指令
27
+
28
+ ```bash
29
+ # 重新初始化(可选)
30
+ arona setup
25
31
 
26
32
  # 更新
27
33
  npm u -g arona-agent
package/README_en.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ARONA Agent
2
2
 
3
- [中文](README.md) | [English](README_en.md)
3
+ [简体中文](README.md)
4
4
 
5
5
  ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)
6
6
 
@@ -15,11 +15,17 @@ A terminal-based conversational AI Agent built on the [Pi SDK](https://www.npmjs
15
15
  ```bash
16
16
  npm i -g arona-agent
17
17
 
18
- # Initialize configuration
19
- arona setup
20
-
21
- # Launch after setup
18
+ # First run auto-starts the setup wizard, then launches ARONA
22
19
  arona
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Optional commands
25
+
26
+ ```bash
27
+ # Re-run setup manually (optional)
28
+ arona setup
23
29
 
24
30
  # Upgrade
25
31
  npm u -g arona-agent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arona-agent",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Terminal AI Agent with desktop pet Arona — eye-tracking pupils, voice cloning, Computer Use, TTS/STT, MCP.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pet/agents.cjs CHANGED
@@ -250,8 +250,8 @@ const KOHARU = {
250
250
  // .json = skel_to_json 导出 + gen_sway 衣摆形变;重新生成顺序:skel_to_json → gen_sway
251
251
  skelFile: "koharu_spr.json",
252
252
  atlasFile: "koharu_spr.atlas.txt",
253
- // bounds 1395×2069(高 96.7%,宽大)→ 1.0 初值,目视后按需调
254
- extraScale: 1,
253
+ // bounds 1395×2069:高≈Arona,但宽(含光环球)超宽 取宽为最小边,身高只占 70% → extraScale 放大到 1.3
254
+ extraScale: 1.3,
255
255
  anims: {
256
256
  idle: "Idle_01",
257
257
  blink: "Eye_Close_01",
package/src/agent.ts CHANGED
@@ -670,7 +670,7 @@ function buildSubSystemPrompt(id: SubAgentId, memoryContent: string): string {
670
670
  - You are one of several desktop-pet characters chatting with Sensei (the user).
671
671
  - After the main agent finishes replying, each enabled sub-agent takes a turn. Keep your reply SHORT (one or two sentences), natural, in-character, and add nothing but your own spoken line.
672
672
  - Do not repeat or summarize the main agent's reply.
673
- - In the conversation history, assistant messages carry a \`Name:\` prefix showing who said them (e.g. "Arona:", "Shiroko:", "Hoshino:"); user inputs are Sensei speaking. When you reply, do NOT add any name prefix.
673
+ - In the conversation history, assistant messages carry a \`Name:\` prefix showing who said them (e.g. "Arona:", "Shiroko:", etc.); user inputs are Sensei speaking. When you reply, do NOT add any name prefix.
674
674
  - Your reply may be read aloud by TTS; keep each sentence under 50 characters/words when possible.
675
675
  - If you have nothing to add, call keep_silent instead of writing filler text.
676
676
 
@@ -1,6 +1,6 @@
1
1
  // Agent 注册表:主 Agent + 子 Agent 的桌宠形象与人格。
2
2
  // 主 Agent(arona | plana)由 /change-agent 单选,持久化到 settings.json#mainAgent。
3
- // 子 Agent(shiroko | hoshino 及日后新增)由 /change-agent 多选,持久化到 settings.json#subAgents。
3
+ // 子 Agent(shiroko | hoshino | hanako | koharu)由 /change-agent 多选,持久化到 settings.json#subAgents。
4
4
  // 桌宠侧对应 pet/agents.cjs(ARONA_AGENT env 选主、ARONA_SUB_AGENTS env 选子窗口),
5
5
  // 人格侧对应 agent.ts 的 buildPrompt* + initSubAgent。
6
6
 
@@ -11,7 +11,7 @@ import { t } from "./locale.ts";
11
11
  export const MAIN_AGENT_IDS = ["arona", "plana"] as const;
12
12
  export type MainAgentId = (typeof MAIN_AGENT_IDS)[number];
13
13
 
14
- export const SUB_AGENT_IDS = ["shiroko", "hoshino"] as const;
14
+ export const SUB_AGENT_IDS = ["shiroko", "hoshino", "hanako", "koharu"] as const;
15
15
  export type SubAgentId = (typeof SUB_AGENT_IDS)[number];
16
16
 
17
17
  export const AGENT_IDS = [...MAIN_AGENT_IDS, ...SUB_AGENT_IDS] as const;
package/src/config.ts CHANGED
@@ -99,7 +99,7 @@ interface Settings {
99
99
  language?: LanguageSetting;
100
100
  // 主 Agent(arona | plana):桌宠形象 + 人格,由 agent_registry.ts 读写
101
101
  mainAgent?: string;
102
- // 启用的子 Agent 列表(shiroko | hoshino),由 agent_registry.ts 读写
102
+ // 启用的子 Agent 列表(见 agent_registry.ts),由 agent_registry.ts 读写
103
103
  subAgents?: string[];
104
104
  ttsEnabled?: boolean;
105
105
  sttEnabled?: boolean;
@@ -277,6 +277,16 @@ function loadConfig(): AronaConfig {
277
277
 
278
278
  export const config = loadConfig();
279
279
 
280
+ /**
281
+ * 重新加载 settings.json 并就地更新 config 单例(首次运行引导 setup 完成后调用)。
282
+ * ESM 模块缓存无法重建模块级 const,只能改对象字段;所有消费方均通过 config.xxx
283
+ * 运行时引用属性,就地覆盖即全局生效(无顶层解构,见 index.ts 引导注释)。
284
+ */
285
+ export function reloadConfig(): AronaConfig {
286
+ Object.assign(config, loadConfig());
287
+ return config;
288
+ }
289
+
280
290
  /**
281
291
  * STT 全局热键键名(pynput 命名,供 repl.ts 注入 ARONA_HOTKEY_KEY):
282
292
  * macOS 右 Cmd(pynput 有 Key.cmd_r),Windows/Linux 右 Ctrl(pynput Key.ctrl_r 三平台皆有效)。
package/src/index.ts CHANGED
@@ -1,17 +1,51 @@
1
+ import { spawn } from "node:child_process";
2
+ import { join } from "node:path";
1
3
  import { initAgent } from "./agent.ts";
2
4
  import { Repl } from "./repl.ts";
3
5
  import { resetConversationFlag, loadSession } from "./memory.ts";
4
6
  import { startPet } from "./pet.ts";
5
- import { config, settingsExist } from "./config.ts";
7
+ import { config, settingsExist, reloadConfig, PROJECT_ROOT } from "./config.ts";
6
8
  import { preloadGptSovitsLocal } from "./tts_provider.ts";
7
9
  import { syncSkillsFromAgentsDir } from "./skills.ts";
8
- import { t } from "./locale.ts";
10
+ import { t, refreshLanguage } from "./locale.ts";
9
11
  import chalk from "chalk";
10
12
 
13
+ /**
14
+ * 首次运行引导:以子进程拉起 setup 向导(stdio inherit 复用当前终端交互)。
15
+ * 传 ARONA_AUTO_SETUP=1 让向导末尾提示"正在启动"而非"运行 arona"。setup 在
16
+ * 独立进程写 settings.json,主进程随后 reloadConfig 即可(ESM 缓存无法重建单例)。
17
+ */
18
+ function runSetupWizard(): Promise<number> {
19
+ const tsxBin = process.platform === "win32"
20
+ ? join(PROJECT_ROOT, "node_modules", ".bin", "tsx.cmd")
21
+ : join(PROJECT_ROOT, "node_modules", ".bin", "tsx");
22
+ return new Promise((resolve) => {
23
+ const child = spawn(tsxBin, [join(PROJECT_ROOT, "src", "setup.ts"), ...process.argv.slice(2)], {
24
+ cwd: process.cwd(),
25
+ stdio: "inherit",
26
+ shell: process.platform === "win32",
27
+ env: { ...process.env, ARONA_AUTO_SETUP: "1" },
28
+ });
29
+ child.on("exit", (code) => resolve(code ?? 0));
30
+ });
31
+ }
32
+
11
33
  async function main() {
34
+ // 首次运行引导:无 settings.json 时直接进入 setup 向导,配置完成后继续 REPL
12
35
  if (!settingsExist()) {
13
- console.log(chalk.yellow(t("未找到配置文件,请运行 arona setup 初始化。", "Config file not found. Run `arona setup` to initialize.")));
14
- process.exit(1);
36
+ console.log(chalk.yellow(t("未找到配置文件,正在进入初始化向导…", "Config file not found. Starting the setup wizard…")));
37
+ const setupCode = await runSetupWizard();
38
+ if (setupCode !== 0) {
39
+ console.log(chalk.yellow(t("初始化已中止,配置未保存。", "Setup aborted, configuration not saved.")));
40
+ process.exit(setupCode);
41
+ }
42
+ if (!settingsExist()) {
43
+ console.log(chalk.yellow(t("配置未保存,无法启动。请重新运行 arona 完成初始化。", "Configuration was not saved. Re-run arona to initialize.")));
44
+ process.exit(1);
45
+ }
46
+ // setup 在子进程内写配置:就地刷新 config 单例与 UI 语言后继续
47
+ reloadConfig();
48
+ refreshLanguage();
15
49
  }
16
50
 
17
51
  if (!config.apiKey) {
package/src/locale.ts CHANGED
@@ -129,3 +129,13 @@ export function getLang(): Language {
129
129
  export function setLang(l: Language): void {
130
130
  lang = l;
131
131
  }
132
+
133
+ /**
134
+ * 按 settings.json 的 language 字段重新定型语言(首次运行引导 setup 完成后调用;
135
+ * 不重新探测系统/环境,仅尊重向导写入的显式配置)。auto/缺失保持现状返回当前值。
136
+ */
137
+ export function refreshLanguage(): Language {
138
+ const setting = readSettingsLanguage();
139
+ if (setting === "zh" || setting === "en") lang = setting;
140
+ return lang;
141
+ }
package/src/repl.ts CHANGED
@@ -52,7 +52,7 @@ export class Repl {
52
52
  );
53
53
  // 回合结束标志:中间段的 play_end 不触发 pet.reset,只有回合结束后才恢复桌宠
54
54
  private turnEnded = false;
55
- // 子 Agent session 集合(shiroko/hoshino;按 settings 启用)
55
+ // 子 Agent session 集合(见 agent_registry.ts;按 settings 启用)
56
56
  private subSessions = new Map<SubAgentId, AgentSession>();
57
57
  // 当前正在发言的 session / agent(中断时 abort 的是它,而不是固定主 session)
58
58
  private activeSession: AgentSession;
package/src/setup.ts CHANGED
@@ -25,7 +25,7 @@ interface Settings {
25
25
  language?: "auto" | "zh" | "en";
26
26
  /** 主 Agent(arona | plana):setup 保存时保留,不能覆盖 /change-agent 的选择 */
27
27
  mainAgent?: string;
28
- /** 子 Agent 列表(shiroko | hoshino):setup 保存时保留,不能覆盖 /change-agent 的选择 */
28
+ /** 子 Agent 列表(见 agent_registry.ts):setup 保存时保留,不能覆盖 /change-agent 的选择 */
29
29
  subAgents?: string[];
30
30
  ttsEnabled?: boolean;
31
31
  sttEnabled?: boolean;
@@ -694,7 +694,12 @@ async function main() {
694
694
 
695
695
  console.log(chalk.green(t(`\n✓ 配置已保存到 ${SETTINGS_FILE}`, `\n✓ Configuration saved to ${SETTINGS_FILE}`)));
696
696
  }
697
- console.log(chalk.cyan(t(" 运行 arona 启动 Agent。\n", " Run arona to start the Agent.\n")));
697
+ if (process.env.ARONA_AUTO_SETUP === "1") {
698
+ // 首次运行自动引导(index.ts spawn 传入):配置完成后主进程直接续跑 REPL
699
+ console.log(chalk.cyan(t(" 配置完成,正在启动 ARONA...\n", " Configuration saved. Starting ARONA...\n")));
700
+ } else {
701
+ console.log(chalk.cyan(t(" 运行 arona 启动 Agent。\n", " Run arona to start the Agent.\n")));
702
+ }
698
703
  } finally {
699
704
  rl.close();
700
705
  }
package/src/voices.ts CHANGED
@@ -37,6 +37,8 @@ export const VOICE_AUDIO: Record<AgentId, string> = {
37
37
  plana: join(PROJECT_ROOT, "assets", "blue-archive", "plana", "voice.mp3"),
38
38
  shiroko: join(PROJECT_ROOT, "assets", "blue-archive", "shiroko", "voice.mp3"),
39
39
  hoshino: join(PROJECT_ROOT, "assets", "blue-archive", "hoshino", "voice.mp3"),
40
+ hanako: join(PROJECT_ROOT, "assets", "blue-archive", "hanako", "voice.mp3"),
41
+ koharu: join(PROJECT_ROOT, "assets", "blue-archive", "koharu", "voice.mp3"),
40
42
  };
41
43
 
42
44
  /**