@ganglion/xacpx 0.18.1 → 0.19.0

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.
@@ -2633,12 +2633,12 @@ var init_prompt_media = __esm(() => {
2633
2633
  };
2634
2634
  });
2635
2635
 
2636
- // src/transport/claude-background-followup.ts
2636
+ // src/transport/background-followup.ts
2637
2637
  import { access, open as open2, readFile, readdir, stat } from "node:fs/promises";
2638
2638
  import { constants as fsConstants } from "node:fs";
2639
2639
  import { homedir as homedir2 } from "node:os";
2640
2640
  import { basename, dirname as dirname2, join as join2 } from "node:path";
2641
- function isClaudeAsyncAgentLaunch(event) {
2641
+ function isAsyncAgentLaunch(event) {
2642
2642
  return isAsyncAgentLaunchOutput(event.rawOutput);
2643
2643
  }
2644
2644
  function isAsyncAgentLaunchOutput(rawOutput) {
@@ -2660,13 +2660,13 @@ function tryParseJsonObject(text) {
2660
2660
  return;
2661
2661
  }
2662
2662
  }
2663
- function claudeAsyncAgentId(event) {
2663
+ function asyncAgentId(event) {
2664
2664
  const fromObject = findStringField(event.rawOutput, new Set(["agentId", "agent_id"]));
2665
2665
  if (fromObject)
2666
2666
  return fromObject;
2667
2667
  return /\bagent(?:Id|_id)["']?\s*[:=]\s*["']?([A-Za-z0-9_-]+)/i.exec(textOfUnknown(event.rawOutput))?.[1];
2668
2668
  }
2669
- async function findClaudeTranscriptPath(input) {
2669
+ async function findNativeTranscriptPath(input) {
2670
2670
  const configDirName = input.driver === "qoder" ? ".qoder" : ".claude";
2671
2671
  const projectsDir = join2(input.homeDir ?? homedir2(), configDirName, "projects");
2672
2672
  const direct = join2(projectsDir, encodeClaudeProjectDirectory(input.cwd), `${input.sessionId}.jsonl`);
@@ -2686,8 +2686,8 @@ async function findClaudeTranscriptPath(input) {
2686
2686
  }
2687
2687
  return;
2688
2688
  }
2689
- async function followClaudeBackgroundTurn(options) {
2690
- const transcriptPath = options.transcriptPath ?? await findClaudeTranscriptPath(options);
2689
+ async function followBackgroundTurn(options) {
2690
+ const transcriptPath = options.transcriptPath ?? await findNativeTranscriptPath(options);
2691
2691
  if (!transcriptPath) {
2692
2692
  return { status: "unavailable", completedToolCallIds: [], failedToolCallIds: [] };
2693
2693
  }
@@ -2869,8 +2869,8 @@ async function followClaudeBackgroundTurn(options) {
2869
2869
  ...previous?.rawOutput !== undefined ? { rawOutput: previous.rawOutput } : output ? { rawOutput: output } : {},
2870
2870
  status: readBoolean(block, "is_error") || previous?.status === "error" ? "error" : "success"
2871
2871
  };
2872
- if (event.isSubagent && isClaudeAsyncAgentLaunch(event)) {
2873
- const agentId = claudeAsyncAgentId(event);
2872
+ if (event.isSubagent && isAsyncAgentLaunch(event)) {
2873
+ const agentId = asyncAgentId(event);
2874
2874
  if (agentId)
2875
2875
  parentToolCallIdByAgentId.set(agentId, event.toolCallId);
2876
2876
  }
@@ -3183,7 +3183,7 @@ async function waitForPoll(ms, signal) {
3183
3183
  });
3184
3184
  }
3185
3185
  var DEFAULT_POLL_INTERVAL_MS = 250, DEFAULT_TIMEOUT_MS, FINAL_SUBAGENT_DRAIN_MAX_POLLS = 4, FINAL_SUBAGENT_DRAIN_STABLE_POLLS = 2, ASYNC_AGENT_LAUNCH;
3186
- var init_claude_background_followup = __esm(() => {
3186
+ var init_background_followup = __esm(() => {
3187
3187
  DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
3188
3188
  ASYNC_AGENT_LAUNCH = /Async agent launched successfully|["']?status["']?\s*:\s*["']async_launched["']/i;
3189
3189
  });
@@ -3454,8 +3454,8 @@ function buildToolUseEvent(update, driver) {
3454
3454
  const claudeMeta = isClaudeDriver ? update._meta?.claudeCode : undefined;
3455
3455
  const claudeToolResponse = claudeMeta?.toolResponse;
3456
3456
  const hasClaudeToolResponse = !isEmptyToolField(claudeToolResponse);
3457
- const isAsyncAgentLaunch = update._meta?.claudeCode?.toolName === "Agent" && isRecord2(claudeToolResponse) && claudeToolResponse.status === "async_launched" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" && isAsyncAgentLaunchOutput(update.rawOutput);
3458
- const status = isAsyncAgentLaunch ? "running" : statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : hasClaudeToolResponse ? "success" : "running";
3457
+ const isAsyncAgentLaunch2 = update._meta?.claudeCode?.toolName === "Agent" && isRecord2(claudeToolResponse) && claudeToolResponse.status === "async_launched" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" && isAsyncAgentLaunchOutput(update.rawOutput);
3458
+ const status = isAsyncAgentLaunch2 ? "running" : statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : hasClaudeToolResponse ? "success" : "running";
3459
3459
  const rawInput = update.rawInput;
3460
3460
  const content = update.content;
3461
3461
  const rawOutput = update.rawOutput ?? claudeToolResponse;
@@ -3631,7 +3631,7 @@ function isGenericToolTitle(kind, title) {
3631
3631
  }
3632
3632
  var USAGE_BREAKDOWN_FIELDS;
3633
3633
  var init_streaming_prompt = __esm(() => {
3634
- init_claude_background_followup();
3634
+ init_background_followup();
3635
3635
  init_tool_kind_emoji();
3636
3636
  USAGE_BREAKDOWN_FIELDS = [
3637
3637
  ["inputTokens", ["inputTokens", "input_tokens"]],
package/dist/cli.js CHANGED
@@ -33177,12 +33177,12 @@ var init_prompt_media = __esm(() => {
33177
33177
  };
33178
33178
  });
33179
33179
 
33180
- // src/transport/claude-background-followup.ts
33180
+ // src/transport/background-followup.ts
33181
33181
  import { access as access4, open as open5, readFile as readFile14, readdir as readdir3, stat as stat3 } from "node:fs/promises";
33182
33182
  import { constants as fsConstants } from "node:fs";
33183
33183
  import { homedir as homedir10 } from "node:os";
33184
33184
  import { basename as basename3, dirname as dirname12, join as join20 } from "node:path";
33185
- function isClaudeAsyncAgentLaunch(event) {
33185
+ function isAsyncAgentLaunch(event) {
33186
33186
  return isAsyncAgentLaunchOutput(event.rawOutput);
33187
33187
  }
33188
33188
  function isAsyncAgentLaunchOutput(rawOutput) {
@@ -33204,13 +33204,13 @@ function tryParseJsonObject(text) {
33204
33204
  return;
33205
33205
  }
33206
33206
  }
33207
- function claudeAsyncAgentId(event) {
33207
+ function asyncAgentId(event) {
33208
33208
  const fromObject = findStringField(event.rawOutput, new Set(["agentId", "agent_id"]));
33209
33209
  if (fromObject)
33210
33210
  return fromObject;
33211
33211
  return /\bagent(?:Id|_id)["']?\s*[:=]\s*["']?([A-Za-z0-9_-]+)/i.exec(textOfUnknown(event.rawOutput))?.[1];
33212
33212
  }
33213
- async function findClaudeTranscriptPath(input) {
33213
+ async function findNativeTranscriptPath(input) {
33214
33214
  const configDirName = input.driver === "qoder" ? ".qoder" : ".claude";
33215
33215
  const projectsDir = join20(input.homeDir ?? homedir10(), configDirName, "projects");
33216
33216
  const direct = join20(projectsDir, encodeClaudeProjectDirectory(input.cwd), `${input.sessionId}.jsonl`);
@@ -33230,8 +33230,8 @@ async function findClaudeTranscriptPath(input) {
33230
33230
  }
33231
33231
  return;
33232
33232
  }
33233
- async function followClaudeBackgroundTurn(options) {
33234
- const transcriptPath = options.transcriptPath ?? await findClaudeTranscriptPath(options);
33233
+ async function followBackgroundTurn(options) {
33234
+ const transcriptPath = options.transcriptPath ?? await findNativeTranscriptPath(options);
33235
33235
  if (!transcriptPath) {
33236
33236
  return { status: "unavailable", completedToolCallIds: [], failedToolCallIds: [] };
33237
33237
  }
@@ -33413,8 +33413,8 @@ async function followClaudeBackgroundTurn(options) {
33413
33413
  ...previous?.rawOutput !== undefined ? { rawOutput: previous.rawOutput } : output ? { rawOutput: output } : {},
33414
33414
  status: readBoolean(block, "is_error") || previous?.status === "error" ? "error" : "success"
33415
33415
  };
33416
- if (event.isSubagent && isClaudeAsyncAgentLaunch(event)) {
33417
- const agentId = claudeAsyncAgentId(event);
33416
+ if (event.isSubagent && isAsyncAgentLaunch(event)) {
33417
+ const agentId = asyncAgentId(event);
33418
33418
  if (agentId)
33419
33419
  parentToolCallIdByAgentId.set(agentId, event.toolCallId);
33420
33420
  }
@@ -33727,7 +33727,7 @@ async function waitForPoll(ms, signal) {
33727
33727
  });
33728
33728
  }
33729
33729
  var DEFAULT_POLL_INTERVAL_MS = 250, DEFAULT_TIMEOUT_MS, FINAL_SUBAGENT_DRAIN_MAX_POLLS = 4, FINAL_SUBAGENT_DRAIN_STABLE_POLLS = 2, ASYNC_AGENT_LAUNCH;
33730
- var init_claude_background_followup = __esm(() => {
33730
+ var init_background_followup = __esm(() => {
33731
33731
  DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
33732
33732
  ASYNC_AGENT_LAUNCH = /Async agent launched successfully|["']?status["']?\s*:\s*["']async_launched["']/i;
33733
33733
  });
@@ -33987,8 +33987,8 @@ function buildToolUseEvent(update, driver) {
33987
33987
  const claudeMeta = isClaudeDriver ? update._meta?.claudeCode : undefined;
33988
33988
  const claudeToolResponse = claudeMeta?.toolResponse;
33989
33989
  const hasClaudeToolResponse = !isEmptyToolField(claudeToolResponse);
33990
- const isAsyncAgentLaunch = update._meta?.claudeCode?.toolName === "Agent" && isRecord4(claudeToolResponse) && claudeToolResponse.status === "async_launched" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" && isAsyncAgentLaunchOutput(update.rawOutput);
33991
- const status = isAsyncAgentLaunch ? "running" : statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : hasClaudeToolResponse ? "success" : "running";
33990
+ const isAsyncAgentLaunch2 = update._meta?.claudeCode?.toolName === "Agent" && isRecord4(claudeToolResponse) && claudeToolResponse.status === "async_launched" || driver === "qoder" && update._meta?.qoder?.toolName === "Agent" && isAsyncAgentLaunchOutput(update.rawOutput);
33991
+ const status = isAsyncAgentLaunch2 ? "running" : statusRaw === "completed" || statusRaw === "success" ? "success" : statusRaw === "failed" || statusRaw === "error" ? "error" : hasClaudeToolResponse ? "success" : "running";
33992
33992
  const rawInput = update.rawInput;
33993
33993
  const content = update.content;
33994
33994
  const rawOutput = update.rawOutput ?? claudeToolResponse;
@@ -34164,7 +34164,7 @@ function isGenericToolTitle(kind, title) {
34164
34164
  }
34165
34165
  var USAGE_BREAKDOWN_FIELDS;
34166
34166
  var init_streaming_prompt = __esm(() => {
34167
- init_claude_background_followup();
34167
+ init_background_followup();
34168
34168
  init_tool_kind_emoji();
34169
34169
  USAGE_BREAKDOWN_FIELDS = [
34170
34170
  ["inputTokens", ["inputTokens", "input_tokens"]],
@@ -35314,9 +35314,9 @@ var init_acpx_cli_transport = __esm(() => {
35314
35314
  require4 = createRequire5(import.meta.url);
35315
35315
  });
35316
35316
 
35317
- // src/transport/claude-background-followup-transport.ts
35318
- function createClaudeBackgroundFollowupTransport(delegate, options) {
35319
- const followBackgroundTurn = options.followBackgroundTurn ?? followClaudeBackgroundTurn;
35317
+ // src/transport/background-followup-transport.ts
35318
+ function createBackgroundFollowupTransport(delegate, options) {
35319
+ const runBackgroundFollowup = options.followBackgroundTurn ?? followBackgroundTurn;
35320
35320
  const prompt = async (session3, text, reply, replyContext, promptOptions) => {
35321
35321
  const latestToolEvents = new Map;
35322
35322
  const pendingToolEvents = new Map;
@@ -35329,9 +35329,9 @@ function createClaudeBackgroundFollowupTransport(delegate, options) {
35329
35329
  pendingToolEvents.set(event.toolCallId, event);
35330
35330
  else
35331
35331
  pendingToolEvents.delete(event.toolCallId);
35332
- if (event.isSubagent && isClaudeAsyncAgentLaunch(event)) {
35332
+ if (event.isSubagent && isAsyncAgentLaunch(event)) {
35333
35333
  asyncToolCallIds.add(event.toolCallId);
35334
- const agentId = claudeAsyncAgentId(event);
35334
+ const agentId = asyncAgentId(event);
35335
35335
  if (agentId)
35336
35336
  subagentIdsByToolCallId.set(event.toolCallId, agentId);
35337
35337
  }
@@ -35350,7 +35350,7 @@ function createClaudeBackgroundFollowupTransport(delegate, options) {
35350
35350
  try {
35351
35351
  agentSessionId = await delegate.getAgentSessionId?.(session3);
35352
35352
  } catch (error2) {
35353
- await options.logger.error("transport.claude_background_followup.session_id_failed", "failed to resolve agent session id for background follow-up", { alias: session3.alias, error: error2 instanceof Error ? error2.message : String(error2) });
35353
+ await options.logger.error(`${LEGACY_LOG_EVENT_PREFIX}.session_id_failed`, "failed to resolve agent session id for background follow-up", { alias: session3.alias, error: error2 instanceof Error ? error2.message : String(error2) });
35354
35354
  }
35355
35355
  }
35356
35356
  if (!agentSessionId) {
@@ -35363,8 +35363,8 @@ function createClaudeBackgroundFollowupTransport(delegate, options) {
35363
35363
  }
35364
35364
  return result;
35365
35365
  }
35366
- await options.logger.info("transport.claude_background_followup.started", "following background-agent continuation", { alias: session3.alias, agentSessionId, driver, taskCount: asyncToolCallIds.size });
35367
- const followup = await followBackgroundTurn({
35366
+ await options.logger.info(`${LEGACY_LOG_EVENT_PREFIX}.started`, "following background-agent continuation", { alias: session3.alias, agentSessionId, driver, taskCount: asyncToolCallIds.size });
35367
+ const followup = await runBackgroundFollowup({
35368
35368
  cwd: session3.cwd,
35369
35369
  sessionId: agentSessionId,
35370
35370
  driver,
@@ -35399,7 +35399,7 @@ function createClaudeBackgroundFollowupTransport(delegate, options) {
35399
35399
  ...followup.status === "completed" && !failed ? {} : { rawOutput: { message: failed ? "background Agent failed" : `background continuation ${followup.status}` } }
35400
35400
  });
35401
35401
  }
35402
- await options.logger.info(`transport.claude_background_followup.${followup.status}`, `background-agent follow-up ${followup.status}`, {
35402
+ await options.logger.info(`${LEGACY_LOG_EVENT_PREFIX}.${followup.status}`, `background-agent follow-up ${followup.status}`, {
35403
35403
  alias: session3.alias,
35404
35404
  agentSessionId,
35405
35405
  driver,
@@ -35417,8 +35417,9 @@ function createClaudeBackgroundFollowupTransport(delegate, options) {
35417
35417
  }
35418
35418
  });
35419
35419
  }
35420
- var init_claude_background_followup_transport = __esm(() => {
35421
- init_claude_background_followup();
35420
+ var LEGACY_LOG_EVENT_PREFIX = "transport.claude_background_followup";
35421
+ var init_background_followup_transport = __esm(() => {
35422
+ init_background_followup();
35422
35423
  });
35423
35424
 
35424
35425
  // src/util/async.ts
@@ -36782,21 +36783,28 @@ class WorkspaceGit {
36782
36783
  }
36783
36784
  return startPoint;
36784
36785
  }
36785
- async includeRenameSources(root, paths) {
36786
- const selected = new Set(paths);
36787
- const expanded = new Set(paths);
36786
+ async readPorcelain(root) {
36788
36787
  const fields = (await this.runRaw(root, ["-c", "core.quotePath=false", "status", "--porcelain", "-z"])).split("\x00");
36788
+ const entries = [];
36789
36789
  for (let index = 0;index < fields.length; index += 1) {
36790
36790
  const field = fields[index];
36791
36791
  if (!field)
36792
36792
  continue;
36793
36793
  const status = field.slice(0, 2);
36794
36794
  const path14 = field.slice(3);
36795
- if (status[0] !== "R" && status[0] !== "C")
36796
- continue;
36797
- const originalPath = fields[++index];
36798
- if (originalPath && selected.has(path14))
36799
- expanded.add(originalPath);
36795
+ const entry = { status, path: path14 };
36796
+ if (status[0] === "R" || status[0] === "C")
36797
+ entry.originalPath = fields[++index];
36798
+ entries.push(entry);
36799
+ }
36800
+ return entries;
36801
+ }
36802
+ async includeRenameSources(root, paths) {
36803
+ const selected = new Set(paths);
36804
+ const expanded = new Set(paths);
36805
+ for (const entry of await this.readPorcelain(root)) {
36806
+ if (entry.originalPath && selected.has(entry.path))
36807
+ expanded.add(entry.originalPath);
36800
36808
  }
36801
36809
  return [...expanded];
36802
36810
  }
@@ -36834,6 +36842,38 @@ class WorkspaceGit {
36834
36842
  }
36835
36843
  });
36836
36844
  }
36845
+ async untrack(workspace3, paths) {
36846
+ await this.withWrite(workspace3, async () => {
36847
+ const root = await this.rootFor(workspace3);
36848
+ await this.run(root, ["--literal-pathspecs", "rm", "--cached", "--force", "--", ...this.validatePaths(paths)]);
36849
+ });
36850
+ }
36851
+ async discard(workspace3, paths) {
36852
+ await this.withWrite(workspace3, async () => {
36853
+ const root = await this.rootFor(workspace3);
36854
+ const selected = new Set(this.validatePaths(paths));
36855
+ const deletePaths = new Set;
36856
+ const restorePaths = new Set;
36857
+ for (const entry of await this.readPorcelain(root)) {
36858
+ if (!selected.has(entry.path))
36859
+ continue;
36860
+ if (entry.status === "??" || entry.status[0] === "A" || entry.originalPath !== undefined) {
36861
+ deletePaths.add(entry.path);
36862
+ if (entry.originalPath)
36863
+ restorePaths.add(entry.originalPath);
36864
+ } else {
36865
+ restorePaths.add(entry.path);
36866
+ }
36867
+ }
36868
+ if (deletePaths.size) {
36869
+ await this.run(root, ["--literal-pathspecs", "reset", "-q", "--", ...deletePaths]);
36870
+ await this.run(root, ["--literal-pathspecs", "clean", "-qf", "--", ...deletePaths]);
36871
+ }
36872
+ if (restorePaths.size) {
36873
+ await this.run(root, ["--literal-pathspecs", "restore", "--source=HEAD", "--staged", "--worktree", "--", ...restorePaths]);
36874
+ }
36875
+ });
36876
+ }
36837
36877
  async commit(workspace3, message) {
36838
36878
  return this.withWrite(workspace3, async () => {
36839
36879
  const root = await this.rootFor(workspace3);
@@ -37564,6 +37604,12 @@ class ControlService {
37564
37604
  gitUnstage(workspace3, paths) {
37565
37605
  return this.mutateWorkspaceGit(() => this.workspaceGit.unstage(workspace3, paths));
37566
37606
  }
37607
+ gitUntrack(workspace3, paths) {
37608
+ return this.mutateWorkspaceGit(() => this.workspaceGit.untrack(workspace3, paths));
37609
+ }
37610
+ gitDiscard(workspace3, paths) {
37611
+ return this.mutateWorkspaceGit(() => this.workspaceGit.discard(workspace3, paths));
37612
+ }
37567
37613
  gitCommit(workspace3, message) {
37568
37614
  return this.mutateWorkspaceGit(() => this.workspaceGit.commit(workspace3, message));
37569
37615
  }
@@ -38594,7 +38640,7 @@ async function buildApp(paths, deps = {}) {
38594
38640
  });
38595
38641
  }
38596
38642
  })))) : deps.createCliTransport?.(acpxCommand) ?? new AcpxCliTransport({ ...config4.transport, command: acpxCommand });
38597
- const transport = createClaudeBackgroundFollowupTransport(baseTransport, {
38643
+ const transport = createBackgroundFollowupTransport(baseTransport, {
38598
38644
  logger,
38599
38645
  resolveDriver: (agent4) => config4.agents[agent4]?.driver
38600
38646
  });
@@ -39269,7 +39315,7 @@ var init_main = __esm(async () => {
39269
39315
  init_acpx_bridge_client();
39270
39316
  init_acpx_bridge_transport();
39271
39317
  init_acpx_cli_transport();
39272
- init_claude_background_followup_transport();
39318
+ init_background_followup_transport();
39273
39319
  init_queue_owner_reaper();
39274
39320
  init_collect_reap_targets();
39275
39321
  init_channel_registry();
@@ -158,6 +158,8 @@ export declare class ControlService {
158
158
  private withWorktreeRegistration;
159
159
  gitStage(workspace: string, paths: string[]): Promise<void>;
160
160
  gitUnstage(workspace: string, paths: string[]): Promise<void>;
161
+ gitUntrack(workspace: string, paths: string[]): Promise<void>;
162
+ gitDiscard(workspace: string, paths: string[]): Promise<void>;
161
163
  gitCommit(workspace: string, message: string): Promise<GitCommitResult>;
162
164
  gitFetch(workspace: string, remote?: string): Promise<void>;
163
165
  gitPull(workspace: string): Promise<void>;
@@ -77,6 +77,7 @@ export declare class WorkspaceGit {
77
77
  private validatePaths;
78
78
  private validateBranch;
79
79
  private validateStartPoint;
80
+ private readPorcelain;
80
81
  private includeRenameSources;
81
82
  /** Git write commands for one configured workspace share a FIFO. Reads remain
82
83
  * concurrent, and a failed write releases the next command instead of poisoning
@@ -84,6 +85,8 @@ export declare class WorkspaceGit {
84
85
  private withWrite;
85
86
  stage(workspace: string, paths: string[]): Promise<void>;
86
87
  unstage(workspace: string, paths: string[]): Promise<void>;
88
+ untrack(workspace: string, paths: string[]): Promise<void>;
89
+ discard(workspace: string, paths: string[]): Promise<void>;
87
90
  commit(workspace: string, message: string): Promise<GitCommitResult>;
88
91
  checkout(workspace: string, options: GitCheckoutOptions): Promise<void>;
89
92
  fetch(workspace: string, remote?: string): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganglion/xacpx",
3
- "version": "0.18.1",
3
+ "version": "0.19.0",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",