@ganglion/xacpx 0.24.5-beta.0 → 0.24.6-beta.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.
@@ -2,12 +2,12 @@ export declare const MANAGED_ADAPTERS: {
2
2
  readonly codex: {
3
3
  readonly packageName: "@agentclientprotocol/codex-acp";
4
4
  readonly binName: "codex-acp";
5
- readonly defaultVersion: "1.10.0";
5
+ readonly defaultVersion: "1.12.0";
6
6
  };
7
7
  readonly claude: {
8
8
  readonly packageName: "@agentclientprotocol/claude-agent-acp";
9
9
  readonly binName: "claude-agent-acp";
10
- readonly defaultVersion: "0.75.1";
10
+ readonly defaultVersion: "0.78.0";
11
11
  };
12
12
  };
13
13
  export type ManagedAdapterId = keyof typeof MANAGED_ADAPTERS;
@@ -0,0 +1,66 @@
1
+ export type BotRuntimeScope = "bot-direct" | "group-member" | "group-controller";
2
+ export interface BotProfilePresentation {
3
+ name: string;
4
+ avatar?: string;
5
+ role?: string;
6
+ }
7
+ export interface BotProfileBehavior {
8
+ instructions?: string;
9
+ }
10
+ export interface BotProfileExecution {
11
+ agent: string;
12
+ workspace: string;
13
+ model?: string;
14
+ effort?: string;
15
+ }
16
+ /** Durable linearization of the Bot fields a Run was accepted against. */
17
+ export interface BotProfileSnapshot {
18
+ revision: number;
19
+ capturedAt: string;
20
+ presentation: BotProfilePresentation;
21
+ behavior: BotProfileBehavior;
22
+ execution: BotProfileExecution;
23
+ }
24
+ export interface BotProfile {
25
+ id: string;
26
+ name: string;
27
+ avatar?: string;
28
+ role?: string;
29
+ instructions?: string;
30
+ agent: string;
31
+ workspace: string;
32
+ cwd?: string;
33
+ model?: string;
34
+ effort?: string;
35
+ enabled: boolean;
36
+ /** Monotonic Bot-config generation. Missing on PR2 records; parse defaults to 1. */
37
+ profileRevision: number;
38
+ createdAt: string;
39
+ updatedAt: string;
40
+ }
41
+ export declare function sessionMatchesExecution(session: {
42
+ agent: string;
43
+ workspace: string;
44
+ model?: string;
45
+ effort?: string;
46
+ }, execution: BotProfileExecution): boolean;
47
+ export declare function snapshotBotProfile(bot: BotProfile, capturedAt: string): BotProfileSnapshot;
48
+ interface BotRuntimeBindingBase {
49
+ id: string;
50
+ conversationId: string;
51
+ topicId: string;
52
+ logicalSessionId: string;
53
+ sessionAlias: string;
54
+ createdAt: string;
55
+ updatedAt: string;
56
+ }
57
+ export type BotRuntimeBinding = (BotRuntimeBindingBase & {
58
+ scope: "bot-direct";
59
+ botId: string;
60
+ }) | (BotRuntimeBindingBase & {
61
+ scope: "group-member";
62
+ botId: string;
63
+ }) | (BotRuntimeBindingBase & {
64
+ scope: "group-controller";
65
+ });
66
+ export {};
@@ -7254,12 +7254,12 @@ var init_adapter_catalog = __esm(() => {
7254
7254
  codex: {
7255
7255
  packageName: "@agentclientprotocol/codex-acp",
7256
7256
  binName: "codex-acp",
7257
- defaultVersion: "1.10.0"
7257
+ defaultVersion: "1.12.0"
7258
7258
  },
7259
7259
  claude: {
7260
7260
  packageName: "@agentclientprotocol/claude-agent-acp",
7261
7261
  binName: "claude-agent-acp",
7262
- defaultVersion: "0.75.1"
7262
+ defaultVersion: "0.78.0"
7263
7263
  }
7264
7264
  };
7265
7265
  EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
@@ -14539,8 +14539,9 @@ class RuntimeEngine {
14539
14539
  }
14540
14540
  } else if (event.type === "status") {
14541
14541
  if (event.tag === "plan") {
14542
- sink({ type: "prompt.segment", text: `${event.text}
14543
- ` });
14542
+ const entries = toPromptPlanEntries(event.entries);
14543
+ if (entries)
14544
+ sink({ type: "prompt.plan", entries });
14544
14545
  return;
14545
14546
  }
14546
14547
  if (typeof event.used === "number" && typeof event.size === "number") {
@@ -16255,6 +16256,31 @@ async function buildRuntimeAttachments(media) {
16255
16256
  }
16256
16257
  return attachments;
16257
16258
  }
16259
+ var PROMPT_PLAN_STATUSES = new Set(["pending", "in_progress", "completed"]);
16260
+ var PROMPT_PLAN_PRIORITIES = new Set(["high", "medium", "low"]);
16261
+ function toPromptPlanEntries(value) {
16262
+ if (!Array.isArray(value))
16263
+ return;
16264
+ if (value.length === 0)
16265
+ return [];
16266
+ const entries = [];
16267
+ for (const item of value) {
16268
+ if (typeof item !== "object" || item === null)
16269
+ continue;
16270
+ const record = item;
16271
+ const content = typeof record.content === "string" ? record.content.trim() : "";
16272
+ const status = typeof record.status === "string" ? record.status.trim() : "";
16273
+ if (!content || !PROMPT_PLAN_STATUSES.has(status))
16274
+ continue;
16275
+ const priority = typeof record.priority === "string" ? record.priority.trim() : "";
16276
+ entries.push({
16277
+ content,
16278
+ status,
16279
+ ...PROMPT_PLAN_PRIORITIES.has(priority) ? { priority } : {}
16280
+ });
16281
+ }
16282
+ return entries.length > 0 ? entries : undefined;
16283
+ }
16258
16284
  function mapRuntimeToolEvent(event) {
16259
16285
  const toolCallId = event.toolCallId || `tc-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
16260
16286
  const title = (event.title ?? "").trim();
@@ -5872,12 +5872,12 @@ var init_adapter_catalog = __esm(() => {
5872
5872
  codex: {
5873
5873
  packageName: "@agentclientprotocol/codex-acp",
5874
5874
  binName: "codex-acp",
5875
- defaultVersion: "1.10.0"
5875
+ defaultVersion: "1.12.0"
5876
5876
  },
5877
5877
  claude: {
5878
5878
  packageName: "@agentclientprotocol/claude-agent-acp",
5879
5879
  binName: "claude-agent-acp",
5880
- defaultVersion: "0.75.1"
5880
+ defaultVersion: "0.78.0"
5881
5881
  }
5882
5882
  };
5883
5883
  EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
@@ -7157,6 +7157,7 @@ async function* mapEvents(events) {
7157
7157
  };
7158
7158
  }
7159
7159
  } else if (event.type === "status") {
7160
+ const planEntries = normalizeAdapterPlanEntries(event.entries);
7160
7161
  yield {
7161
7162
  type: "status",
7162
7163
  text: event.text,
@@ -7165,7 +7166,8 @@ async function* mapEvents(events) {
7165
7166
  ...event.size !== undefined ? { size: event.size } : {},
7166
7167
  ...event.cost ? { cost: event.cost } : {},
7167
7168
  ...event.breakdown ? { breakdown: event.breakdown } : {},
7168
- ...event.availableCommands ? { availableCommands: event.availableCommands } : {}
7169
+ ...event.availableCommands ? { availableCommands: event.availableCommands } : {},
7170
+ ...planEntries !== undefined ? { entries: planEntries } : {}
7169
7171
  };
7170
7172
  } else if (event.type === "tool_call") {
7171
7173
  const isInitialToolEvent = typeof event.toolCallId === "string" ? !toolCalls.has(event.toolCallId) : event.tag !== "tool_call_update";
@@ -7188,6 +7190,31 @@ async function* mapEvents(events) {
7188
7190
  }
7189
7191
  }
7190
7192
  }
7193
+ var ADAPTER_PLAN_STATUSES = new Set(["pending", "in_progress", "completed"]);
7194
+ var ADAPTER_PLAN_PRIORITIES = new Set(["high", "medium", "low"]);
7195
+ function normalizeAdapterPlanEntries(value) {
7196
+ if (!Array.isArray(value))
7197
+ return;
7198
+ if (value.length === 0)
7199
+ return [];
7200
+ const entries = [];
7201
+ for (const entry of value) {
7202
+ if (typeof entry !== "object" || entry === null)
7203
+ continue;
7204
+ const record = entry;
7205
+ const content = typeof record.content === "string" ? record.content.trim() : "";
7206
+ const status = typeof record.status === "string" ? record.status.trim() : "";
7207
+ if (!content || !ADAPTER_PLAN_STATUSES.has(status))
7208
+ continue;
7209
+ const priority = typeof record.priority === "string" ? record.priority.trim() : "";
7210
+ entries.push({
7211
+ content,
7212
+ status,
7213
+ ...ADAPTER_PLAN_PRIORITIES.has(priority) ? { priority } : {}
7214
+ });
7215
+ }
7216
+ return entries.length > 0 ? entries : undefined;
7217
+ }
7191
7218
  async function mapResult(result) {
7192
7219
  const settled = await result;
7193
7220
  if (settled.status === "failed") {
package/dist/cli.js CHANGED
@@ -4355,12 +4355,12 @@ var init_adapter_catalog = __esm(() => {
4355
4355
  codex: {
4356
4356
  packageName: "@agentclientprotocol/codex-acp",
4357
4357
  binName: "codex-acp",
4358
- defaultVersion: "1.10.0"
4358
+ defaultVersion: "1.12.0"
4359
4359
  },
4360
4360
  claude: {
4361
4361
  packageName: "@agentclientprotocol/claude-agent-acp",
4362
4362
  binName: "claude-agent-acp",
4363
- defaultVersion: "0.75.1"
4363
+ defaultVersion: "0.78.0"
4364
4364
  }
4365
4365
  };
4366
4366
  EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
@@ -30373,7 +30373,11 @@ function createEmptyState() {
30373
30373
  chat_contexts: {},
30374
30374
  native_session_lists: {},
30375
30375
  orchestration: createEmptyOrchestrationState(),
30376
- scheduled_tasks: {}
30376
+ scheduled_tasks: {},
30377
+ bots: {},
30378
+ conversations: {},
30379
+ conversation_topics: {},
30380
+ bot_runtime_bindings: {}
30377
30381
  };
30378
30382
  }
30379
30383
  var init_types4 = () => {};
@@ -30730,7 +30734,17 @@ function isSessionRecord(value) {
30730
30734
  if (!isRecord4(value)) {
30731
30735
  return false;
30732
30736
  }
30733
- return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && (value.logical_session_id === undefined || isLogicalSessionId(value.logical_session_id)) && isSessionSource(value.source) && isOptionalString(value.agent_session_id) && isOptionalString(value.agent_session_title) && isOptionalString(value.agent_session_updated_at) && isOptionalString(value.attached_at) && isOptionalString(value.transport_agent_command) && isOptionalString(value.transport_acpx_agent) && (value.transport_agent_argv === undefined || isStringArray(value.transport_agent_argv)) && (value.transport_engine === undefined || value.transport_engine === "cli" || value.transport_engine === "runtime") && isOptionalString(value.mode_id) && isOptionalString(value.effort) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
30737
+ return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && (value.logical_session_id === undefined || isLogicalSessionId(value.logical_session_id)) && isSessionSource(value.source) && isOptionalString(value.agent_session_id) && isOptionalString(value.agent_session_title) && isOptionalString(value.agent_session_updated_at) && isOptionalString(value.attached_at) && isOptionalString(value.transport_agent_command) && isOptionalString(value.transport_acpx_agent) && (value.transport_agent_argv === undefined || isStringArray(value.transport_agent_argv)) && (value.transport_engine === undefined || value.transport_engine === "cli" || value.transport_engine === "runtime") && isOptionalString(value.mode_id) && isOptionalString(value.effort) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at) && (value.owner === undefined || isLogicalSessionOwner(value.owner));
30738
+ }
30739
+ function isLogicalSessionOwner(value) {
30740
+ if (!isRecord4(value)) {
30741
+ return false;
30742
+ }
30743
+ if (value.kind !== "bot-direct" && value.kind !== "group-member" && value.kind !== "group-controller" || !isString(value.bindingId) || value.bindingId.length === 0) {
30744
+ return false;
30745
+ }
30746
+ const optional3 = (field) => value[field] === undefined || isString(value[field]) && value[field].length > 0;
30747
+ return optional3("botId") && optional3("conversationId") && optional3("topicId");
30734
30748
  }
30735
30749
  function parseSessions(raw, dropped, migrated) {
30736
30750
  const sessions = {};
@@ -30822,6 +30836,108 @@ function parseScheduledTasks(raw, dropped) {
30822
30836
  }
30823
30837
  return tasks;
30824
30838
  }
30839
+ function isBotProfile(value) {
30840
+ if (!isRecord4(value)) {
30841
+ return false;
30842
+ }
30843
+ return isString(value.id) && isString(value.name) && isOptionalString(value.avatar) && isOptionalString(value.role) && isOptionalString(value.instructions) && isString(value.agent) && isString(value.workspace) && isOptionalString(value.cwd) && isOptionalString(value.model) && isOptionalString(value.effort) && typeof value.enabled === "boolean" && (value.profileRevision === undefined || typeof value.profileRevision === "number" && Number.isInteger(value.profileRevision) && value.profileRevision >= 1) && isString(value.createdAt) && isString(value.updatedAt);
30844
+ }
30845
+ function parseBotProfiles(raw, dropped) {
30846
+ const source = sectionRecord(raw, "bots", dropped);
30847
+ const bots = {};
30848
+ for (const [id, value] of Object.entries(source)) {
30849
+ if (!isBotProfile(value) || value.id !== id) {
30850
+ dropped.push({ section: "bots", key: id, reason: "malformed bot profile" });
30851
+ continue;
30852
+ }
30853
+ bots[id] = {
30854
+ ...value,
30855
+ profileRevision: value.profileRevision ?? 1
30856
+ };
30857
+ }
30858
+ return bots;
30859
+ }
30860
+ function isUniqueStringArray(value) {
30861
+ return isStringArray(value) && new Set(value).size === value.length;
30862
+ }
30863
+ function isConversationRecord(value) {
30864
+ if (!isRecord4(value)) {
30865
+ return false;
30866
+ }
30867
+ if (!isString(value.id) || !isString(value.title) || !isOptionalString(value.description) || !isUniqueStringArray(value.botIds) || !isOptionalString(value.leadBotId) || !isString(value.createdAt) || !isString(value.updatedAt)) {
30868
+ return false;
30869
+ }
30870
+ if (value.lifecycle !== undefined && value.lifecycle !== "active" && value.lifecycle !== "deleting") {
30871
+ return false;
30872
+ }
30873
+ if (value.leadBotId !== undefined && !value.botIds.includes(value.leadBotId)) {
30874
+ return false;
30875
+ }
30876
+ if (value.kind === "bot") {
30877
+ return value.botIds.length === 1;
30878
+ }
30879
+ if (value.kind === "group") {
30880
+ return value.botIds.length >= 2;
30881
+ }
30882
+ return false;
30883
+ }
30884
+ function parseConversations(raw, dropped) {
30885
+ const source = sectionRecord(raw, "conversations", dropped);
30886
+ const conversations = {};
30887
+ for (const [id, value] of Object.entries(source)) {
30888
+ if (!isConversationRecord(value) || value.id !== id) {
30889
+ dropped.push({ section: "conversations", key: id, reason: "malformed conversation record" });
30890
+ continue;
30891
+ }
30892
+ conversations[id] = value;
30893
+ }
30894
+ return conversations;
30895
+ }
30896
+ function isConversationTopic(value) {
30897
+ if (!isRecord4(value)) {
30898
+ return false;
30899
+ }
30900
+ return isString(value.id) && isString(value.conversationId) && isString(value.title) && (value.status === "active" || value.status === "archived" || value.status === "deleting") && isString(value.createdAt) && isString(value.updatedAt);
30901
+ }
30902
+ function parseConversationTopics(raw, dropped) {
30903
+ const source = sectionRecord(raw, "conversation_topics", dropped);
30904
+ const topics = {};
30905
+ for (const [id, value] of Object.entries(source)) {
30906
+ if (!isConversationTopic(value) || value.id !== id) {
30907
+ dropped.push({ section: "conversation_topics", key: id, reason: "malformed conversation topic" });
30908
+ continue;
30909
+ }
30910
+ topics[id] = value;
30911
+ }
30912
+ return topics;
30913
+ }
30914
+ function isBotRuntimeBinding(value) {
30915
+ if (!isRecord4(value)) {
30916
+ return false;
30917
+ }
30918
+ if (!isString(value.id) || !isString(value.conversationId) || !isString(value.topicId) || !isString(value.logicalSessionId) || !isString(value.sessionAlias) || !isString(value.createdAt) || !isString(value.updatedAt)) {
30919
+ return false;
30920
+ }
30921
+ if (value.scope === "bot-direct" || value.scope === "group-member") {
30922
+ return isString(value.botId) && value.botId.length > 0;
30923
+ }
30924
+ if (value.scope === "group-controller") {
30925
+ return value.botId === undefined;
30926
+ }
30927
+ return false;
30928
+ }
30929
+ function parseBotRuntimeBindings(raw, dropped) {
30930
+ const source = sectionRecord(raw, "bot_runtime_bindings", dropped);
30931
+ const bindings = {};
30932
+ for (const [id, value] of Object.entries(source)) {
30933
+ if (!isBotRuntimeBinding(value) || value.id !== id) {
30934
+ dropped.push({ section: "bot_runtime_bindings", key: id, reason: "malformed bot runtime binding" });
30935
+ continue;
30936
+ }
30937
+ bindings[id] = value;
30938
+ }
30939
+ return bindings;
30940
+ }
30825
30941
  function parseState(raw, path3, dropped = [], migrated = []) {
30826
30942
  if (!isRecord4(raw)) {
30827
30943
  throw new Error(`state file "${path3}" must contain a JSON object`);
@@ -30834,7 +30950,11 @@ function parseState(raw, path3, dropped = [], migrated = []) {
30834
30950
  chat_contexts: parseChatContexts(sectionRecord(raw.chat_contexts, "chat_contexts", dropped), dropped),
30835
30951
  native_session_lists: parseNativeSessionLists(raw.native_session_lists),
30836
30952
  orchestration: orchestration3,
30837
- scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, dropped)
30953
+ scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, dropped),
30954
+ bots: parseBotProfiles(raw.bots, dropped),
30955
+ conversations: parseConversations(raw.conversations, dropped),
30956
+ conversation_topics: parseConversationTopics(raw.conversation_topics, dropped),
30957
+ bot_runtime_bindings: parseBotRuntimeBindings(raw.bot_runtime_bindings, dropped)
30838
30958
  };
30839
30959
  }
30840
30960
  function repairExternalCoordinatorIdentityCollisions(sessions, orchestration3, dropped) {
@@ -42471,6 +42591,7 @@ function lockForPhysicalKey(physicalKey) {
42471
42591
  }
42472
42592
  async function removeAliasWithPhysicalLifecycle(options) {
42473
42593
  const { sessions, transport, session: session3, internalAlias } = options;
42594
+ const policy = options.physicalFailurePolicy ?? "legacy-cli-best-effort";
42474
42595
  const groupKey = physicalLifecycleKeyForResolvedSession(session3);
42475
42596
  const isRuntime = session3.transportEngine === "runtime";
42476
42597
  return lockForPhysicalKey(groupKey).run(async () => {
@@ -42500,9 +42621,14 @@ async function removeAliasWithPhysicalLifecycle(options) {
42500
42621
  await transport.deleteSession(session3);
42501
42622
  action = "deleted";
42502
42623
  } catch (error2) {
42624
+ if (policy === "strict") {
42625
+ throw error2;
42626
+ }
42503
42627
  transportTeardownWarning = error2 instanceof Error ? error2.message : String(error2);
42504
42628
  action = "logical-only";
42505
42629
  }
42630
+ } else if (remaining === 0 && policy === "strict") {
42631
+ throw new Error(`cannot hard-delete last CLI alias "${internalAlias}": transport has no deleteSession operation`);
42506
42632
  } else {
42507
42633
  action = "logical-only";
42508
42634
  }
@@ -54938,6 +55064,10 @@ function replaceRuntimeState(target, source) {
54938
55064
  target.chat_contexts = source.chat_contexts;
54939
55065
  target.orchestration = source.orchestration;
54940
55066
  target.scheduled_tasks = source.scheduled_tasks;
55067
+ target.bots = source.bots;
55068
+ target.conversations = source.conversations;
55069
+ target.conversation_topics = source.conversation_topics;
55070
+ target.bot_runtime_bindings = source.bot_runtime_bindings;
54941
55071
  }
54942
55072
 
54943
55073
  // src/sessions/transport-engine.ts
@@ -55139,8 +55269,8 @@ class SessionService {
55139
55269
  ...this.permissionInteractionCapable !== undefined ? { permissionInteractionCapable: this.permissionInteractionCapable } : {}
55140
55270
  }).engine;
55141
55271
  }
55142
- async createSession(alias, agent3, workspace3) {
55143
- return await this.createLogicalSession(alias, agent3, workspace3, `${workspace3}:${alias}`);
55272
+ async createSession(alias, agent3, workspace3, options) {
55273
+ return await this.createLogicalSession(alias, agent3, workspace3, `${workspace3}:${alias}`, undefined, undefined, undefined, undefined, options);
55144
55274
  }
55145
55275
  listAllResolvedSessions() {
55146
55276
  const seen = new Set;
@@ -55547,6 +55677,9 @@ class SessionService {
55547
55677
  getLogicalSessionRecord(alias) {
55548
55678
  return this.state.sessions[alias] ?? null;
55549
55679
  }
55680
+ getLogicalSessionById(logicalSessionId) {
55681
+ return Object.values(this.state.sessions).find((session3) => session3.logical_session_id === logicalSessionId) ?? null;
55682
+ }
55550
55683
  listLogicalSessionRecords() {
55551
55684
  return Object.values(this.state.sessions);
55552
55685
  }
@@ -56166,7 +56299,7 @@ class SessionService {
56166
56299
  }
56167
56300
  return input.sameAgentExistingEngine ?? siblingEngine ?? input.fallback();
56168
56301
  }
56169
- async createLogicalSession(alias, agent3, workspace3, transportSession, transportAgentCommand, native, transportAcpxAgent, transportAgentArgv) {
56302
+ async createLogicalSession(alias, agent3, workspace3, transportSession, transportAgentCommand, native, transportAcpxAgent, transportAgentArgv, extras) {
56170
56303
  return await this.mutate(async () => {
56171
56304
  this.validateSession(alias, agent3, workspace3);
56172
56305
  if (Object.keys(this.state.orchestration.externalCoordinators).some((coordinatorSession) => sameCoordinatorSession(coordinatorSession, transportSession))) {
@@ -56191,8 +56324,8 @@ class SessionService {
56191
56324
  ...transportAcpxAgent ? { transport_acpx_agent: transportAcpxAgent } : sameAgentExisting?.transport_acpx_agent ? { transport_acpx_agent: sameAgentExisting.transport_acpx_agent } : {},
56192
56325
  ...transportAgentArgv && transportAgentArgv.length > 0 ? { transport_agent_argv: [...transportAgentArgv] } : sameAgentExisting?.transport_agent_argv ? { transport_agent_argv: [...sameAgentExisting.transport_agent_argv] } : {},
56193
56326
  mode_id: sameAgentExisting?.mode_id,
56194
- model: sameAgentExisting?.model,
56195
- effort: sameAgentExisting?.effort,
56327
+ model: extras?.model ?? sameAgentExisting?.model,
56328
+ effort: extras?.effort ?? sameAgentExisting?.effort,
56196
56329
  reply_mode: sameAgentExisting?.reply_mode,
56197
56330
  display_name: sameAgentExisting?.display_name,
56198
56331
  transport_engine: this.resolveEngineWithPhysicalInheritance({
@@ -56206,7 +56339,8 @@ class SessionService {
56206
56339
  ...sameAgentExisting ? { sameAgentExisting } : {}
56207
56340
  }),
56208
56341
  created_at: existingSession?.created_at ?? now,
56209
- last_used_at: now
56342
+ last_used_at: now,
56343
+ ...extras?.owner ? { owner: extras.owner } : {}
56210
56344
  };
56211
56345
  const nextState = structuredClone(this.state);
56212
56346
  nextState.sessions[alias] = session3;
@@ -63016,6 +63150,7 @@ ${envelope}` : envelope;
63016
63150
  return {
63017
63151
  ok: false,
63018
63152
  errorMessage,
63153
+ ...!timedOut && signal.aborted ? { cancelled: true } : {},
63019
63154
  ...internalAlias && priorTransportSession ? { postTurnDetection: { internalAlias, priorTransportSession } } : {}
63020
63155
  };
63021
63156
  }
@@ -63440,10 +63575,13 @@ class TurnQueue {
63440
63575
  return {
63441
63576
  ok: result.ok,
63442
63577
  ...result.text !== undefined ? { text: result.text } : {},
63443
- ...result.errorMessage !== undefined ? { errorMessage: result.errorMessage } : {}
63578
+ ...result.errorMessage !== undefined ? { errorMessage: result.errorMessage } : {},
63579
+ ...result.cancelled ? { cancelled: true } : {}
63444
63580
  };
63445
63581
  }
63446
63582
  advanceQueue(key) {
63583
+ const finished = this.inFlight.get(key);
63584
+ this.recordSettledRequestId(finished?.promptRequestId);
63447
63585
  const interrupt = this.pendingInterrupts.get(key);
63448
63586
  if (interrupt) {
63449
63587
  this.pendingInterrupts.delete(key);
@@ -63498,6 +63636,26 @@ class TurnQueue {
63498
63636
  entry.controller.abort();
63499
63637
  return true;
63500
63638
  }
63639
+ cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId, concurrencyKey) {
63640
+ const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
63641
+ const entry = this.inFlight.get(key);
63642
+ if (!entry || entry.promptRequestId !== promptRequestId) {
63643
+ return false;
63644
+ }
63645
+ entry.controller.abort();
63646
+ return true;
63647
+ }
63648
+ inspectPromptRequest(chatKey, sessionAlias, promptRequestId, concurrencyKey) {
63649
+ const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
63650
+ const entry = this.inFlight.get(key);
63651
+ if (entry?.promptRequestId === promptRequestId) {
63652
+ return "in-flight";
63653
+ }
63654
+ if (this.hasSettledRequestId(promptRequestId)) {
63655
+ return "settled";
63656
+ }
63657
+ return "absent";
63658
+ }
63501
63659
  async clearSession(chatKey, sessionAlias, concurrencyKey) {
63502
63660
  const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
63503
63661
  const guardPreexisting = this.removing.has(key);
@@ -64084,26 +64242,40 @@ class ControlService {
64084
64242
  return task;
64085
64243
  }
64086
64244
  async prompt(input) {
64245
+ return this.submitHumanPrompt(input, true);
64246
+ }
64247
+ async promptImmediate(input) {
64248
+ return this.submitHumanPrompt(input, false);
64249
+ }
64250
+ submitHumanPrompt(input, queueable) {
64087
64251
  const channelId = getChannelIdFromChatKey(input.chatKey);
64088
64252
  const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(input.sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, input.sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, input.sessionAlias);
64089
64253
  const configTail = this.sessionConfigSetTails.get(internalAlias) ?? this.sessionConfigSetTails.get(input.sessionAlias);
64254
+ const turnOrigin = queueable ? "human" : input.executionOrigin === "human" ? "human" : "orchestration";
64255
+ const submit = () => {
64256
+ if (input.abortSignal?.aborted) {
64257
+ return Promise.resolve({ ok: false, cancelled: true, errorMessage: "cancelled" });
64258
+ }
64259
+ return this.turnQueue.submit({
64260
+ chatKey: input.chatKey,
64261
+ sessionAlias: input.sessionAlias,
64262
+ concurrencyKey: internalAlias,
64263
+ text: input.text,
64264
+ senderId: input.senderId,
64265
+ turnOrigin,
64266
+ queueable,
64267
+ ...input.isOwner !== undefined ? { isOwner: input.isOwner } : {},
64268
+ ...input.accountId !== undefined ? { accountId: input.accountId } : {},
64269
+ ...input.media !== undefined ? { media: input.media } : {},
64270
+ ...input.agentMentions !== undefined ? { agentMentions: input.agentMentions } : {},
64271
+ ...input.promptRequestId !== undefined ? { promptRequestId: input.promptRequestId } : {},
64272
+ ...input.abortSignal !== undefined ? { abortSignal: input.abortSignal } : {}
64273
+ });
64274
+ };
64090
64275
  if (configTail) {
64091
- await configTail.catch(() => {});
64276
+ return configTail.catch(() => {}).then(submit);
64092
64277
  }
64093
- return this.turnQueue.submit({
64094
- chatKey: input.chatKey,
64095
- sessionAlias: input.sessionAlias,
64096
- concurrencyKey: internalAlias,
64097
- text: input.text,
64098
- senderId: input.senderId,
64099
- turnOrigin: "human",
64100
- queueable: true,
64101
- ...input.isOwner !== undefined ? { isOwner: input.isOwner } : {},
64102
- ...input.accountId !== undefined ? { accountId: input.accountId } : {},
64103
- ...input.media !== undefined ? { media: input.media } : {},
64104
- ...input.agentMentions !== undefined ? { agentMentions: input.agentMentions } : {},
64105
- ...input.promptRequestId !== undefined ? { promptRequestId: input.promptRequestId } : {}
64106
- });
64278
+ return submit();
64107
64279
  }
64108
64280
  async runScheduledTurn(input) {
64109
64281
  const channelId = getChannelIdFromChatKey(input.chatKey);
@@ -64142,6 +64314,16 @@ class ControlService {
64142
64314
  const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
64143
64315
  return this.turnQueue.cancelTurn(chatKey, sessionAlias, internalAlias);
64144
64316
  }
64317
+ cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId) {
64318
+ const channelId = getChannelIdFromChatKey(chatKey);
64319
+ const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
64320
+ return this.turnQueue.cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId, internalAlias);
64321
+ }
64322
+ inspectPromptRequest(chatKey, sessionAlias, promptRequestId) {
64323
+ const channelId = getChannelIdFromChatKey(chatKey);
64324
+ const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
64325
+ return this.turnQueue.inspectPromptRequest(chatKey, sessionAlias, promptRequestId, internalAlias);
64326
+ }
64145
64327
  async submitPeerTurn(input) {
64146
64328
  const channelId = getChannelIdFromChatKey(input.chatKey);
64147
64329
  const internalAlias = input.boundSessionAlias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(input.sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, input.sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, input.sessionAlias);
@@ -1,5 +1,6 @@
1
1
  import type { SessionService } from "../sessions/session-service";
2
2
  import type { ResolvedSession, SessionTransport } from "../transport/types";
3
+ export type PhysicalFailurePolicy = "legacy-cli-best-effort" | "strict";
3
4
  export interface PhysicalRemoveOutcome {
4
5
  wasActive: boolean;
5
6
  /**
@@ -26,6 +27,14 @@ export declare function removeAliasWithPhysicalLifecycle(options: {
26
27
  transport: Pick<SessionTransport, "releaseLogicalSession" | "deleteSession">;
27
28
  session: ResolvedSession;
28
29
  internalAlias: string;
30
+ /**
31
+ * Default `legacy-cli-best-effort` keeps `/session rm` semantics: a CLI
32
+ * last-owner `deleteSession` failure records a warning and still removes
33
+ * the LogicalSession. `strict` is the Bot/Conversation owned-session
34
+ * path: any Runtime or CLI physical failure throws BEFORE the logical row
35
+ * disappears so callers keep the retry handle.
36
+ */
37
+ physicalFailurePolicy?: PhysicalFailurePolicy;
29
38
  }): Promise<PhysicalRemoveOutcome>;
30
39
  export interface ProvisionalSessionCleanup {
31
40
  sessions: SessionService;
@@ -71,7 +71,7 @@ export interface TransportConfig {
71
71
  */
72
72
  turnIdleTimeoutSeconds?: number;
73
73
  /**
74
- * Advanced acpx embedding-host ceilings (acpx 0.15.1, plan B5).
74
+ * Advanced acpx embedding-host ceilings (acpx 0.15.1+, plan B5).
75
75
  * `acpxMaxIncomingMessageBytes` overrides the 64 MiB default ceiling on
76
76
  * agent → acpx inbound ACP messages (`0` = unlimited — avoid unless a real
77
77
  * workload needs it); `acpxTerminalMaxOutputBytes` caps retained
@@ -7,6 +7,7 @@ import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
7
7
  import type { CancelTaskInput, OrchestrationService, OrchestrationTaskFilter } from "../orchestration/orchestration-service";
8
8
  import type { OrchestrationTaskRecord } from "../orchestration/orchestration-types";
9
9
  import type { AgentMessageCompletion, AgentMessageMode } from "../orchestration/agent-messaging-types";
10
+ import type { PermissionInteractionOrigin } from "../permissions/permission-types.js";
10
11
  import type { ControlEventBus } from "./control-event-bus";
11
12
  import type { AgentCatalogEntry } from "../config/agent-catalog";
12
13
  import { type BrowseDirsResult, type DirListing, type FileContent, type SearchOptions, type SearchResult, type WorkspaceDiff } from "./workspace-fs";
@@ -221,11 +222,23 @@ export interface ControlPromptInput {
221
222
  * turn-started so the hub can tie a queued prompt back to its pre-written inbound
222
223
  * row (see PromptPayload.promptRequestId). */
223
224
  promptRequestId?: string;
225
+ /** Conversation pre-admission cancel. Checked after any config-tail wait and
226
+ * immediately before TurnQueue.submit so a cancelled Run never starts. */
227
+ abortSignal?: AbortSignal;
228
+ /**
229
+ * Conversation execution provenance, derived by ConversationStore at claim
230
+ * from the live authority epoch. `promptImmediate` fail-closes to
231
+ * orchestration unless this is exactly `"human"`. Interactive `prompt()`
232
+ * ignores it and is always human. Omitting it cannot mint human authority.
233
+ */
234
+ executionOrigin?: PermissionInteractionOrigin;
224
235
  }
225
236
  export interface ControlPromptResult {
226
237
  ok: boolean;
227
238
  text?: string;
228
239
  errorMessage?: string;
240
+ /** Proven cancellation (AbortSignal / user Stop), not an error string match. */
241
+ cancelled?: boolean;
229
242
  /** True when this prompt did not run immediately and was instead appended to the
230
243
  * per-session server-side queue (a turn was already in flight). */
231
244
  queued?: boolean;
@@ -386,6 +399,14 @@ export declare class ControlService {
386
399
  getOrchestrationTask(taskId: string): Promise<OrchestrationTaskRecord | null>;
387
400
  cancelOrchestrationTask(input: CancelTaskInput): Promise<OrchestrationTaskRecord>;
388
401
  prompt(input: ControlPromptInput): Promise<ControlPromptResult>;
402
+ /**
403
+ * Conversation execution seam: same TurnQueue / SessionTurnRunner path as
404
+ * `prompt()`, but never FIFO-enqueues when the session lane is busy.
405
+ * Turn origin is the store-derived `executionOrigin` (fail-closed to
406
+ * orchestration). ConversationStore already owns durable queuing.
407
+ */
408
+ promptImmediate(input: ControlPromptInput): Promise<ControlPromptResult>;
409
+ private submitHumanPrompt;
389
410
  /** Run a fired scheduled task as a real turn through the same machinery as a manual
390
411
  * prompt — so it streams live and persists to history — while tagging turn-started
391
412
  * with the prompt text + schedule origin so the hub records the inbound message and
@@ -395,6 +416,8 @@ export declare class ControlService {
395
416
  isBusy(chatKey: string, sessionAlias: string): boolean;
396
417
  isSessionBusy(internalAlias: string): boolean;
397
418
  cancelTurn(chatKey: string, sessionAlias: string): boolean;
419
+ cancelTurnForPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string): boolean;
420
+ inspectPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string): "in-flight" | "settled" | "absent";
398
421
  submitPeerTurn(input: {
399
422
  chatKey: string;
400
423
  sessionAlias: string;
@@ -36,6 +36,8 @@ export interface TurnResult {
36
36
  ok: boolean;
37
37
  text?: string;
38
38
  errorMessage?: string;
39
+ /** Proven user-Stop / abort cancellation. Idle-timeout aborts omit this. */
40
+ cancelled?: boolean;
39
41
  postTurnDetection?: {
40
42
  internalAlias: string;
41
43
  priorTransportSession: string;
@@ -150,6 +150,14 @@ export declare class TurnQueue {
150
150
  private advanceQueue;
151
151
  private drainQueuedPrompt;
152
152
  cancelTurn(chatKey: string, sessionAlias: string, concurrencyKey?: string): boolean;
153
+ /**
154
+ * Abort the in-flight turn only when it is the given promptRequestId.
155
+ * A minted Conversation correlation id is not a lane-wide cancel: a later
156
+ * prompt on the same session must not be aborted, and a settled request
157
+ * must not be treated as cancelled just because Stop was pressed late.
158
+ */
159
+ cancelTurnForPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string, concurrencyKey?: string): boolean;
160
+ inspectPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string, concurrencyKey?: string): "in-flight" | "settled" | "absent";
153
161
  /** Tear down all turn state for a session that is being removed or archived: drop every
154
162
  * queued prompt, abort a running turn, and wait (bounded) for it to unwind. The queue is
155
163
  * cleared BEFORE the abort so the aborting turn's finally sees it empty and releases the
@@ -0,0 +1,117 @@
1
+ import type { BotProfileSnapshot } from "../bots/bot-types";
2
+ export type ConversationKind = "bot" | "group";
3
+ export type ConversationLifecycle = "active" | "deleting";
4
+ export type ConversationTopicStatus = "active" | "archived" | "deleting";
5
+ export type ConversationMessageRole = "human" | "bot" | "system";
6
+ export type GroupTurnOrigin = "human-explicit" | "controller" | "handoff" | "recovery";
7
+ export type GroupTurnState = "queued" | "running" | "completed" | "failed" | "cancelled";
8
+ export type ConversationRunMode = "explicit";
9
+ export type ConversationRunState = "queued" | "running" | "waiting-human" | "completed" | "failed" | "cancelled" | "indeterminate";
10
+ export type MemberTurnOrigin = "human" | "followup" | "retry" | "recovery";
11
+ export type MemberTurnState = "queued" | "dispatched" | "running" | "completed" | "failed" | "cancelled" | "indeterminate";
12
+ export type PendingDispatchState = "pending" | "claimed" | "completed";
13
+ export interface ConversationRecord {
14
+ id: string;
15
+ kind: ConversationKind;
16
+ title: string;
17
+ description?: string;
18
+ botIds: string[];
19
+ leadBotId?: string;
20
+ /** Bounded AppState lifecycle flag. SQLite conversation_lifecycle is authoritative for dispatch. */
21
+ lifecycle?: ConversationLifecycle;
22
+ createdAt: string;
23
+ updatedAt: string;
24
+ }
25
+ export interface ConversationTopic {
26
+ id: string;
27
+ conversationId: string;
28
+ title: string;
29
+ status: ConversationTopicStatus;
30
+ createdAt: string;
31
+ updatedAt: string;
32
+ }
33
+ export interface ConversationMessage {
34
+ id: string;
35
+ conversationId: string;
36
+ topicId: string;
37
+ seq: number;
38
+ role: ConversationMessageRole;
39
+ senderBotId?: string;
40
+ recipients?: string[];
41
+ content: string;
42
+ replyTo?: string;
43
+ runId?: string;
44
+ createdAt: string;
45
+ sourceTurn?: {
46
+ sessionAlias: string;
47
+ turnId?: string;
48
+ };
49
+ }
50
+ export interface ConversationRun {
51
+ id: string;
52
+ conversationId: string;
53
+ topicId: string;
54
+ requestMessageId: string;
55
+ requestId: string;
56
+ mode: ConversationRunMode;
57
+ state: ConversationRunState;
58
+ completionReason?: string;
59
+ generation: number;
60
+ maxMemberTurns: number;
61
+ consumedMemberTurns: number;
62
+ profileRevision: number;
63
+ profileSnapshot: BotProfileSnapshot;
64
+ createdAt: string;
65
+ startedAt?: string;
66
+ finishedAt?: string;
67
+ }
68
+ export interface MemberTurnRecord {
69
+ id: string;
70
+ runId: string;
71
+ conversationId: string;
72
+ topicId: string;
73
+ botId: string;
74
+ sessionAlias?: string;
75
+ logicalSessionId?: string;
76
+ sourceTurnId?: string;
77
+ queueItemId?: string;
78
+ batch: number;
79
+ attempt: number;
80
+ origin: MemberTurnOrigin;
81
+ state: MemberTurnState;
82
+ triggerMessageIds: string[];
83
+ createdAt: string;
84
+ startedAt?: string;
85
+ finishedAt?: string;
86
+ }
87
+ export interface PendingDispatch {
88
+ id: string;
89
+ runId: string;
90
+ memberTurnId: string;
91
+ generation: number;
92
+ state: PendingDispatchState;
93
+ owner?: string;
94
+ leaseExpiresAt?: string;
95
+ /** Live dispatcher epoch that accepted this work. Matching claim keeps human
96
+ * permission authority; mismatch or revoked epoch is recovery/orchestration. */
97
+ authorityEpoch?: string;
98
+ createdAt: string;
99
+ claimedAt?: string;
100
+ completedAt?: string;
101
+ }
102
+ export interface GroupTurnRecord {
103
+ id: string;
104
+ conversationId: string;
105
+ topicId: string;
106
+ botId: string;
107
+ sessionAlias: string;
108
+ triggerMessageIds: string[];
109
+ origin: GroupTurnOrigin;
110
+ state: GroupTurnState;
111
+ createdAt: string;
112
+ startedAt?: string;
113
+ finishedAt?: string;
114
+ }
115
+ export declare const ACTIVE_RUN_STATES: readonly ConversationRunState[];
116
+ export declare const TERMINAL_RUN_STATES: readonly ConversationRunState[];
117
+ export declare const TERMINAL_MEMBER_STATES: readonly MemberTurnState[];
@@ -1,7 +1,7 @@
1
1
  import type { AppConfig } from "../config/types";
2
2
  import { AsyncMutex } from "../orchestration/async-mutex";
3
3
  import type { StateStore } from "../state/state-store";
4
- import type { AppState, BackgroundResult, LogicalSession, SessionTransportEngine } from "../state/types";
4
+ import type { AppState, BackgroundResult, LogicalSession, LogicalSessionOwner, SessionTransportEngine } from "../state/types";
5
5
  import type { SessionResourceLifecyclePublishInput } from "./session-resource-catalog";
6
6
  import type { AgentSession, ResolvedSession } from "../transport/types";
7
7
  import type { ReapTarget } from "../transport/queue-owner-reaper";
@@ -125,7 +125,11 @@ export declare class SessionService {
125
125
  agent: string;
126
126
  workspace: string;
127
127
  }): SessionTransportEngine;
128
- createSession(alias: string, agent: string, workspace: string): Promise<ResolvedSession>;
128
+ createSession(alias: string, agent: string, workspace: string, options?: {
129
+ owner?: LogicalSessionOwner;
130
+ model?: string;
131
+ effort?: string;
132
+ }): Promise<ResolvedSession>;
129
133
  /**
130
134
  * All currently-known logical sessions resolved to transport sessions, deduped by
131
135
  * the composite identity acpx keys its session records on (agent + agent command +
@@ -250,6 +254,7 @@ export declare class SessionService {
250
254
  * does not carry (immutable logical_session_id, archived flag).
251
255
  */
252
256
  getLogicalSessionRecord(alias: string): LogicalSession | null;
257
+ getLogicalSessionById(logicalSessionId: string): LogicalSession | null;
253
258
  /** Read-only view of every persisted logical session record, across all channels. */
254
259
  listLogicalSessionRecords(): LogicalSession[];
255
260
  setCurrentSessionMode(chatKey: string, modeId: string | undefined): Promise<void>;
@@ -1,7 +1,26 @@
1
+ import type { BotProfile, BotRuntimeBinding } from "../bots/bot-types";
2
+ import type { ConversationRecord, ConversationTopic } from "../conversations/conversation-types";
1
3
  import { type OrchestrationState } from "../orchestration/orchestration-types";
2
4
  import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
3
5
  export type SessionTransportEngine = "cli" | "runtime";
4
6
  export type LogicalSessionSource = "xacpx" | "agent-side";
7
+ export interface LogicalSessionOwner {
8
+ kind: "bot-direct" | "group-member" | "group-controller";
9
+ bindingId: string;
10
+ /**
11
+ * Explicit Bot id for scoped bot-direct ownership. Optional on PR2 records
12
+ * that only stored `bindingId` (the legacy deterministic default-Topic id).
13
+ */
14
+ botId?: string;
15
+ conversationId?: string;
16
+ topicId?: string;
17
+ }
18
+ export declare function createBotDirectOwner(input: {
19
+ bindingId: string;
20
+ botId: string;
21
+ conversationId: string;
22
+ topicId: string;
23
+ }): LogicalSessionOwner;
5
24
  export interface NativeSessionCacheEntry {
6
25
  session_id: string;
7
26
  cwd?: string;
@@ -59,6 +78,7 @@ export interface LogicalSession {
59
78
  archived_at?: string;
60
79
  created_at: string;
61
80
  last_used_at: string;
81
+ owner?: LogicalSessionOwner;
62
82
  }
63
83
  export interface BackgroundResult {
64
84
  text: string;
@@ -76,5 +96,9 @@ export interface AppState {
76
96
  native_session_lists: Record<string, NativeSessionListCacheRecord>;
77
97
  orchestration: OrchestrationState;
78
98
  scheduled_tasks: Record<string, ScheduledTaskRecord>;
99
+ bots: Record<string, BotProfile>;
100
+ conversations: Record<string, ConversationRecord>;
101
+ conversation_topics: Record<string, ConversationTopic>;
102
+ bot_runtime_bindings: Record<string, BotRuntimeBinding>;
79
103
  }
80
104
  export declare function createEmptyState(): AppState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganglion/xacpx",
3
- "version": "0.24.5-beta.0",
3
+ "version": "0.24.6-beta.0",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",
@@ -86,12 +86,13 @@
86
86
  "test:unit": "node ./scripts/run-tests.mjs tests/unit",
87
87
  "test:smoke": "node ./scripts/run-tests.mjs tests/smoke",
88
88
  "test:compat:acpx": "node ./scripts/run-tests.mjs tests/compat",
89
+ "test:release-boundary": "node ./scripts/release-plan-boundary.mjs",
89
90
  "lint:acpx-imports": "node ./scripts/lint-acpx-imports.mjs",
90
91
  "smoke:local-install": "node ./scripts/smoke-local-install.mjs"
91
92
  },
92
93
  "dependencies": {
93
94
  "@modelcontextprotocol/sdk": "^1.29.0",
94
- "acpx": "0.15.1",
95
+ "acpx": "0.16.0",
95
96
  "node-pty": "^1.1.0",
96
97
  "proper-lockfile": "^4.1.2",
97
98
  "protobufjs": "^7.5.6",