@ganglion/xacpx 0.24.5-beta.0 → 0.24.5

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.
@@ -0,0 +1,35 @@
1
+ export type BotRuntimeScope = "bot-direct" | "group-member" | "group-controller";
2
+ export interface BotProfile {
3
+ id: string;
4
+ name: string;
5
+ avatar?: string;
6
+ role?: string;
7
+ instructions?: string;
8
+ agent: string;
9
+ workspace: string;
10
+ cwd?: string;
11
+ model?: string;
12
+ effort?: string;
13
+ enabled: boolean;
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ }
17
+ interface BotRuntimeBindingBase {
18
+ id: string;
19
+ conversationId: string;
20
+ topicId: string;
21
+ logicalSessionId: string;
22
+ sessionAlias: string;
23
+ createdAt: string;
24
+ updatedAt: string;
25
+ }
26
+ export type BotRuntimeBinding = (BotRuntimeBindingBase & {
27
+ scope: "bot-direct";
28
+ botId: string;
29
+ }) | (BotRuntimeBindingBase & {
30
+ scope: "group-member";
31
+ botId: string;
32
+ }) | (BotRuntimeBindingBase & {
33
+ scope: "group-controller";
34
+ });
35
+ export {};
package/dist/cli.js CHANGED
@@ -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,13 @@ 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
+ return (value.kind === "bot-direct" || value.kind === "group-member" || value.kind === "group-controller") && isString(value.bindingId) && value.bindingId.length > 0;
30734
30744
  }
30735
30745
  function parseSessions(raw, dropped, migrated) {
30736
30746
  const sessions = {};
@@ -30822,6 +30832,102 @@ function parseScheduledTasks(raw, dropped) {
30822
30832
  }
30823
30833
  return tasks;
30824
30834
  }
30835
+ function isBotProfile(value) {
30836
+ if (!isRecord4(value)) {
30837
+ return false;
30838
+ }
30839
+ 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" && isString(value.createdAt) && isString(value.updatedAt);
30840
+ }
30841
+ function parseBotProfiles(raw, dropped) {
30842
+ const source = sectionRecord(raw, "bots", dropped);
30843
+ const bots = {};
30844
+ for (const [id, value] of Object.entries(source)) {
30845
+ if (!isBotProfile(value) || value.id !== id) {
30846
+ dropped.push({ section: "bots", key: id, reason: "malformed bot profile" });
30847
+ continue;
30848
+ }
30849
+ bots[id] = value;
30850
+ }
30851
+ return bots;
30852
+ }
30853
+ function isUniqueStringArray(value) {
30854
+ return isStringArray(value) && new Set(value).size === value.length;
30855
+ }
30856
+ function isConversationRecord(value) {
30857
+ if (!isRecord4(value)) {
30858
+ return false;
30859
+ }
30860
+ if (!isString(value.id) || !isString(value.title) || !isOptionalString(value.description) || !isUniqueStringArray(value.botIds) || !isOptionalString(value.leadBotId) || !isString(value.createdAt) || !isString(value.updatedAt)) {
30861
+ return false;
30862
+ }
30863
+ if (value.leadBotId !== undefined && !value.botIds.includes(value.leadBotId)) {
30864
+ return false;
30865
+ }
30866
+ if (value.kind === "bot") {
30867
+ return value.botIds.length === 1;
30868
+ }
30869
+ if (value.kind === "group") {
30870
+ return value.botIds.length >= 2;
30871
+ }
30872
+ return false;
30873
+ }
30874
+ function parseConversations(raw, dropped) {
30875
+ const source = sectionRecord(raw, "conversations", dropped);
30876
+ const conversations = {};
30877
+ for (const [id, value] of Object.entries(source)) {
30878
+ if (!isConversationRecord(value) || value.id !== id) {
30879
+ dropped.push({ section: "conversations", key: id, reason: "malformed conversation record" });
30880
+ continue;
30881
+ }
30882
+ conversations[id] = value;
30883
+ }
30884
+ return conversations;
30885
+ }
30886
+ function isConversationTopic(value) {
30887
+ if (!isRecord4(value)) {
30888
+ return false;
30889
+ }
30890
+ return isString(value.id) && isString(value.conversationId) && isString(value.title) && (value.status === "active" || value.status === "archived") && isString(value.createdAt) && isString(value.updatedAt);
30891
+ }
30892
+ function parseConversationTopics(raw, dropped) {
30893
+ const source = sectionRecord(raw, "conversation_topics", dropped);
30894
+ const topics = {};
30895
+ for (const [id, value] of Object.entries(source)) {
30896
+ if (!isConversationTopic(value) || value.id !== id) {
30897
+ dropped.push({ section: "conversation_topics", key: id, reason: "malformed conversation topic" });
30898
+ continue;
30899
+ }
30900
+ topics[id] = value;
30901
+ }
30902
+ return topics;
30903
+ }
30904
+ function isBotRuntimeBinding(value) {
30905
+ if (!isRecord4(value)) {
30906
+ return false;
30907
+ }
30908
+ if (!isString(value.id) || !isString(value.conversationId) || !isString(value.topicId) || !isString(value.logicalSessionId) || !isString(value.sessionAlias) || !isString(value.createdAt) || !isString(value.updatedAt)) {
30909
+ return false;
30910
+ }
30911
+ if (value.scope === "bot-direct" || value.scope === "group-member") {
30912
+ return isString(value.botId) && value.botId.length > 0;
30913
+ }
30914
+ if (value.scope === "group-controller") {
30915
+ return value.botId === undefined;
30916
+ }
30917
+ return false;
30918
+ }
30919
+ function parseBotRuntimeBindings(raw, dropped) {
30920
+ const source = sectionRecord(raw, "bot_runtime_bindings", dropped);
30921
+ const bindings = {};
30922
+ for (const [id, value] of Object.entries(source)) {
30923
+ if (!isBotRuntimeBinding(value) || value.id !== id) {
30924
+ dropped.push({ section: "bot_runtime_bindings", key: id, reason: "malformed bot runtime binding" });
30925
+ continue;
30926
+ }
30927
+ bindings[id] = value;
30928
+ }
30929
+ return bindings;
30930
+ }
30825
30931
  function parseState(raw, path3, dropped = [], migrated = []) {
30826
30932
  if (!isRecord4(raw)) {
30827
30933
  throw new Error(`state file "${path3}" must contain a JSON object`);
@@ -30834,7 +30940,11 @@ function parseState(raw, path3, dropped = [], migrated = []) {
30834
30940
  chat_contexts: parseChatContexts(sectionRecord(raw.chat_contexts, "chat_contexts", dropped), dropped),
30835
30941
  native_session_lists: parseNativeSessionLists(raw.native_session_lists),
30836
30942
  orchestration: orchestration3,
30837
- scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, dropped)
30943
+ scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, dropped),
30944
+ bots: parseBotProfiles(raw.bots, dropped),
30945
+ conversations: parseConversations(raw.conversations, dropped),
30946
+ conversation_topics: parseConversationTopics(raw.conversation_topics, dropped),
30947
+ bot_runtime_bindings: parseBotRuntimeBindings(raw.bot_runtime_bindings, dropped)
30838
30948
  };
