@ai-setting/roy-agent-cli 1.7.15 → 1.7.17

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.
@@ -1678,7 +1678,7 @@ __export(exports_repl_ink, {
1678
1678
  });
1679
1679
  import * as React2 from "react";
1680
1680
  import { Box as Box3, Text as Text4, Static, useApp, useInput as useInput2 } from "ink";
1681
- import { createLogger as createLogger4 } from "@ai-setting/roy-agent-core";
1681
+ import { createLogger as createLogger5 } from "@ai-setting/roy-agent-core";
1682
1682
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1683
1683
  function nextMessageId() {
1684
1684
  _msgIdCounter += 1;
@@ -2033,7 +2033,7 @@ var init_repl_ink = __esm(() => {
2033
2033
  children: out
2034
2034
  }, undefined, false, undefined, this);
2035
2035
  });
2036
- inkLogger = createLogger4("repl-ink");
2036
+ inkLogger = createLogger5("repl-ink");
2037
2037
  MultilineInput = React2.memo(React2.forwardRef(function MultilineInput2(props, ref) {
2038
2038
  const { onSubmit, placeholder, popupActive, onChange, onEscape } = props;
2039
2039
  const [buffer, setBuffer] = React2.useState("");
@@ -9461,7 +9461,7 @@ class CliQuietModeService {
9461
9461
  // package.json
9462
9462
  var package_default = {
9463
9463
  name: "@ai-setting/roy-agent-cli",
9464
- version: "1.7.15",
9464
+ version: "1.7.17",
9465
9465
  type: "module",
9466
9466
  description: "CLI for roy-agent - Non-interactive command execution",
9467
9467
  main: "./dist/index.js",
@@ -10381,6 +10381,8 @@ __legacyDecorateClassTS([
10381
10381
  import { ContextError as ContextError2, ErrorCodes as ErrorCodes2, getTracerProvider as getTracerProvider2 } from "@ai-setting/roy-agent-core";
10382
10382
 
10383
10383
  // src/commands/shared/task-event-handler.ts
10384
+ import { createLogger as createLogger4 } from "@ai-setting/roy-agent-core";
10385
+ var logger4 = createLogger4("task-event-handler");
10384
10386
  var TASK_EVENTS = {
10385
10387
  CREATED: "task.created",
10386
10388
  UPDATED: "task.updated",
@@ -10407,14 +10409,14 @@ class TaskEventHandler {
10407
10409
  this.handleEvent(event);
10408
10410
  }
10409
10411
  });
10410
- console.log("[TaskEventHandler] Started");
10412
+ logger4.info("[TaskEventHandler] Started");
10411
10413
  return () => this.stop();
10412
10414
  }
10413
10415
  stop() {
10414
10416
  if (this.unsubscribe) {
10415
10417
  this.unsubscribe();
10416
10418
  this.unsubscribe = null;
10417
- console.log("[TaskEventHandler] Stopped");
10419
+ logger4.info("[TaskEventHandler] Stopped");
10418
10420
  }
10419
10421
  }
10420
10422
  handleEvent(event) {
@@ -10439,47 +10441,47 @@ class TaskEventHandler {
10439
10441
  this.logTaskDelegated(payload);
10440
10442
  break;
10441
10443
  default:
10442
- console.log(`[${event.type}]`, payload);
10444
+ logger4.info(`[${event.type}]`, payload);
10443
10445
  }
10444
10446
  }
10445
10447
  logTaskCreated(payload) {
10446
10448
  const task = payload.task;
10447
- console.log(`\uD83D\uDCDD Task created: #${task.id} - ${task.title}`);
10448
- console.log(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}`);
10449
+ logger4.info(`\uD83D\uDCDD Task created: #${task.id} - ${task.title}`);
10450
+ logger4.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}`);
10449
10451
  if (task.project_path) {
10450
- console.log(` Project: ${task.project_path}`);
10452
+ logger4.info(` Project: ${task.project_path}`);
10451
10453
  }
10452
10454
  if (task.context) {
10453
- console.log(` Context: ${task.context}`);
10455
+ logger4.info(` Context: ${task.context}`);
10454
10456
  }
10455
10457
  }
10456
10458
  logTaskUpdated(payload) {
10457
10459
  const task = payload.task;
10458
10460
  const changes = payload.changes;
10459
- console.log(`✏️ Task updated: #${task.id} - ${task.title}`);
10460
- console.log(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}, Progress: ${task.progress}%`);
10461
+ logger4.info(`✏️ Task updated: #${task.id} - ${task.title}`);
10462
+ logger4.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}, Progress: ${task.progress}%`);
10461
10463
  if (changes) {
10462
- console.log(` Changes: ${JSON.stringify(changes)}`);
10464
+ logger4.info(` Changes: ${JSON.stringify(changes)}`);
10463
10465
  }
10464
10466
  }
10465
10467
  logTaskCompleted(payload) {
10466
10468
  const task = payload.task;
10467
- console.log(`✅ Task completed: #${task.id} - ${task.title}`);
10468
- console.log(` Progress: ${task.progress}%, Updated: ${task.updatedAt}`);
10469
+ logger4.info(`✅ Task completed: #${task.id} - ${task.title}`);
10470
+ logger4.info(` Progress: ${task.progress}%, Updated: ${task.updatedAt}`);
10469
10471
  }
10470
10472
  logTaskDeleted(payload) {
10471
- console.log(`\uD83D\uDDD1️ Task deleted: #${payload.taskId}`);
10473
+ logger4.info(`\uD83D\uDDD1️ Task deleted: #${payload.taskId}`);
10472
10474
  }
10473
10475
  logOperationAdded(payload) {
10474
10476
  const op = payload.operation;
10475
- console.log(`\uD83D\uDCCB Operation added to task #${payload.taskId}:`);
10476
- console.log(` [${op.milestoneType}] ${op.milestoneTitle}`);
10477
- console.log(` Session: ${op.sessionId}`);
10477
+ logger4.info(`\uD83D\uDCCB Operation added to task #${payload.taskId}:`);
10478
+ logger4.info(` [${op.milestoneType}] ${op.milestoneTitle}`);
10479
+ logger4.info(` Session: ${op.sessionId}`);
10478
10480
  }
10479
10481
  logTaskDelegated(payload) {
10480
- console.log(`\uD83D\uDE80 Task delegated: #${payload.taskId}`);
10481
- console.log(` Background: ${payload.backgroundTaskId}, Type: ${payload.subagentType}`);
10482
- console.log(` ${payload.description}`);
10482
+ logger4.info(`\uD83D\uDE80 Task delegated: #${payload.taskId}`);
10483
+ logger4.info(` Background: ${payload.backgroundTaskId}, Type: ${payload.subagentType}`);
10484
+ logger4.info(` ${payload.description}`);
10483
10485
  }
10484
10486
  }
10485
10487
 
@@ -10557,9 +10559,9 @@ async function runActShutdownCleanup(deps) {
10557
10559
  envService,
10558
10560
  shouldDisposeEnvService,
10559
10561
  output,
10560
- logger: logger4
10562
+ logger: logger5
10561
10563
  } = deps;
10562
- const log = logger4 ?? {
10564
+ const log = logger5 ?? {
10563
10565
  debug: () => {},
10564
10566
  warn: (msg) => console.warn(msg)
10565
10567
  };
@@ -11703,7 +11705,7 @@ function hasActiveDescendants(env, parentSessionId) {
11703
11705
 
11704
11706
  // src/commands/interactive.ts
11705
11707
  init_stream_output_service();
11706
- import { createLogger as createLogger5, getTracerProvider as getTracerProvider3 } from "@ai-setting/roy-agent-core";
11708
+ import { createLogger as createLogger6, getTracerProvider as getTracerProvider3 } from "@ai-setting/roy-agent-core";
11707
11709
 
11708
11710
  // src/commands/input-handler.ts
11709
11711
  class InputHandler {
@@ -12028,7 +12030,7 @@ async function shutdownInteractiveSteps(deps) {
12028
12030
  envService,
12029
12031
  shouldDisposeEnvService,
12030
12032
  output,
12031
- logger: logger4,
12033
+ logger: logger5,
12032
12034
  console: consoleLike
12033
12035
  } = deps;
12034
12036
  const log = (msg) => consoleLike?.log?.(msg) ?? console.log(msg);
@@ -12041,7 +12043,7 @@ async function shutdownInteractiveSteps(deps) {
12041
12043
  await memoryPluginDispose();
12042
12044
  log("\uD83D\uDCBE 记忆已保存完毕");
12043
12045
  } catch (err) {
12044
- logger4.warn(`[Shutdown] MemoryPlugin dispose failed: ${err}`);
12046
+ logger5.warn(`[Shutdown] MemoryPlugin dispose failed: ${err}`);
12045
12047
  output.warn(`⚠️ 记忆保存失败: ${err}`);
12046
12048
  }
12047
12049
  }
@@ -12049,25 +12051,25 @@ async function shutdownInteractiveSteps(deps) {
12049
12051
  try {
12050
12052
  await lspManagerDispose();
12051
12053
  } catch (err) {
12052
- logger4.warn(`[Shutdown] LSP Manager dispose failed: ${err}`);
12054
+ logger5.warn(`[Shutdown] LSP Manager dispose failed: ${err}`);
12053
12055
  }
12054
12056
  }
12055
12057
  if (pluginAdapterDispose) {
12056
12058
  try {
12057
12059
  await pluginAdapterDispose();
12058
12060
  } catch (err) {
12059
- logger4.warn(`[Shutdown] PluginAdapter dispose failed: ${err}`);
12061
+ logger5.warn(`[Shutdown] PluginAdapter dispose failed: ${err}`);
12060
12062
  }
12061
12063
  }
12062
12064
  try {
12063
12065
  eventHandler.stop();
12064
12066
  } catch (err) {
12065
- logger4.warn(`[Shutdown] EventHandler.stop failed: ${err}`);
12067
+ logger5.warn(`[Shutdown] EventHandler.stop failed: ${err}`);
12066
12068
  }
12067
12069
  try {
12068
12070
  queryExecutor.dispose();
12069
12071
  } catch (err) {
12070
- logger4.warn(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
12072
+ logger5.warn(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
12071
12073
  }
12072
12074
  try {
12073
12075
  const eventSourceComponent = env.getComponent("event-source");
@@ -12076,7 +12078,7 @@ async function shutdownInteractiveSteps(deps) {
12076
12078
  if (sources && sources.length > 0) {
12077
12079
  for (const source of sources) {
12078
12080
  const status = eventSourceComponent.getStatus?.(source.id);
12079
- logger4.debug(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
12081
+ logger5.debug(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
12080
12082
  if (status !== "stopped" && status !== "created") {
12081
12083
  try {
12082
12084
  await eventSourceComponent.stopSource(source.id);
@@ -12089,20 +12091,20 @@ async function shutdownInteractiveSteps(deps) {
12089
12091
  }
12090
12092
  }
12091
12093
  } catch (err) {
12092
- logger4.warn(`[Shutdown] EventSource cleanup failed: ${err}`);
12094
+ logger5.warn(`[Shutdown] EventSource cleanup failed: ${err}`);
12093
12095
  }
12094
12096
  if (shouldDisposeEnvService) {
12095
12097
  try {
12096
12098
  await envService.dispose();
12097
12099
  } catch (err) {
12098
- logger4.warn(`[Shutdown] envService.dispose failed: ${err}`);
12100
+ logger5.warn(`[Shutdown] envService.dispose failed: ${err}`);
12099
12101
  }
12100
12102
  }
12101
12103
  try {
12102
12104
  await TempFileManager2.getInstance().cleanupAll();
12103
- logger4.debug("[Shutdown] TempFileManager cleaned up");
12105
+ logger5.debug("[Shutdown] TempFileManager cleaned up");
12104
12106
  } catch (err) {
12105
- logger4.warn(`[Shutdown] TempFileManager cleanup failed: ${err}`);
12107
+ logger5.warn(`[Shutdown] TempFileManager cleanup failed: ${err}`);
12106
12108
  }
12107
12109
  }
12108
12110
 
@@ -12292,7 +12294,7 @@ var COLOR_BY_STATUS = {
12292
12294
  busy: COLORS.accent
12293
12295
  };
12294
12296
  // src/commands/interactive.ts
12295
- var logger4 = createLogger5("cli:interactive");
12297
+ var logger5 = createLogger6("cli:interactive");
12296
12298
  var USER_PROMPT = COLORS.accent("❯ ");
12297
12299
 
12298
12300
  class REPL {
@@ -12484,10 +12486,10 @@ ${COLORS.system("[正在中断...]")}`);
12484
12486
  const agentComponent = this.env.getComponent("agent");
12485
12487
  if (agentComponent?.abortAll) {
12486
12488
  agentComponent.abortAll();
12487
- logger4.debug("[/abort] AgentComponent.abortAll() called");
12489
+ logger5.debug("[/abort] AgentComponent.abortAll() called");
12488
12490
  } else if (agentComponent?.abort) {
12489
12491
  agentComponent.abort("default");
12490
- logger4.debug("[/abort] AgentComponent.abort('default') called (fallback)");
12492
+ logger5.debug("[/abort] AgentComponent.abort('default') called (fallback)");
12491
12493
  }
12492
12494
  }
12493
12495
  abortStream();
@@ -12582,7 +12584,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12582
12584
  try {
12583
12585
  await this.options.onAfterExecute(this.lastUsage);
12584
12586
  } catch (hookError) {
12585
- logger4.warn("onAfterExecute hook failed (ink path)", { error: String(hookError) });
12587
+ logger5.warn("onAfterExecute hook failed (ink path)", { error: String(hookError) });
12586
12588
  }
12587
12589
  }
12588
12590
  } catch (err) {
@@ -12602,7 +12604,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12602
12604
  await this.shutdown();
12603
12605
  resolve();
12604
12606
  }).catch(async (err) => {
12605
- logger4.error("ink REPL render failed", { error: String(err) });
12607
+ logger5.error("ink REPL render failed", { error: String(err) });
12606
12608
  await this.shutdown();
12607
12609
  resolve();
12608
12610
  });
@@ -12659,7 +12661,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12659
12661
  }
12660
12662
  if (key.name === "escape") {
12661
12663
  this.handleEscKey().catch((err) => {
12662
- logger4.warn(`[Esc] handleEscKey failed: ${err}`);
12664
+ logger5.warn(`[Esc] handleEscKey failed: ${err}`);
12663
12665
  });
12664
12666
  }
12665
12667
  };
@@ -12854,7 +12856,7 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
12854
12856
  try {
12855
12857
  await this.options.onAfterExecute(this.lastUsage);
12856
12858
  } catch (hookError) {
12857
- logger4.warn("onAfterExecute hook failed", { error: String(hookError) });
12859
+ logger5.warn("onAfterExecute hook failed", { error: String(hookError) });
12858
12860
  }
12859
12861
  }
12860
12862
  } catch (error) {
@@ -13017,12 +13019,12 @@ ${COLORS.error("❌ 执行失败: " + error)}
13017
13019
  }
13018
13020
  async handleEscKey() {
13019
13021
  if (this.isShuttingDown) {
13020
- logger4.debug("[Esc] handler entered (isShuttingDown=true) → early return");
13022
+ logger5.debug("[Esc] handler entered (isShuttingDown=true) → early return");
13021
13023
  return;
13022
13024
  }
13023
13025
  const mainSessionIdEarly = this.options.sessionId;
13024
13026
  const hasActiveDescendant = mainSessionIdEarly ? hasActiveDescendants(this.env, mainSessionIdEarly) : false;
13025
- logger4.debug(`[Esc] handler entered: isExecuting=${this.isExecuting} hasActiveDescendant=${hasActiveDescendant} lastEscPressTime=${this.lastEscPressTime}`);
13027
+ logger5.debug(`[Esc] handler entered: isExecuting=${this.isExecuting} hasActiveDescendant=${hasActiveDescendant} lastEscPressTime=${this.lastEscPressTime}`);
13026
13028
  const now = Date.now();
13027
13029
  const isExecuting = this.isExecuting;
13028
13030
  const canCascade = isExecuting || hasActiveDescendant;
@@ -13031,17 +13033,17 @@ ${COLORS.error("❌ 执行失败: " + error)}
13031
13033
  this.lastEscPressTime = now;
13032
13034
  }
13033
13035
  if (!canCascade) {
13034
- logger4.debug("[Esc] idle no-op: isExecuting=false, no active descendant");
13036
+ logger5.debug("[Esc] idle no-op: isExecuting=false, no active descendant");
13035
13037
  return;
13036
13038
  }
13037
13039
  if (this.env) {
13038
13040
  const agentComponent = this.env.getComponent("agent");
13039
13041
  if (agentComponent?.abortAll) {
13040
13042
  agentComponent.abortAll();
13041
- logger4.debug("[Esc] AgentComponent.abortAll() called");
13043
+ logger5.debug("[Esc] AgentComponent.abortAll() called");
13042
13044
  } else if (agentComponent?.abort) {
13043
13045
  agentComponent.abort("default");
13044
- logger4.debug("[Esc] AgentComponent.abort('default') called (fallback)");
13046
+ logger5.debug("[Esc] AgentComponent.abort('default') called (fallback)");
13045
13047
  }
13046
13048
  }
13047
13049
  abortStream();
@@ -13049,7 +13051,7 @@ ${COLORS.error("❌ 执行失败: " + error)}
13049
13051
  try {
13050
13052
  this.inkApi.finishAssistantStream();
13051
13053
  } catch (err) {
13052
- logger4.warn("[Esc] finishAssistantStream failed", { error: String(err) });
13054
+ logger5.warn("[Esc] finishAssistantStream failed", { error: String(err) });
13053
13055
  }
13054
13056
  }
13055
13057
  const mainSessionId = this.options.sessionId;
@@ -13062,9 +13064,9 @@ ${COLORS.error("❌ 执行失败: " + error)}
13062
13064
  timer = setTimeout(() => reject(new Error("cascade timeout 5s")), 5000);
13063
13065
  })
13064
13066
  ]);
13065
- logger4.info(`[Esc] cascade stop force=${result.force} tasks=${result.stoppedTaskIds.length} workflows=${result.stoppedWorkflowSessionIds.length} errors=${result.errors.length}`);
13067
+ logger5.info(`[Esc] cascade stop force=${result.force} tasks=${result.stoppedTaskIds.length} workflows=${result.stoppedWorkflowSessionIds.length} errors=${result.errors.length}`);
13066
13068
  } catch (err) {
13067
- logger4.warn(`[Esc] cascade stop failed: ${err}`);
13069
+ logger5.warn(`[Esc] cascade stop failed: ${err}`);
13068
13070
  } finally {
13069
13071
  if (timer !== undefined)
13070
13072
  clearTimeout(timer);
@@ -13446,7 +13448,7 @@ function createInteractiveCommand(externalEnvService) {
13446
13448
  envService,
13447
13449
  shouldDisposeEnvService,
13448
13450
  output,
13449
- logger: logger4,
13451
+ logger: logger5,
13450
13452
  console
13451
13453
  });
13452
13454
  }
@@ -25493,24 +25495,106 @@ var LspCommand = {
25493
25495
 
25494
25496
  // src/commands/install/index.ts
25495
25497
  import { spawnSync } from "node:child_process";
25496
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, rmSync } from "node:fs";
25497
- import { join as join5, resolve } from "node:path";
25498
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync, mkdirSync, rmSync as rmSync2 } from "node:fs";
25499
+ import { join as join6, resolve } from "node:path";
25498
25500
  import { homedir as homedir4 } from "node:os";
25501
+
25502
+ // src/commands/install/cleanup-stale-plugin-copies.ts
25503
+ import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync, cpSync } from "node:fs";
25504
+ import { join as join5 } from "node:path";
25505
+ import { homedir as nodeHomedir, tmpdir as nodeTmpdir } from "node:os";
25506
+ function cleanupStalePluginCopies(packageName, options) {
25507
+ const HOME = options.homedir ?? nodeHomedir();
25508
+ const paths = options.localNodeModulesPaths ?? [
25509
+ join5(HOME, "node_modules"),
25510
+ join5(HOME, ".roy-agent", "node_modules")
25511
+ ];
25512
+ const backupRoot = options.backupDir ?? nodeTmpdir();
25513
+ const result = {
25514
+ cleaned: [],
25515
+ skipped: [],
25516
+ backups: []
25517
+ };
25518
+ if (!options.globalVersion) {
25519
+ for (const p of paths) {
25520
+ const candidate = join5(p, packageName);
25521
+ result.skipped.push({ path: candidate, reason: "no-global-version" });
25522
+ }
25523
+ return result;
25524
+ }
25525
+ for (const nmPath of paths) {
25526
+ const localPkgDir = join5(nmPath, packageName);
25527
+ const localPkgJson = join5(localPkgDir, "package.json");
25528
+ if (!existsSync4(localPkgJson)) {
25529
+ result.skipped.push({ path: localPkgDir, reason: "no-local-copy" });
25530
+ continue;
25531
+ }
25532
+ let localVersion = null;
25533
+ try {
25534
+ const pkg = JSON.parse(readFileSync3(localPkgJson, "utf-8"));
25535
+ localVersion = typeof pkg.version === "string" ? pkg.version : null;
25536
+ } catch {
25537
+ localVersion = null;
25538
+ }
25539
+ const shouldClean = localVersion === null || compareVersions(localVersion, options.globalVersion) < 0;
25540
+ if (!shouldClean) {
25541
+ result.skipped.push({ path: localPkgDir, reason: "local-equal-or-newer" });
25542
+ continue;
25543
+ }
25544
+ let backupPath = null;
25545
+ try {
25546
+ const safeName = packageName.replace(/@/g, "").replace(/[^a-zA-Z0-9._/-]/g, "-");
25547
+ const safeLocalVersion = (localVersion ?? "unknown").replace(/[^a-zA-Z0-9._-]/g, "-");
25548
+ const timestamp = Date.now();
25549
+ backupPath = join5(backupRoot, `${safeName}-${safeLocalVersion}-backup-${timestamp}`);
25550
+ cpSync(localPkgDir, backupPath, { recursive: true });
25551
+ result.backups.push({ originalPath: localPkgDir, backupPath });
25552
+ } catch (err) {
25553
+ backupPath = null;
25554
+ console.warn(`⚠️ Failed to backup stale copy at '${localPkgDir}': ${err}`);
25555
+ }
25556
+ try {
25557
+ rmSync(localPkgDir, { recursive: true, force: true });
25558
+ result.cleaned.push(localPkgDir);
25559
+ } catch (err) {
25560
+ console.warn(`⚠️ Failed to remove stale copy at '${localPkgDir}': ${err}`);
25561
+ result.skipped.push({ path: localPkgDir, reason: "cleanup-failed" });
25562
+ if (backupPath) {
25563
+ console.warn(` ↪ Backup preserved at '${backupPath}' for manual recovery`);
25564
+ }
25565
+ }
25566
+ }
25567
+ return result;
25568
+ }
25569
+ function compareVersions(a, b) {
25570
+ const pa = a.split(".").map((s) => Number.parseInt(s, 10));
25571
+ const pb = b.split(".").map((s) => Number.parseInt(s, 10));
25572
+ for (let i = 0;i < 3; i++) {
25573
+ const na = Number.isFinite(pa[i]) ? pa[i] : 0;
25574
+ const nb = Number.isFinite(pb[i]) ? pb[i] : 0;
25575
+ const diff = na - nb;
25576
+ if (diff !== 0)
25577
+ return diff;
25578
+ }
25579
+ return 0;
25580
+ }
25581
+
25582
+ // src/commands/install/index.ts
25499
25583
  function getConfigDir(scope) {
25500
- return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
25584
+ return scope === "global" ? join6(homedir4(), ".roy-agent") : join6(process.cwd(), ".roy");
25501
25585
  }
25502
25586
  function detectDefaultScope() {
25503
- const projectDir = join5(process.cwd(), ".roy");
25504
- return existsSync4(projectDir) ? "project" : "global";
25587
+ const projectDir = join6(process.cwd(), ".roy");
25588
+ return existsSync5(projectDir) ? "project" : "global";
25505
25589
  }
25506
25590
  function getConfigPath(scope) {
25507
- return join5(getConfigDir(scope), "plugins.json");
25591
+ return join6(getConfigDir(scope), "plugins.json");
25508
25592
  }
25509
25593
  function loadPlugins(scope) {
25510
25594
  const configPath = getConfigPath(scope);
25511
25595
  try {
25512
- if (existsSync4(configPath)) {
25513
- const raw = readFileSync3(configPath, "utf-8");
25596
+ if (existsSync5(configPath)) {
25597
+ const raw = readFileSync4(configPath, "utf-8");
25514
25598
  const config = JSON.parse(raw);
25515
25599
  return config.plugins ?? [];
25516
25600
  }
@@ -25520,7 +25604,7 @@ function loadPlugins(scope) {
25520
25604
  function savePlugins(plugins, scope) {
25521
25605
  const configDir = getConfigDir(scope);
25522
25606
  const configPath = getConfigPath(scope);
25523
- if (!existsSync4(configDir)) {
25607
+ if (!existsSync5(configDir)) {
25524
25608
  mkdirSync(configDir, { recursive: true });
25525
25609
  }
25526
25610
  const config = { plugins };
@@ -25536,10 +25620,10 @@ function stripVersionSpec(packageName) {
25536
25620
  function readPackageInfo(packageName) {
25537
25621
  const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
25538
25622
  if (packageName.startsWith("/") || packageName.startsWith(".")) {
25539
- const localPkgPath = join5(packageName, "package.json");
25540
- if (existsSync4(localPkgPath)) {
25623
+ const localPkgPath = join6(packageName, "package.json");
25624
+ if (existsSync5(localPkgPath)) {
25541
25625
  try {
25542
- const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
25626
+ const pkg = JSON.parse(readFileSync4(localPkgPath, "utf-8"));
25543
25627
  return {
25544
25628
  version: pkg.version ?? "0.0.0",
25545
25629
  name: pkg.name ?? packageName,
@@ -25551,19 +25635,19 @@ function readPackageInfo(packageName) {
25551
25635
  }
25552
25636
  }
25553
25637
  const searchPaths = [
25554
- join5(process.cwd(), "node_modules", bareName, "package.json"),
25638
+ join6(process.cwd(), "node_modules", bareName, "package.json"),
25555
25639
  resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
25556
- join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
25640
+ join6(process.cwd(), ".roy", "plugins", bareName, "package.json"),
25557
25641
  ...(() => {
25558
25642
  const globalRoot = getNpmGlobalRoot();
25559
- return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
25643
+ return globalRoot ? [join6(globalRoot, bareName, "package.json")] : [];
25560
25644
  })(),
25561
- join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json")
25645
+ join6(homedir4(), ".roy-agent", "node_modules", bareName, "package.json")
25562
25646
  ];
25563
25647
  for (const pkgPath of searchPaths) {
25564
25648
  try {
25565
- if (existsSync4(pkgPath)) {
25566
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
25649
+ if (existsSync5(pkgPath)) {
25650
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
25567
25651
  return {
25568
25652
  version: pkg.version ?? "0.0.0",
25569
25653
  name: pkg.name ?? bareName,
@@ -25585,19 +25669,6 @@ function getNpmGlobalRoot() {
25585
25669
  }
25586
25670
  return null;
25587
25671
  }
25588
- function cleanupStaleCpCopy(packageName) {
25589
- const cpDir = join5(homedir4(), ".roy-agent", "node_modules", packageName);
25590
- if (!existsSync4(cpDir)) {
25591
- return false;
25592
- }
25593
- try {
25594
- rmSync(cpDir, { recursive: true, force: true });
25595
- return true;
25596
- } catch (err) {
25597
- console.warn(`⚠️ Failed to clean stale cp copy at '${cpDir}': ${err}`);
25598
- return false;
25599
- }
25600
- }
25601
25672
  async function verifyInstalledVersion(packageName, declaredVersion) {
25602
25673
  const actual = readPackageInfo(packageName);
25603
25674
  if (!actual || !actual.version) {
@@ -25609,15 +25680,15 @@ async function verifyInstalledVersion(packageName, declaredVersion) {
25609
25680
  return { ok: true, actualVersion: actual.version };
25610
25681
  }
25611
25682
  function getPackageManagerCommand() {
25612
- if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
25613
- if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
25683
+ if (existsSync5(join6(process.cwd(), "pnpm-lock.yaml"))) {
25684
+ if (existsSync5(join6(process.cwd(), "pnpm-workspace.yaml"))) {
25614
25685
  return "pnpm -w";
25615
25686
  }
25616
25687
  return "pnpm";
25617
25688
  }
25618
- if (existsSync4(join5(process.cwd(), "yarn.lock")))
25689
+ if (existsSync5(join6(process.cwd(), "yarn.lock")))
25619
25690
  return "yarn";
25620
- if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
25691
+ if (existsSync5(join6(process.cwd(), "bun.lock")) || existsSync5(join6(process.cwd(), "bun.lockb")))
25621
25692
  return "bun";
25622
25693
  return "npm";
25623
25694
  }
@@ -25656,14 +25727,14 @@ var InstallPackageCommand = {
25656
25727
  }
25657
25728
  resolvedName = info2.name;
25658
25729
  const srcDir = resolve(packageName);
25659
- if (!existsSync4(srcDir)) {
25730
+ if (!existsSync5(srcDir)) {
25660
25731
  console.error(`
25661
25732
  ❌ Local path '${srcDir}' does not exist.
25662
25733
  `);
25663
25734
  process.exit(1);
25664
25735
  }
25665
- const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
25666
- if (!existsSync4(pluginDir)) {
25736
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", resolvedName);
25737
+ if (!existsSync5(pluginDir)) {
25667
25738
  mkdirSync(pluginDir, { recursive: true });
25668
25739
  }
25669
25740
  const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
@@ -25698,12 +25769,12 @@ var InstallPackageCommand = {
25698
25769
  process.exit(1);
25699
25770
  }
25700
25771
  resolvedName = info2.name;
25701
- const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
25702
- if (!existsSync4(pluginDir)) {
25772
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", resolvedName);
25773
+ if (!existsSync5(pluginDir)) {
25703
25774
  mkdirSync(pluginDir, { recursive: true });
25704
25775
  }
25705
- const nmPath = join5(process.cwd(), "node_modules", packageName);
25706
- if (existsSync4(nmPath)) {
25776
+ const nmPath = join6(process.cwd(), "node_modules", packageName);
25777
+ if (existsSync5(nmPath)) {
25707
25778
  spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
25708
25779
  }
25709
25780
  }
@@ -25723,11 +25794,24 @@ var InstallPackageCommand = {
25723
25794
  }
25724
25795
  const tmpInfo = readPackageInfo(packageName);
25725
25796
  if (tmpInfo) {
25726
- const cleaned = cleanupStaleCpCopy(tmpInfo.name);
25727
- if (cleaned) {
25797
+ const cleanupResult = cleanupStalePluginCopies(tmpInfo.name, {
25798
+ globalVersion: tmpInfo.version,
25799
+ homedir: homedir4()
25800
+ });
25801
+ if (cleanupResult.cleaned.length > 0) {
25728
25802
  console.log(`
25729
- \uD83E\uDDF9 Cleaned stale cp copy: ~/.roy-agent/node_modules/${tmpInfo.name}
25730
- `);
25803
+ \uD83E\uDDF9 Cleaned stale plugin copies:`);
25804
+ for (const path9 of cleanupResult.cleaned) {
25805
+ console.log(` - ${path9}`);
25806
+ }
25807
+ if (cleanupResult.backups.length > 0) {
25808
+ console.log(`
25809
+ \uD83D\uDCE6 Backups (for manual recovery):`);
25810
+ for (const b of cleanupResult.backups) {
25811
+ console.log(` ${b.originalPath} → ${b.backupPath}`);
25812
+ }
25813
+ }
25814
+ console.log();
25731
25815
  }
25732
25816
  }
25733
25817
  }
@@ -25852,8 +25936,8 @@ var InstallRemoveCommand = {
25852
25936
  \uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
25853
25937
  `);
25854
25938
  if (scope === "project") {
25855
- const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
25856
- if (existsSync4(pluginDir)) {
25939
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", plugin.packageName);
25940
+ if (existsSync5(pluginDir)) {
25857
25941
  spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
25858
25942
  console.log(` Removed plugin directory: ${pluginDir}`);
25859
25943
  }
@@ -25868,8 +25952,8 @@ var InstallRemoveCommand = {
25868
25952
  `);
25869
25953
  process.exit(result.status ?? 1);
25870
25954
  }
25871
- const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
25872
- if (existsSync4(globalNm)) {
25955
+ const globalNm = join6(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
25956
+ if (existsSync5(globalNm)) {
25873
25957
  spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
25874
25958
  }
25875
25959
  }
package/dist/index.js CHANGED
@@ -1677,7 +1677,7 @@ __export(exports_repl_ink, {
1677
1677
  });
1678
1678
  import * as React2 from "react";
1679
1679
  import { Box as Box3, Text as Text4, Static, useApp, useInput as useInput2 } from "ink";
1680
- import { createLogger as createLogger4 } from "@ai-setting/roy-agent-core";
1680
+ import { createLogger as createLogger5 } from "@ai-setting/roy-agent-core";
1681
1681
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1682
1682
  function nextMessageId() {
1683
1683
  _msgIdCounter += 1;
@@ -2032,7 +2032,7 @@ var init_repl_ink = __esm(() => {
2032
2032
  children: out
2033
2033
  }, undefined, false, undefined, this);
2034
2034
  });
2035
- inkLogger = createLogger4("repl-ink");
2035
+ inkLogger = createLogger5("repl-ink");
2036
2036
  MultilineInput = React2.memo(React2.forwardRef(function MultilineInput2(props, ref) {
2037
2037
  const { onSubmit, placeholder, popupActive, onChange, onEscape } = props;
2038
2038
  const [buffer, setBuffer] = React2.useState("");
@@ -9460,7 +9460,7 @@ class CliQuietModeService {
9460
9460
  // package.json
9461
9461
  var package_default = {
9462
9462
  name: "@ai-setting/roy-agent-cli",
9463
- version: "1.7.15",
9463
+ version: "1.7.17",
9464
9464
  type: "module",
9465
9465
  description: "CLI for roy-agent - Non-interactive command execution",
9466
9466
  main: "./dist/index.js",
@@ -10380,6 +10380,8 @@ __legacyDecorateClassTS([
10380
10380
  import { ContextError as ContextError2, ErrorCodes as ErrorCodes2, getTracerProvider as getTracerProvider2 } from "@ai-setting/roy-agent-core";
10381
10381
 
10382
10382
  // src/commands/shared/task-event-handler.ts
10383
+ import { createLogger as createLogger4 } from "@ai-setting/roy-agent-core";
10384
+ var logger4 = createLogger4("task-event-handler");
10383
10385
  var TASK_EVENTS = {
10384
10386
  CREATED: "task.created",
10385
10387
  UPDATED: "task.updated",
@@ -10406,14 +10408,14 @@ class TaskEventHandler {
10406
10408
  this.handleEvent(event);
10407
10409
  }
10408
10410
  });
10409
- console.log("[TaskEventHandler] Started");
10411
+ logger4.info("[TaskEventHandler] Started");
10410
10412
  return () => this.stop();
10411
10413
  }
10412
10414
  stop() {
10413
10415
  if (this.unsubscribe) {
10414
10416
  this.unsubscribe();
10415
10417
  this.unsubscribe = null;
10416
- console.log("[TaskEventHandler] Stopped");
10418
+ logger4.info("[TaskEventHandler] Stopped");
10417
10419
  }
10418
10420
  }
10419
10421
  handleEvent(event) {
@@ -10438,47 +10440,47 @@ class TaskEventHandler {
10438
10440
  this.logTaskDelegated(payload);
10439
10441
  break;
10440
10442
  default:
10441
- console.log(`[${event.type}]`, payload);
10443
+ logger4.info(`[${event.type}]`, payload);
10442
10444
  }
10443
10445
  }
10444
10446
  logTaskCreated(payload) {
10445
10447
  const task = payload.task;
10446
- console.log(`\uD83D\uDCDD Task created: #${task.id} - ${task.title}`);
10447
- console.log(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}`);
10448
+ logger4.info(`\uD83D\uDCDD Task created: #${task.id} - ${task.title}`);
10449
+ logger4.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}`);
10448
10450
  if (task.project_path) {
10449
- console.log(` Project: ${task.project_path}`);
10451
+ logger4.info(` Project: ${task.project_path}`);
10450
10452
  }
10451
10453
  if (task.context) {
10452
- console.log(` Context: ${task.context}`);
10454
+ logger4.info(` Context: ${task.context}`);
10453
10455
  }
10454
10456
  }
10455
10457
  logTaskUpdated(payload) {
10456
10458
  const task = payload.task;
10457
10459
  const changes = payload.changes;
10458
- console.log(`✏️ Task updated: #${task.id} - ${task.title}`);
10459
- console.log(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}, Progress: ${task.progress}%`);
10460
+ logger4.info(`✏️ Task updated: #${task.id} - ${task.title}`);
10461
+ logger4.info(` Status: ${task.status}, Priority: ${task.priority}, Type: ${task.type || "normal"}, Progress: ${task.progress}%`);
10460
10462
  if (changes) {
10461
- console.log(` Changes: ${JSON.stringify(changes)}`);
10463
+ logger4.info(` Changes: ${JSON.stringify(changes)}`);
10462
10464
  }
10463
10465
  }
10464
10466
  logTaskCompleted(payload) {
10465
10467
  const task = payload.task;
10466
- console.log(`✅ Task completed: #${task.id} - ${task.title}`);
10467
- console.log(` Progress: ${task.progress}%, Updated: ${task.updatedAt}`);
10468
+ logger4.info(`✅ Task completed: #${task.id} - ${task.title}`);
10469
+ logger4.info(` Progress: ${task.progress}%, Updated: ${task.updatedAt}`);
10468
10470
  }
10469
10471
  logTaskDeleted(payload) {
10470
- console.log(`\uD83D\uDDD1️ Task deleted: #${payload.taskId}`);
10472
+ logger4.info(`\uD83D\uDDD1️ Task deleted: #${payload.taskId}`);
10471
10473
  }
10472
10474
  logOperationAdded(payload) {
10473
10475
  const op = payload.operation;
10474
- console.log(`\uD83D\uDCCB Operation added to task #${payload.taskId}:`);
10475
- console.log(` [${op.milestoneType}] ${op.milestoneTitle}`);
10476
- console.log(` Session: ${op.sessionId}`);
10476
+ logger4.info(`\uD83D\uDCCB Operation added to task #${payload.taskId}:`);
10477
+ logger4.info(` [${op.milestoneType}] ${op.milestoneTitle}`);
10478
+ logger4.info(` Session: ${op.sessionId}`);
10477
10479
  }
10478
10480
  logTaskDelegated(payload) {
10479
- console.log(`\uD83D\uDE80 Task delegated: #${payload.taskId}`);
10480
- console.log(` Background: ${payload.backgroundTaskId}, Type: ${payload.subagentType}`);
10481
- console.log(` ${payload.description}`);
10481
+ logger4.info(`\uD83D\uDE80 Task delegated: #${payload.taskId}`);
10482
+ logger4.info(` Background: ${payload.backgroundTaskId}, Type: ${payload.subagentType}`);
10483
+ logger4.info(` ${payload.description}`);
10482
10484
  }
10483
10485
  }
10484
10486
 
@@ -10556,9 +10558,9 @@ async function runActShutdownCleanup(deps) {
10556
10558
  envService,
10557
10559
  shouldDisposeEnvService,
10558
10560
  output,
10559
- logger: logger4
10561
+ logger: logger5
10560
10562
  } = deps;
10561
- const log = logger4 ?? {
10563
+ const log = logger5 ?? {
10562
10564
  debug: () => {},
10563
10565
  warn: (msg) => console.warn(msg)
10564
10566
  };
@@ -11702,7 +11704,7 @@ function hasActiveDescendants(env, parentSessionId) {
11702
11704
 
11703
11705
  // src/commands/interactive.ts
11704
11706
  init_stream_output_service();
11705
- import { createLogger as createLogger5, getTracerProvider as getTracerProvider3 } from "@ai-setting/roy-agent-core";
11707
+ import { createLogger as createLogger6, getTracerProvider as getTracerProvider3 } from "@ai-setting/roy-agent-core";
11706
11708
 
11707
11709
  // src/commands/input-handler.ts
11708
11710
  class InputHandler {
@@ -12027,7 +12029,7 @@ async function shutdownInteractiveSteps(deps) {
12027
12029
  envService,
12028
12030
  shouldDisposeEnvService,
12029
12031
  output,
12030
- logger: logger4,
12032
+ logger: logger5,
12031
12033
  console: consoleLike
12032
12034
  } = deps;
12033
12035
  const log = (msg) => consoleLike?.log?.(msg) ?? console.log(msg);
@@ -12040,7 +12042,7 @@ async function shutdownInteractiveSteps(deps) {
12040
12042
  await memoryPluginDispose();
12041
12043
  log("\uD83D\uDCBE 记忆已保存完毕");
12042
12044
  } catch (err) {
12043
- logger4.warn(`[Shutdown] MemoryPlugin dispose failed: ${err}`);
12045
+ logger5.warn(`[Shutdown] MemoryPlugin dispose failed: ${err}`);
12044
12046
  output.warn(`⚠️ 记忆保存失败: ${err}`);
12045
12047
  }
12046
12048
  }
@@ -12048,25 +12050,25 @@ async function shutdownInteractiveSteps(deps) {
12048
12050
  try {
12049
12051
  await lspManagerDispose();
12050
12052
  } catch (err) {
12051
- logger4.warn(`[Shutdown] LSP Manager dispose failed: ${err}`);
12053
+ logger5.warn(`[Shutdown] LSP Manager dispose failed: ${err}`);
12052
12054
  }
12053
12055
  }
12054
12056
  if (pluginAdapterDispose) {
12055
12057
  try {
12056
12058
  await pluginAdapterDispose();
12057
12059
  } catch (err) {
12058
- logger4.warn(`[Shutdown] PluginAdapter dispose failed: ${err}`);
12060
+ logger5.warn(`[Shutdown] PluginAdapter dispose failed: ${err}`);
12059
12061
  }
12060
12062
  }
12061
12063
  try {
12062
12064
  eventHandler.stop();
12063
12065
  } catch (err) {
12064
- logger4.warn(`[Shutdown] EventHandler.stop failed: ${err}`);
12066
+ logger5.warn(`[Shutdown] EventHandler.stop failed: ${err}`);
12065
12067
  }
12066
12068
  try {
12067
12069
  queryExecutor.dispose();
12068
12070
  } catch (err) {
12069
- logger4.warn(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
12071
+ logger5.warn(`[Shutdown] QueryExecutor.dispose failed: ${err}`);
12070
12072
  }
12071
12073
  try {
12072
12074
  const eventSourceComponent = env.getComponent("event-source");
@@ -12075,7 +12077,7 @@ async function shutdownInteractiveSteps(deps) {
12075
12077
  if (sources && sources.length > 0) {
12076
12078
  for (const source of sources) {
12077
12079
  const status = eventSourceComponent.getStatus?.(source.id);
12078
- logger4.debug(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
12080
+ logger5.debug(`[Shutdown] 检查事件源: ${source.id}, 状态: ${status}`);
12079
12081
  if (status !== "stopped" && status !== "created") {
12080
12082
  try {
12081
12083
  await eventSourceComponent.stopSource(source.id);
@@ -12088,20 +12090,20 @@ async function shutdownInteractiveSteps(deps) {
12088
12090
  }
12089
12091
  }
12090
12092
  } catch (err) {
12091
- logger4.warn(`[Shutdown] EventSource cleanup failed: ${err}`);
12093
+ logger5.warn(`[Shutdown] EventSource cleanup failed: ${err}`);
12092
12094
  }
12093
12095
  if (shouldDisposeEnvService) {
12094
12096
  try {
12095
12097
  await envService.dispose();
12096
12098
  } catch (err) {
12097
- logger4.warn(`[Shutdown] envService.dispose failed: ${err}`);
12099
+ logger5.warn(`[Shutdown] envService.dispose failed: ${err}`);
12098
12100
  }
12099
12101
  }
12100
12102
  try {
12101
12103
  await TempFileManager2.getInstance().cleanupAll();
12102
- logger4.debug("[Shutdown] TempFileManager cleaned up");
12104
+ logger5.debug("[Shutdown] TempFileManager cleaned up");
12103
12105
  } catch (err) {
12104
- logger4.warn(`[Shutdown] TempFileManager cleanup failed: ${err}`);
12106
+ logger5.warn(`[Shutdown] TempFileManager cleanup failed: ${err}`);
12105
12107
  }
12106
12108
  }
12107
12109
 
@@ -12291,7 +12293,7 @@ var COLOR_BY_STATUS = {
12291
12293
  busy: COLORS.accent
12292
12294
  };
12293
12295
  // src/commands/interactive.ts
12294
- var logger4 = createLogger5("cli:interactive");
12296
+ var logger5 = createLogger6("cli:interactive");
12295
12297
  var USER_PROMPT = COLORS.accent("❯ ");
12296
12298
 
12297
12299
  class REPL {
@@ -12483,10 +12485,10 @@ ${COLORS.system("[正在中断...]")}`);
12483
12485
  const agentComponent = this.env.getComponent("agent");
12484
12486
  if (agentComponent?.abortAll) {
12485
12487
  agentComponent.abortAll();
12486
- logger4.debug("[/abort] AgentComponent.abortAll() called");
12488
+ logger5.debug("[/abort] AgentComponent.abortAll() called");
12487
12489
  } else if (agentComponent?.abort) {
12488
12490
  agentComponent.abort("default");
12489
- logger4.debug("[/abort] AgentComponent.abort('default') called (fallback)");
12491
+ logger5.debug("[/abort] AgentComponent.abort('default') called (fallback)");
12490
12492
  }
12491
12493
  }
12492
12494
  abortStream();
@@ -12581,7 +12583,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12581
12583
  try {
12582
12584
  await this.options.onAfterExecute(this.lastUsage);
12583
12585
  } catch (hookError) {
12584
- logger4.warn("onAfterExecute hook failed (ink path)", { error: String(hookError) });
12586
+ logger5.warn("onAfterExecute hook failed (ink path)", { error: String(hookError) });
12585
12587
  }
12586
12588
  }
12587
12589
  } catch (err) {
@@ -12601,7 +12603,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12601
12603
  await this.shutdown();
12602
12604
  resolve();
12603
12605
  }).catch(async (err) => {
12604
- logger4.error("ink REPL render failed", { error: String(err) });
12606
+ logger5.error("ink REPL render failed", { error: String(err) });
12605
12607
  await this.shutdown();
12606
12608
  resolve();
12607
12609
  });
@@ -12658,7 +12660,7 @@ ${COLORS.system("[没有正在执行的请求]")}`);
12658
12660
  }
12659
12661
  if (key.name === "escape") {
12660
12662
  this.handleEscKey().catch((err) => {
12661
- logger4.warn(`[Esc] handleEscKey failed: ${err}`);
12663
+ logger5.warn(`[Esc] handleEscKey failed: ${err}`);
12662
12664
  });
12663
12665
  }
12664
12666
  };
@@ -12853,7 +12855,7 @@ ${COLORS.system("[通知2] ❯ " + message.replace(/\n/g, `
12853
12855
  try {
12854
12856
  await this.options.onAfterExecute(this.lastUsage);
12855
12857
  } catch (hookError) {
12856
- logger4.warn("onAfterExecute hook failed", { error: String(hookError) });
12858
+ logger5.warn("onAfterExecute hook failed", { error: String(hookError) });
12857
12859
  }
12858
12860
  }
12859
12861
  } catch (error) {
@@ -13016,12 +13018,12 @@ ${COLORS.error("❌ 执行失败: " + error)}
13016
13018
  }
13017
13019
  async handleEscKey() {
13018
13020
  if (this.isShuttingDown) {
13019
- logger4.debug("[Esc] handler entered (isShuttingDown=true) → early return");
13021
+ logger5.debug("[Esc] handler entered (isShuttingDown=true) → early return");
13020
13022
  return;
13021
13023
  }
13022
13024
  const mainSessionIdEarly = this.options.sessionId;
13023
13025
  const hasActiveDescendant = mainSessionIdEarly ? hasActiveDescendants(this.env, mainSessionIdEarly) : false;
13024
- logger4.debug(`[Esc] handler entered: isExecuting=${this.isExecuting} hasActiveDescendant=${hasActiveDescendant} lastEscPressTime=${this.lastEscPressTime}`);
13026
+ logger5.debug(`[Esc] handler entered: isExecuting=${this.isExecuting} hasActiveDescendant=${hasActiveDescendant} lastEscPressTime=${this.lastEscPressTime}`);
13025
13027
  const now = Date.now();
13026
13028
  const isExecuting = this.isExecuting;
13027
13029
  const canCascade = isExecuting || hasActiveDescendant;
@@ -13030,17 +13032,17 @@ ${COLORS.error("❌ 执行失败: " + error)}
13030
13032
  this.lastEscPressTime = now;
13031
13033
  }
13032
13034
  if (!canCascade) {
13033
- logger4.debug("[Esc] idle no-op: isExecuting=false, no active descendant");
13035
+ logger5.debug("[Esc] idle no-op: isExecuting=false, no active descendant");
13034
13036
  return;
13035
13037
  }
13036
13038
  if (this.env) {
13037
13039
  const agentComponent = this.env.getComponent("agent");
13038
13040
  if (agentComponent?.abortAll) {
13039
13041
  agentComponent.abortAll();
13040
- logger4.debug("[Esc] AgentComponent.abortAll() called");
13042
+ logger5.debug("[Esc] AgentComponent.abortAll() called");
13041
13043
  } else if (agentComponent?.abort) {
13042
13044
  agentComponent.abort("default");
13043
- logger4.debug("[Esc] AgentComponent.abort('default') called (fallback)");
13045
+ logger5.debug("[Esc] AgentComponent.abort('default') called (fallback)");
13044
13046
  }
13045
13047
  }
13046
13048
  abortStream();
@@ -13048,7 +13050,7 @@ ${COLORS.error("❌ 执行失败: " + error)}
13048
13050
  try {
13049
13051
  this.inkApi.finishAssistantStream();
13050
13052
  } catch (err) {
13051
- logger4.warn("[Esc] finishAssistantStream failed", { error: String(err) });
13053
+ logger5.warn("[Esc] finishAssistantStream failed", { error: String(err) });
13052
13054
  }
13053
13055
  }
13054
13056
  const mainSessionId = this.options.sessionId;
@@ -13061,9 +13063,9 @@ ${COLORS.error("❌ 执行失败: " + error)}
13061
13063
  timer = setTimeout(() => reject(new Error("cascade timeout 5s")), 5000);
13062
13064
  })
13063
13065
  ]);
13064
- logger4.info(`[Esc] cascade stop force=${result.force} tasks=${result.stoppedTaskIds.length} workflows=${result.stoppedWorkflowSessionIds.length} errors=${result.errors.length}`);
13066
+ logger5.info(`[Esc] cascade stop force=${result.force} tasks=${result.stoppedTaskIds.length} workflows=${result.stoppedWorkflowSessionIds.length} errors=${result.errors.length}`);
13065
13067
  } catch (err) {
13066
- logger4.warn(`[Esc] cascade stop failed: ${err}`);
13068
+ logger5.warn(`[Esc] cascade stop failed: ${err}`);
13067
13069
  } finally {
13068
13070
  if (timer !== undefined)
13069
13071
  clearTimeout(timer);
@@ -13445,7 +13447,7 @@ function createInteractiveCommand(externalEnvService) {
13445
13447
  envService,
13446
13448
  shouldDisposeEnvService,
13447
13449
  output,
13448
- logger: logger4,
13450
+ logger: logger5,
13449
13451
  console
13450
13452
  });
13451
13453
  }
@@ -25492,24 +25494,106 @@ var LspCommand = {
25492
25494
 
25493
25495
  // src/commands/install/index.ts
25494
25496
  import { spawnSync } from "node:child_process";
25495
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync, rmSync } from "node:fs";
25496
- import { join as join5, resolve } from "node:path";
25497
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync, mkdirSync, rmSync as rmSync2 } from "node:fs";
25498
+ import { join as join6, resolve } from "node:path";
25497
25499
  import { homedir as homedir4 } from "node:os";
25500
+
25501
+ // src/commands/install/cleanup-stale-plugin-copies.ts
25502
+ import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync, cpSync } from "node:fs";
25503
+ import { join as join5 } from "node:path";
25504
+ import { homedir as nodeHomedir, tmpdir as nodeTmpdir } from "node:os";
25505
+ function cleanupStalePluginCopies(packageName, options) {
25506
+ const HOME = options.homedir ?? nodeHomedir();
25507
+ const paths = options.localNodeModulesPaths ?? [
25508
+ join5(HOME, "node_modules"),
25509
+ join5(HOME, ".roy-agent", "node_modules")
25510
+ ];
25511
+ const backupRoot = options.backupDir ?? nodeTmpdir();
25512
+ const result = {
25513
+ cleaned: [],
25514
+ skipped: [],
25515
+ backups: []
25516
+ };
25517
+ if (!options.globalVersion) {
25518
+ for (const p of paths) {
25519
+ const candidate = join5(p, packageName);
25520
+ result.skipped.push({ path: candidate, reason: "no-global-version" });
25521
+ }
25522
+ return result;
25523
+ }
25524
+ for (const nmPath of paths) {
25525
+ const localPkgDir = join5(nmPath, packageName);
25526
+ const localPkgJson = join5(localPkgDir, "package.json");
25527
+ if (!existsSync4(localPkgJson)) {
25528
+ result.skipped.push({ path: localPkgDir, reason: "no-local-copy" });
25529
+ continue;
25530
+ }
25531
+ let localVersion = null;
25532
+ try {
25533
+ const pkg = JSON.parse(readFileSync3(localPkgJson, "utf-8"));
25534
+ localVersion = typeof pkg.version === "string" ? pkg.version : null;
25535
+ } catch {
25536
+ localVersion = null;
25537
+ }
25538
+ const shouldClean = localVersion === null || compareVersions(localVersion, options.globalVersion) < 0;
25539
+ if (!shouldClean) {
25540
+ result.skipped.push({ path: localPkgDir, reason: "local-equal-or-newer" });
25541
+ continue;
25542
+ }
25543
+ let backupPath = null;
25544
+ try {
25545
+ const safeName = packageName.replace(/@/g, "").replace(/[^a-zA-Z0-9._/-]/g, "-");
25546
+ const safeLocalVersion = (localVersion ?? "unknown").replace(/[^a-zA-Z0-9._-]/g, "-");
25547
+ const timestamp = Date.now();
25548
+ backupPath = join5(backupRoot, `${safeName}-${safeLocalVersion}-backup-${timestamp}`);
25549
+ cpSync(localPkgDir, backupPath, { recursive: true });
25550
+ result.backups.push({ originalPath: localPkgDir, backupPath });
25551
+ } catch (err) {
25552
+ backupPath = null;
25553
+ console.warn(`⚠️ Failed to backup stale copy at '${localPkgDir}': ${err}`);
25554
+ }
25555
+ try {
25556
+ rmSync(localPkgDir, { recursive: true, force: true });
25557
+ result.cleaned.push(localPkgDir);
25558
+ } catch (err) {
25559
+ console.warn(`⚠️ Failed to remove stale copy at '${localPkgDir}': ${err}`);
25560
+ result.skipped.push({ path: localPkgDir, reason: "cleanup-failed" });
25561
+ if (backupPath) {
25562
+ console.warn(` ↪ Backup preserved at '${backupPath}' for manual recovery`);
25563
+ }
25564
+ }
25565
+ }
25566
+ return result;
25567
+ }
25568
+ function compareVersions(a, b) {
25569
+ const pa = a.split(".").map((s) => Number.parseInt(s, 10));
25570
+ const pb = b.split(".").map((s) => Number.parseInt(s, 10));
25571
+ for (let i = 0;i < 3; i++) {
25572
+ const na = Number.isFinite(pa[i]) ? pa[i] : 0;
25573
+ const nb = Number.isFinite(pb[i]) ? pb[i] : 0;
25574
+ const diff = na - nb;
25575
+ if (diff !== 0)
25576
+ return diff;
25577
+ }
25578
+ return 0;
25579
+ }
25580
+
25581
+ // src/commands/install/index.ts
25498
25582
  function getConfigDir(scope) {
25499
- return scope === "global" ? join5(homedir4(), ".roy-agent") : join5(process.cwd(), ".roy");
25583
+ return scope === "global" ? join6(homedir4(), ".roy-agent") : join6(process.cwd(), ".roy");
25500
25584
  }
25501
25585
  function detectDefaultScope() {
25502
- const projectDir = join5(process.cwd(), ".roy");
25503
- return existsSync4(projectDir) ? "project" : "global";
25586
+ const projectDir = join6(process.cwd(), ".roy");
25587
+ return existsSync5(projectDir) ? "project" : "global";
25504
25588
  }
25505
25589
  function getConfigPath(scope) {
25506
- return join5(getConfigDir(scope), "plugins.json");
25590
+ return join6(getConfigDir(scope), "plugins.json");
25507
25591
  }
25508
25592
  function loadPlugins(scope) {
25509
25593
  const configPath = getConfigPath(scope);
25510
25594
  try {
25511
- if (existsSync4(configPath)) {
25512
- const raw = readFileSync3(configPath, "utf-8");
25595
+ if (existsSync5(configPath)) {
25596
+ const raw = readFileSync4(configPath, "utf-8");
25513
25597
  const config = JSON.parse(raw);
25514
25598
  return config.plugins ?? [];
25515
25599
  }
@@ -25519,7 +25603,7 @@ function loadPlugins(scope) {
25519
25603
  function savePlugins(plugins, scope) {
25520
25604
  const configDir = getConfigDir(scope);
25521
25605
  const configPath = getConfigPath(scope);
25522
- if (!existsSync4(configDir)) {
25606
+ if (!existsSync5(configDir)) {
25523
25607
  mkdirSync(configDir, { recursive: true });
25524
25608
  }
25525
25609
  const config = { plugins };
@@ -25535,10 +25619,10 @@ function stripVersionSpec(packageName) {
25535
25619
  function readPackageInfo(packageName) {
25536
25620
  const bareName = packageName.startsWith("/") || packageName.startsWith(".") ? packageName : stripVersionSpec(packageName);
25537
25621
  if (packageName.startsWith("/") || packageName.startsWith(".")) {
25538
- const localPkgPath = join5(packageName, "package.json");
25539
- if (existsSync4(localPkgPath)) {
25622
+ const localPkgPath = join6(packageName, "package.json");
25623
+ if (existsSync5(localPkgPath)) {
25540
25624
  try {
25541
- const pkg = JSON.parse(readFileSync3(localPkgPath, "utf-8"));
25625
+ const pkg = JSON.parse(readFileSync4(localPkgPath, "utf-8"));
25542
25626
  return {
25543
25627
  version: pkg.version ?? "0.0.0",
25544
25628
  name: pkg.name ?? packageName,
@@ -25550,19 +25634,19 @@ function readPackageInfo(packageName) {
25550
25634
  }
25551
25635
  }
25552
25636
  const searchPaths = [
25553
- join5(process.cwd(), "node_modules", bareName, "package.json"),
25637
+ join6(process.cwd(), "node_modules", bareName, "package.json"),
25554
25638
  resolve(process.cwd(), "..", "node_modules", bareName, "package.json"),
25555
- join5(process.cwd(), ".roy", "plugins", bareName, "package.json"),
25639
+ join6(process.cwd(), ".roy", "plugins", bareName, "package.json"),
25556
25640
  ...(() => {
25557
25641
  const globalRoot = getNpmGlobalRoot();
25558
- return globalRoot ? [join5(globalRoot, bareName, "package.json")] : [];
25642
+ return globalRoot ? [join6(globalRoot, bareName, "package.json")] : [];
25559
25643
  })(),
25560
- join5(homedir4(), ".roy-agent", "node_modules", bareName, "package.json")
25644
+ join6(homedir4(), ".roy-agent", "node_modules", bareName, "package.json")
25561
25645
  ];
25562
25646
  for (const pkgPath of searchPaths) {
25563
25647
  try {
25564
- if (existsSync4(pkgPath)) {
25565
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
25648
+ if (existsSync5(pkgPath)) {
25649
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
25566
25650
  return {
25567
25651
  version: pkg.version ?? "0.0.0",
25568
25652
  name: pkg.name ?? bareName,
@@ -25584,19 +25668,6 @@ function getNpmGlobalRoot() {
25584
25668
  }
25585
25669
  return null;
25586
25670
  }
25587
- function cleanupStaleCpCopy(packageName) {
25588
- const cpDir = join5(homedir4(), ".roy-agent", "node_modules", packageName);
25589
- if (!existsSync4(cpDir)) {
25590
- return false;
25591
- }
25592
- try {
25593
- rmSync(cpDir, { recursive: true, force: true });
25594
- return true;
25595
- } catch (err) {
25596
- console.warn(`⚠️ Failed to clean stale cp copy at '${cpDir}': ${err}`);
25597
- return false;
25598
- }
25599
- }
25600
25671
  async function verifyInstalledVersion(packageName, declaredVersion) {
25601
25672
  const actual = readPackageInfo(packageName);
25602
25673
  if (!actual || !actual.version) {
@@ -25608,15 +25679,15 @@ async function verifyInstalledVersion(packageName, declaredVersion) {
25608
25679
  return { ok: true, actualVersion: actual.version };
25609
25680
  }
25610
25681
  function getPackageManagerCommand() {
25611
- if (existsSync4(join5(process.cwd(), "pnpm-lock.yaml"))) {
25612
- if (existsSync4(join5(process.cwd(), "pnpm-workspace.yaml"))) {
25682
+ if (existsSync5(join6(process.cwd(), "pnpm-lock.yaml"))) {
25683
+ if (existsSync5(join6(process.cwd(), "pnpm-workspace.yaml"))) {
25613
25684
  return "pnpm -w";
25614
25685
  }
25615
25686
  return "pnpm";
25616
25687
  }
25617
- if (existsSync4(join5(process.cwd(), "yarn.lock")))
25688
+ if (existsSync5(join6(process.cwd(), "yarn.lock")))
25618
25689
  return "yarn";
25619
- if (existsSync4(join5(process.cwd(), "bun.lock")) || existsSync4(join5(process.cwd(), "bun.lockb")))
25690
+ if (existsSync5(join6(process.cwd(), "bun.lock")) || existsSync5(join6(process.cwd(), "bun.lockb")))
25620
25691
  return "bun";
25621
25692
  return "npm";
25622
25693
  }
@@ -25655,14 +25726,14 @@ var InstallPackageCommand = {
25655
25726
  }
25656
25727
  resolvedName = info2.name;
25657
25728
  const srcDir = resolve(packageName);
25658
- if (!existsSync4(srcDir)) {
25729
+ if (!existsSync5(srcDir)) {
25659
25730
  console.error(`
25660
25731
  ❌ Local path '${srcDir}' does not exist.
25661
25732
  `);
25662
25733
  process.exit(1);
25663
25734
  }
25664
- const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
25665
- if (!existsSync4(pluginDir)) {
25735
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", resolvedName);
25736
+ if (!existsSync5(pluginDir)) {
25666
25737
  mkdirSync(pluginDir, { recursive: true });
25667
25738
  }
25668
25739
  const result = spawnSync("cp", ["-r", `${srcDir}/.`, pluginDir], {
@@ -25697,12 +25768,12 @@ var InstallPackageCommand = {
25697
25768
  process.exit(1);
25698
25769
  }
25699
25770
  resolvedName = info2.name;
25700
- const pluginDir = join5(process.cwd(), ".roy", "plugins", resolvedName);
25701
- if (!existsSync4(pluginDir)) {
25771
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", resolvedName);
25772
+ if (!existsSync5(pluginDir)) {
25702
25773
  mkdirSync(pluginDir, { recursive: true });
25703
25774
  }
25704
- const nmPath = join5(process.cwd(), "node_modules", packageName);
25705
- if (existsSync4(nmPath)) {
25775
+ const nmPath = join6(process.cwd(), "node_modules", packageName);
25776
+ if (existsSync5(nmPath)) {
25706
25777
  spawnSync("cp", ["-r", `${nmPath}/.`, pluginDir], { stdio: "inherit", shell: false });
25707
25778
  }
25708
25779
  }
@@ -25722,11 +25793,24 @@ var InstallPackageCommand = {
25722
25793
  }
25723
25794
  const tmpInfo = readPackageInfo(packageName);
25724
25795
  if (tmpInfo) {
25725
- const cleaned = cleanupStaleCpCopy(tmpInfo.name);
25726
- if (cleaned) {
25796
+ const cleanupResult = cleanupStalePluginCopies(tmpInfo.name, {
25797
+ globalVersion: tmpInfo.version,
25798
+ homedir: homedir4()
25799
+ });
25800
+ if (cleanupResult.cleaned.length > 0) {
25727
25801
  console.log(`
25728
- \uD83E\uDDF9 Cleaned stale cp copy: ~/.roy-agent/node_modules/${tmpInfo.name}
25729
- `);
25802
+ \uD83E\uDDF9 Cleaned stale plugin copies:`);
25803
+ for (const path9 of cleanupResult.cleaned) {
25804
+ console.log(` - ${path9}`);
25805
+ }
25806
+ if (cleanupResult.backups.length > 0) {
25807
+ console.log(`
25808
+ \uD83D\uDCE6 Backups (for manual recovery):`);
25809
+ for (const b of cleanupResult.backups) {
25810
+ console.log(` ${b.originalPath} → ${b.backupPath}`);
25811
+ }
25812
+ }
25813
+ console.log();
25730
25814
  }
25731
25815
  }
25732
25816
  }
@@ -25851,8 +25935,8 @@ var InstallRemoveCommand = {
25851
25935
  \uD83D\uDDD1️ Removing plugin: ${plugin.packageName}@${plugin.version} (${scope})
25852
25936
  `);
25853
25937
  if (scope === "project") {
25854
- const pluginDir = join5(process.cwd(), ".roy", "plugins", plugin.packageName);
25855
- if (existsSync4(pluginDir)) {
25938
+ const pluginDir = join6(process.cwd(), ".roy", "plugins", plugin.packageName);
25939
+ if (existsSync5(pluginDir)) {
25856
25940
  spawnSync("rm", ["-rf", pluginDir], { stdio: "inherit", shell: false });
25857
25941
  console.log(` Removed plugin directory: ${pluginDir}`);
25858
25942
  }
@@ -25867,8 +25951,8 @@ var InstallRemoveCommand = {
25867
25951
  `);
25868
25952
  process.exit(result.status ?? 1);
25869
25953
  }
25870
- const globalNm = join5(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
25871
- if (existsSync4(globalNm)) {
25954
+ const globalNm = join6(homedir4(), ".roy-agent", "node_modules", plugin.packageName);
25955
+ if (existsSync5(globalNm)) {
25872
25956
  spawnSync("rm", ["-rf", globalNm], { stdio: "inherit", shell: false });
25873
25957
  }
25874
25958
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-agent-cli",
3
- "version": "1.7.15",
3
+ "version": "1.7.17",
4
4
  "type": "module",
5
5
  "description": "CLI for roy-agent - Non-interactive command execution",
6
6
  "main": "./dist/index.js",