30839
30949
  }
30840
30950
  function repairExternalCoordinatorIdentityCollisions(sessions, orchestration3, dropped) {
@@ -54938,6 +55048,10 @@ function replaceRuntimeState(target, source) {
54938
55048
  target.chat_contexts = source.chat_contexts;
54939
55049
  target.orchestration = source.orchestration;
54940
55050
  target.scheduled_tasks = source.scheduled_tasks;
55051
+ target.bots = source.bots;
55052
+ target.conversations = source.conversations;
55053
+ target.conversation_topics = source.conversation_topics;
55054
+ target.bot_runtime_bindings = source.bot_runtime_bindings;
54941
55055
  }
54942
55056
 
54943
55057
  // src/sessions/transport-engine.ts
@@ -55139,8 +55253,8 @@ class SessionService {
55139
55253
  ...this.permissionInteractionCapable !== undefined ? { permissionInteractionCapable: this.permissionInteractionCapable } : {}
55140
55254
  }).engine;
55141
55255
  }
55142
- async createSession(alias, agent3, workspace3) {
55143
- return await this.createLogicalSession(alias, agent3, workspace3, `${workspace3}:${alias}`);
55256
+ async createSession(alias, agent3, workspace3, options) {
55257
+ return await this.createLogicalSession(alias, agent3, workspace3, `${workspace3}:${alias}`, undefined, undefined, undefined, undefined, options);
55144
55258
  }
55145
55259
  listAllResolvedSessions() {
55146
55260
  const seen = new Set;
@@ -55547,6 +55661,9 @@ class SessionService {
55547
55661
  getLogicalSessionRecord(alias) {
55548
55662
  return this.state.sessions[alias] ?? null;
55549
55663
  }
55664
+ getLogicalSessionById(logicalSessionId) {
55665
+ return Object.values(this.state.sessions).find((session3) => session3.logical_session_id === logicalSessionId) ?? null;
55666
+ }
55550
55667
  listLogicalSessionRecords() {
55551
55668
  return Object.values(this.state.sessions);
55552
55669
  }
@@ -56166,7 +56283,7 @@ class SessionService {
56166
56283
  }
56167
56284
  return input.sameAgentExistingEngine ?? siblingEngine ?? input.fallback();
56168
56285
  }
56169
- async createLogicalSession(alias, agent3, workspace3, transportSession, transportAgentCommand, native, transportAcpxAgent, transportAgentArgv) {
56286
+ async createLogicalSession(alias, agent3, workspace3, transportSession, transportAgentCommand, native, transportAcpxAgent, transportAgentArgv, extras) {
56170
56287
  return await this.mutate(async () => {
56171
56288
  this.validateSession(alias, agent3, workspace3);
56172
56289
  if (Object.keys(this.state.orchestration.externalCoordinators).some((coordinatorSession) => sameCoordinatorSession(coordinatorSession, transportSession))) {
@@ -56191,8 +56308,8 @@ class SessionService {
56191
56308
  ...transportAcpxAgent ? { transport_acpx_agent: transportAcpxAgent } : sameAgentExisting?.transport_acpx_agent ? { transport_acpx_agent: sameAgentExisting.transport_acpx_agent } : {},
56192
56309
  ...transportAgentArgv && transportAgentArgv.length > 0 ? { transport_agent_argv: [...transportAgentArgv] } : sameAgentExisting?.transport_agent_argv ? { transport_agent_argv: [...sameAgentExisting.transport_agent_argv] } : {},
56193
56310
  mode_id: sameAgentExisting?.mode_id,
56194
- model: sameAgentExisting?.model,
56195
- effort: sameAgentExisting?.effort,
56311
+ model: extras?.model ?? sameAgentExisting?.model,
56312
+ effort: extras?.effort ?? sameAgentExisting?.effort,
56196
56313
  reply_mode: sameAgentExisting?.reply_mode,
56197
56314
  display_name: sameAgentExisting?.display_name,
56198
56315
  transport_engine: this.resolveEngineWithPhysicalInheritance({
@@ -56206,7 +56323,8 @@ class SessionService {
56206
56323
  ...sameAgentExisting ? { sameAgentExisting } : {}
56207
56324
  }),
56208
56325
  created_at: existingSession?.created_at ?? now,
56209
- last_used_at: now
56326
+ last_used_at: now,
56327
+ ...extras?.owner ? { owner: extras.owner } : {}
56210
56328
  };
56211
56329
  const nextState = structuredClone(this.state);
56212
56330
  nextState.sessions[alias] = session3;
@@ -0,0 +1,51 @@
1
+ export type ConversationKind = "bot" | "group";
2
+ export type ConversationTopicStatus = "active" | "archived";
3
+ export type ConversationMessageRole = "human" | "bot" | "system";
4
+ export type GroupTurnOrigin = "human-explicit" | "controller" | "handoff" | "recovery";
5
+ export type GroupTurnState = "queued" | "running" | "completed" | "failed" | "cancelled";
6
+ export interface ConversationRecord {
7
+ id: string;
8
+ kind: ConversationKind;
9
+ title: string;
10
+ description?: string;
11
+ botIds: string[];
12
+ leadBotId?: string;
13
+ createdAt: string;
14
+ updatedAt: string;
15
+ }
16
+ export interface ConversationTopic {
17
+ id: string;
18
+ conversationId: string;
19
+ title: string;
20
+ status: ConversationTopicStatus;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ }
24
+ export interface ConversationMessage {
25
+ id: string;
26
+ conversationId: string;
27
+ topicId: string;
28
+ role: ConversationMessageRole;
29
+ senderBotId?: string;
30
+ recipients?: string[];
31
+ content: string;
32
+ replyTo?: string;
33
+ createdAt: string;
34
+ sourceTurn?: {
35
+ sessionAlias: string;
36
+ turnId?: string;
37
+ };
38
+ }
39
+ export interface GroupTurnRecord {
40
+ id: string;
41
+ conversationId: string;
42
+ topicId: string;
43
+ botId: string;
44
+ sessionAlias: string;
45
+ triggerMessageIds: string[];
46
+ origin: GroupTurnOrigin;
47
+ state: GroupTurnState;
48
+ createdAt: string;
49
+ startedAt?: string;
50
+ finishedAt?: string;
51
+ }
@@ -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,13 @@
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
+ }
5
11
  export interface NativeSessionCacheEntry {
6
12
  session_id: string;
7
13
  cwd?: string;
@@ -59,6 +65,7 @@ export interface LogicalSession {
59
65
  archived_at?: string;
60
66
  created_at: string;
61
67
  last_used_at: string;
68
+ owner?: LogicalSessionOwner;
62
69
  }
63
70
  export interface BackgroundResult {
64
71
  text: string;
@@ -76,5 +83,9 @@ export interface AppState {
76
83
  native_session_lists: Record<string, NativeSessionListCacheRecord>;
77
84
  orchestration: OrchestrationState;
78
85
  scheduled_tasks: Record<string, ScheduledTaskRecord>;
86
+ bots: Record<string, BotProfile>;
87
+ conversations: Record<string, ConversationRecord>;
88
+ conversation_topics: Record<string, ConversationTopic>;
89
+ bot_runtime_bindings: Record<string, BotRuntimeBinding>;
79
90
  }
80
91
  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.5",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",