@ganglion/xacpx 0.20.3 → 0.22.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.
- package/dist/bridge/bridge-main.js +5 -1
- package/dist/channels/cli/provider.d.ts +17 -0
- package/dist/channels/plugin.d.ts +21 -0
- package/dist/channels/types.d.ts +16 -2
- package/dist/cli.js +374 -73
- package/dist/config/local-agent-bin.d.ts +6 -0
- package/dist/config/resolve-agent-command.d.ts +1 -1
- package/dist/config/types.d.ts +6 -4
- package/dist/i18n/types.d.ts +1 -0
- package/dist/plugin-api.d.ts +4 -3
- package/dist/plugin-api.js +2 -0
- package/dist/sessions/session-resource-catalog.d.ts +96 -0
- package/dist/sessions/session-service.d.ts +30 -1
- package/dist/state/state-store.d.ts +23 -4
- package/dist/state/types.d.ts +8 -0
- package/package.json +2 -1
|
@@ -8,6 +8,12 @@ export declare function executableExtensions(platform: NodeJS.Platform, env: Nod
|
|
|
8
8
|
* `opencode` matches `opencode.cmd`/`.exe`. `env`/`isExecutableFile` are injectable for tests.
|
|
9
9
|
*/
|
|
10
10
|
export declare function isExecutableOnPath(name: string, env?: NodeJS.ProcessEnv, isExecutableFile?: (p: string) => boolean): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Is `driver` listed as a local-fallback agent in LOCAL_AGENT_BINS? Use this — not a
|
|
13
|
+
* hand-copied allow-list — for drift guards that need to exempt drivers xacpx itself
|
|
14
|
+
* supplies at runtime (e.g. `agent-catalog.test.ts`'s acpx-registry drift guard).
|
|
15
|
+
*/
|
|
16
|
+
export declare function isLocalAgentBinDriver(driver: string): boolean;
|
|
11
17
|
/**
|
|
12
18
|
* If `driver` is a known npx-fallback agent AND its native CLI is on PATH, return the
|
|
13
19
|
* structured argv (e.g. `["opencode", "acp"]`); otherwise undefined (let acpx fall back
|
|
@@ -31,7 +31,7 @@ export interface ResolveAgentLaunchOptions {
|
|
|
31
31
|
* 2. user `argv`: content-addressed overlay alias + canonical identity.
|
|
32
32
|
* 3. managed codex/claude: structured pinned npx argv (alias launch).
|
|
33
33
|
* 4. hermes: ACP shim argv (alias launch).
|
|
34
|
-
* 5. local fallback (opencode/kilocode on PATH): structured argv (alias launch).
|
|
34
|
+
* 5. local fallback (opencode/kilocode/reasonix/omp on PATH): structured argv (alias launch).
|
|
35
35
|
* 6. anything else: bare built-in driver positional.
|
|
36
36
|
*/
|
|
37
37
|
export declare function resolveConfiguredAgentLaunch(agent: Pick<AgentConfig, "driver" | "command" | "argv">, transport?: Pick<TransportConfig, "preferLocalAgents" | "adapterVersions" | "adapterRegistry">, options?: ResolveAgentLaunchOptions): AgentLaunchSpec;
|
package/dist/config/types.d.ts
CHANGED
|
@@ -37,10 +37,12 @@ export interface TransportConfig {
|
|
|
37
37
|
queueOwnerTtlSeconds?: number;
|
|
38
38
|
/**
|
|
39
39
|
* Prefer a locally-installed native agent CLI over acpx's `npx -y <pkg>` fallback
|
|
40
|
-
* when one is on PATH (currently the
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* when one is on PATH (currently opencode, kilocode, plus the local-fallback drivers
|
|
41
|
+
* reasonix and omp that aren't in acpx's registry but speak ACP via `<bin> acp`).
|
|
42
|
+
* This avoids a per-cold-start npm-registry fetch — faster and immune to network
|
|
43
|
+
* blips (e.g. ECONNRESET during agent init). Defaults to `true`; set `false` to
|
|
44
|
+
* always use acpx's default resolution. A per-agent `command` override still takes
|
|
45
|
+
* precedence.
|
|
44
46
|
*/
|
|
45
47
|
preferLocalAgents?: boolean;
|
|
46
48
|
/** Exact local overrides for xacpx-managed ACP adapter versions. Omitted entries
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -700,6 +700,7 @@ export interface ChannelCliMessages {
|
|
|
700
700
|
channelAdded: (type: string) => string;
|
|
701
701
|
cannotRemoveLastEnabled: string;
|
|
702
702
|
channelRemoved: (id: string) => string;
|
|
703
|
+
channelRetirementFailed: (id: string, error: string) => string;
|
|
703
704
|
channelCredentialsCleared: (id: string) => string;
|
|
704
705
|
channelCredentialsClearFailed: (id: string, error: string) => string;
|
|
705
706
|
channelCredentialsKept: (id: string) => string;
|
package/dist/plugin-api.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { ChannelPluginDefinition } from "./channels/plugin.js";
|
|
1
|
+
export type { ChannelPluginDefinition, ChannelRetireContext, ChannelRetireDaemonState, ChannelRetireHook, } from "./channels/plugin.js";
|
|
2
2
|
export type { ChannelFactory, CreateChannelDeps } from "./channels/create-channel.js";
|
|
3
|
-
export type { ChannelStartInput, ConsumerLock, ConsumerLockMetadata, ConsumerLockOptions, CoordinatorMessageInput, MessageChannelRuntime, ScheduledChannelMessageInput, OrchestrationDeliveryCallbacks, OutboundQuota, PlanEntry, PlanEntryStatus, ToolUseEvent, ToolUseKind, ToolUseStatus, } from "./channels/types.js";
|
|
3
|
+
export type { ChannelStartInput, ConsumerLock, ConsumerLockMetadata, ConsumerLockOptions, ChannelStopReason, CoordinatorMessageInput, MessageChannelRuntime, ScheduledChannelMessageInput, OrchestrationDeliveryCallbacks, OutboundQuota, PlanEntry, PlanEntryStatus, ToolUseEvent, ToolUseKind, ToolUseStatus, } from "./channels/types.js";
|
|
4
4
|
export { formatSubagentNotice, SubagentNoticeTracker } from "./channels/subagent-notice.js";
|
|
5
5
|
export type { AgentCommand, PromptUsage, UsageBreakdown, UsageCost, } from "./transport/types.js";
|
|
6
|
-
export type { ChannelCliInput, ChannelCliIo, ChannelCliParseResult, ChannelCliProvider, ChannelCliValidationIssue, } from "./channels/cli/provider.js";
|
|
6
|
+
export type { ChannelCliInput, ChannelCliIo, ChannelCliParseResult, ChannelCliProvider, ChannelCliValidationIssue, ChannelDoctorFinding, ChannelDoctorFindingLevel, } from "./channels/cli/provider.js";
|
|
7
7
|
export type { ChannelRuntimeConfig } from "./config/types.js";
|
|
8
8
|
export type { CommandHint } from "./commands/command-hints.js";
|
|
9
9
|
export type { AppLogger } from "./logging/app-logger.js";
|
|
@@ -22,4 +22,5 @@ export { getLocale } from "./i18n/index.js";
|
|
|
22
22
|
export type { Locale } from "./i18n/index.js";
|
|
23
23
|
export type { ControlExecuteCommandInput, ControlPromptInput, ControlPromptResult, ControlService, ControlSessionInfo, } from "./control/control-service.js";
|
|
24
24
|
export type { ControlEvent, ControlEventBus, ControlEventListener } from "./control/control-event-bus.js";
|
|
25
|
+
export type { SessionResourceCatalog, SessionResourceDescriptor, SessionResourceLifecycleEvent, } from "./sessions/session-resource-catalog.js";
|
|
25
26
|
export { coreHomeDir } from "./runtime/core-home.js";
|
package/dist/plugin-api.js
CHANGED
|
@@ -927,6 +927,7 @@ var init_channel_cli = __esm(() => {
|
|
|
927
927
|
channelAdded: (type) => `Channel ${type} added`,
|
|
928
928
|
cannotRemoveLastEnabled: "Cannot remove the last enabled channel.",
|
|
929
929
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
930
|
+
channelRetirementFailed: (id, error) => `Channel ${id} retirement cleanup failed: ${error}`,
|
|
930
931
|
channelCredentialsCleared: (id) => `Removed stored credentials for channel ${id}`,
|
|
931
932
|
channelCredentialsClearFailed: (id, error) => `Channel ${id} removed, but clearing its stored credentials failed: ${error}`,
|
|
932
933
|
channelCredentialsKept: (id) => `Kept stored credentials for channel ${id} (--keep-credentials)`,
|
|
@@ -2053,6 +2054,7 @@ var init_channel_cli2 = __esm(() => {
|
|
|
2053
2054
|
channelAdded: (type) => `频道 ${type} 已添加`,
|
|
2054
2055
|
cannotRemoveLastEnabled: "不能删除最后一个启用的频道。",
|
|
2055
2056
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
2057
|
+
channelRetirementFailed: (id, error) => `频道 ${id} 退役清理失败:${error}`,
|
|
2056
2058
|
channelCredentialsCleared: (id) => `已移除频道 ${id} 的存储凭证`,
|
|
2057
2059
|
channelCredentialsClearFailed: (id, error) => `频道 ${id} 已删除,但清除其存储凭证失败:${error}`,
|
|
2058
2060
|
channelCredentialsKept: (id) => `已保留频道 ${id} 的存储凭证(--keep-credentials)`,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { AppConfig } from "../config/types";
|
|
2
|
+
import type { AppLogger } from "../logging/app-logger";
|
|
3
|
+
import type { LogicalSession } from "../state/types";
|
|
4
|
+
import type { SessionService } from "./session-service";
|
|
5
|
+
/**
|
|
6
|
+
* A point-in-time snapshot of one logical session's resource identity. The
|
|
7
|
+
* immutable `logicalSessionId` is the ONLY stable key: aliases, display names
|
|
8
|
+
* and transport bindings can all change under the same id. `cwd` is resolved
|
|
9
|
+
* authoritatively from the core workspace config — callers (e.g. browsers)
|
|
10
|
+
* never contribute a cwd. Descriptors are snapshots: a previously returned
|
|
11
|
+
* descriptor never mutates when the underlying session changes.
|
|
12
|
+
*/
|
|
13
|
+
export interface SessionResourceDescriptor {
|
|
14
|
+
logicalSessionId: string;
|
|
15
|
+
channelId: string;
|
|
16
|
+
internalAlias: string;
|
|
17
|
+
displayAlias: string;
|
|
18
|
+
workspace: string;
|
|
19
|
+
cwd: string;
|
|
20
|
+
archived: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type SessionResourceLifecycleEvent = {
|
|
23
|
+
type: "archived";
|
|
24
|
+
session: SessionResourceDescriptor;
|
|
25
|
+
} | {
|
|
26
|
+
type: "restored";
|
|
27
|
+
session: SessionResourceDescriptor;
|
|
28
|
+
} | {
|
|
29
|
+
type: "removed";
|
|
30
|
+
session: SessionResourceDescriptor;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Write-side seam handed to SessionService: after a lifecycle transition has
|
|
34
|
+
* been durably persisted (never before), the service reports the transition
|
|
35
|
+
* type plus the persisted record; the catalog maps the record to a descriptor
|
|
36
|
+
* and publishes the event to subscribers. For `removed` the record is the
|
|
37
|
+
* pre-delete snapshot, so the event carries the session's final identity.
|
|
38
|
+
*/
|
|
39
|
+
export interface SessionResourceLifecyclePublishInput {
|
|
40
|
+
type: SessionResourceLifecycleEvent["type"];
|
|
41
|
+
record: LogicalSession;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generic, channel-agnostic catalog over logical session resources. Contains
|
|
45
|
+
* no channel- or consumer-specific vocabulary; structured channels (and their
|
|
46
|
+
* plugins) use it to enumerate and resolve the sessions they own.
|
|
47
|
+
*/
|
|
48
|
+
export interface SessionResourceCatalog {
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a chat-scoped alias (display or internal form) to a descriptor.
|
|
51
|
+
* Uses the same chat-scope resolution as ControlService: a caller can never
|
|
52
|
+
* reach another channel's sessions. Returns null for unknown aliases and
|
|
53
|
+
* for sessions whose workspace is no longer registered (their cwd cannot be
|
|
54
|
+
* authoritatively resolved).
|
|
55
|
+
*/
|
|
56
|
+
resolve(chatKey: string, alias: string): Promise<SessionResourceDescriptor | null>;
|
|
57
|
+
/** All sessions of one channel, active AND archived, for reconciliation. */
|
|
58
|
+
list(channelId: string): Promise<SessionResourceDescriptor[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Register a lifecycle listener; returns an unsubscribe function. Listener
|
|
61
|
+
* exceptions are caught and logged to the app log: they never roll back the
|
|
62
|
+
* underlying session operation and never block other listeners.
|
|
63
|
+
*/
|
|
64
|
+
subscribe(listener: (event: SessionResourceLifecycleEvent) => void): () => void;
|
|
65
|
+
}
|
|
66
|
+
interface SessionResourceCatalogDeps {
|
|
67
|
+
sessions: SessionService;
|
|
68
|
+
config: AppConfig;
|
|
69
|
+
logger: AppLogger;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Production catalog assembled by the core runtime over the live SessionService
|
|
73
|
+
* and workspace config. Plugin/channel tests should use their own in-memory
|
|
74
|
+
* implementation of the interface instead of this adapter.
|
|
75
|
+
*/
|
|
76
|
+
export declare class CoreSessionResourceCatalog implements SessionResourceCatalog {
|
|
77
|
+
private readonly deps;
|
|
78
|
+
private readonly listeners;
|
|
79
|
+
constructor(deps: SessionResourceCatalogDeps);
|
|
80
|
+
resolve(chatKey: string, alias: string): Promise<SessionResourceDescriptor | null>;
|
|
81
|
+
list(channelId: string): Promise<SessionResourceDescriptor[]>;
|
|
82
|
+
subscribe(listener: (event: SessionResourceLifecycleEvent) => void): () => void;
|
|
83
|
+
/**
|
|
84
|
+
* Publish one durably-persisted lifecycle transition. SessionService calls
|
|
85
|
+
* this (via the publisher it was handed at runtime wiring) strictly AFTER
|
|
86
|
+
* saveNow succeeded and the runtime state was published; the catalog itself
|
|
87
|
+
* never persists anything. Records whose workspace is no longer registered
|
|
88
|
+
* produce no event: such sessions are invisible in resolve()/list(), so
|
|
89
|
+
* consumers never tracked a resource for them.
|
|
90
|
+
*/
|
|
91
|
+
publishLifecycleEvent(input: SessionResourceLifecyclePublishInput): void;
|
|
92
|
+
/** Fan an event out to all subscribers; listener throws are isolated. */
|
|
93
|
+
private emit;
|
|
94
|
+
private toDescriptor;
|
|
95
|
+
}
|
|
96
|
+
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
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 } from "../state/types";
|
|
4
|
+
import type { AppState, BackgroundResult, LogicalSession } from "../state/types";
|
|
5
|
+
import type { SessionResourceLifecyclePublishInput } from "./session-resource-catalog";
|
|
5
6
|
import type { AgentSession, ResolvedSession } from "../transport/types";
|
|
6
7
|
interface SessionListItem {
|
|
7
8
|
alias: string;
|
|
@@ -79,6 +80,7 @@ export declare class SessionService {
|
|
|
79
80
|
private readonly platform;
|
|
80
81
|
private readonly runtimeRoot;
|
|
81
82
|
private readonly pendingSessionAliasOperations;
|
|
83
|
+
private lifecyclePublisher;
|
|
82
84
|
constructor(config: AppConfig, stateStore: SessionStateWriter, state: AppState, options?: SessionServiceOptions);
|
|
83
85
|
createSession(alias: string, agent: string, workspace: string): Promise<ResolvedSession>;
|
|
84
86
|
/**
|
|
@@ -109,6 +111,8 @@ export declare class SessionService {
|
|
|
109
111
|
getPreferredSessionForTransport(transportSession: string): Promise<ResolvedSession | null>;
|
|
110
112
|
findAttachedNativeSession(chatKey: string, agent: string, agentSessionId: string): Promise<ResolvedSession | null>;
|
|
111
113
|
useSession(chatKey: string, alias: string): Promise<SessionSwitchResult>;
|
|
114
|
+
/** Apply the use-session mutation (switch, plus restore when archived). */
|
|
115
|
+
private applyUseSession;
|
|
112
116
|
usePreviousSession(chatKey: string): Promise<SessionSwitchResult | null>;
|
|
113
117
|
setBackgroundResult(chatKey: string, alias: string, result: BackgroundResult): Promise<void>;
|
|
114
118
|
takeBackgroundResult(chatKey: string, alias: string): Promise<BackgroundResult | null>;
|
|
@@ -155,11 +159,36 @@ export declare class SessionService {
|
|
|
155
159
|
*/
|
|
156
160
|
buildFreshTransportSession(stableTransportSession: string): string;
|
|
157
161
|
listInternalAliases(): string[];
|
|
162
|
+
/**
|
|
163
|
+
* Read-only access to the persisted logical session record by internal alias.
|
|
164
|
+
* Returns the LIVE record — callers must treat it as immutable. Exists for
|
|
165
|
+
* consumers (the session resource catalog) that need fields ResolvedSession
|
|
166
|
+
* does not carry (immutable logical_session_id, archived flag).
|
|
167
|
+
*/
|
|
168
|
+
getLogicalSessionRecord(alias: string): LogicalSession | null;
|
|
169
|
+
/** Read-only view of every persisted logical session record, across all channels. */
|
|
170
|
+
listLogicalSessionRecords(): LogicalSession[];
|
|
158
171
|
setCurrentSessionMode(chatKey: string, modeId: string | undefined): Promise<void>;
|
|
159
172
|
setCurrentSessionReplyMode(chatKey: string, replyMode: "stream" | "final" | "verbose" | undefined): Promise<void>;
|
|
160
173
|
getCurrentSession(chatKey: string): Promise<ResolvedSession | null>;
|
|
161
174
|
listSessions(chatKey: string): Promise<SessionListItem[]>;
|
|
162
175
|
countAliasesSharingTransport(transportSession: string, excludeAlias?: string): number;
|
|
176
|
+
/**
|
|
177
|
+
* Wire the sink for resource lifecycle events (production: the core
|
|
178
|
+
* SessionResourceCatalog; the runtime calls this once after constructing
|
|
179
|
+
* the catalog). Archive/restore/remove transitions report through it only
|
|
180
|
+
* AFTER their state has been durably persisted — never before.
|
|
181
|
+
*/
|
|
182
|
+
setSessionResourceLifecyclePublisher(publish: (input: SessionResourceLifecyclePublishInput) => void): void;
|
|
183
|
+
private publishLifecycleEvent;
|
|
184
|
+
/**
|
|
185
|
+
* Durability gate for lifecycle transitions: persist the copy-on-write
|
|
186
|
+
* snapshot first (saveNow rejects on write failure, so the live state, chat
|
|
187
|
+
* contexts and event stream all stay untouched), then publish the persisted
|
|
188
|
+
* snapshot to the runtime state. Only after this resolves may the lifecycle
|
|
189
|
+
* event be emitted.
|
|
190
|
+
*/
|
|
191
|
+
private commitLifecycleTransition;
|
|
163
192
|
setArchived(alias: string, archived: boolean): Promise<void>;
|
|
164
193
|
removeSession(alias: string): Promise<{
|
|
165
194
|
wasActive: boolean;
|
|
@@ -12,6 +12,12 @@ export interface StateLoadDroppedRecord {
|
|
|
12
12
|
}
|
|
13
13
|
export interface StateLoadReport {
|
|
14
14
|
dropped: StateLoadDroppedRecord[];
|
|
15
|
+
/**
|
|
16
|
+
* Legacy session records that were assigned a fresh logical_session_id
|
|
17
|
+
* during load. Kept separate from {@link dropped}: a migrated record is
|
|
18
|
+
* healthy and survives, a dropped record is corrupt and was removed.
|
|
19
|
+
*/
|
|
20
|
+
migrated?: StateLoadDroppedRecord[];
|
|
15
21
|
/** Backup copy of the original file, written because records were dropped. */
|
|
16
22
|
quarantinePath?: string;
|
|
17
23
|
/** Unreadable original renamed aside (whole-file JSON corruption). */
|
|
@@ -19,6 +25,12 @@ export interface StateLoadReport {
|
|
|
19
25
|
/** Best-effort backup/rename failure; load still returned the cleaned state. */
|
|
20
26
|
backupError?: string;
|
|
21
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* A logical_session_id is always a UUIDv4 (randomUUID). Present-but-invalid
|
|
30
|
+
* values are treated as corruption and quarantined with the record; only a
|
|
31
|
+
* genuinely MISSING field (legacy record) enters the load-time migration.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isLogicalSessionId(value: unknown): value is string;
|
|
22
34
|
/**
|
|
23
35
|
* Lenient state parser: a malformed record (or wrong-typed section) is skipped
|
|
24
36
|
* and collected in `dropped` instead of throwing, so one bad record can never
|
|
@@ -27,7 +39,7 @@ export interface StateLoadReport {
|
|
|
27
39
|
* non-object top level still throws (StateStore.load treats that as a corrupt
|
|
28
40
|
* file and renames it aside).
|
|
29
41
|
*/
|
|
30
|
-
export declare function parseState(raw: unknown, path: string, dropped?: StateLoadDroppedRecord[]): AppState;
|
|
42
|
+
export declare function parseState(raw: unknown, path: string, dropped?: StateLoadDroppedRecord[], migrated?: StateLoadDroppedRecord[]): AppState;
|
|
31
43
|
export interface StateStoreOptions {
|
|
32
44
|
/** Injectable clock used for quarantine/corrupt backup file names. */
|
|
33
45
|
now?: () => Date;
|
|
@@ -37,6 +49,11 @@ export interface StateStoreOptions {
|
|
|
37
49
|
* writer suffix-retries instead of overwriting an existing backup).
|
|
38
50
|
*/
|
|
39
51
|
writeBackup?: (targetPath: string, content: string) => Promise<string | void>;
|
|
52
|
+
/**
|
|
53
|
+
* Injectable durable writer for the legacy logical_session_id migration
|
|
54
|
+
* (tests simulate write failures). Defaults to the regular atomic save.
|
|
55
|
+
*/
|
|
56
|
+
writeMigration?: (state: AppState) => Promise<void>;
|
|
40
57
|
}
|
|
41
58
|
/** Result of a side-effect-free {@link StateStore.inspect}. */
|
|
42
59
|
export interface StateLoadInspection {
|
|
@@ -56,11 +73,13 @@ export declare class StateStore {
|
|
|
56
73
|
*/
|
|
57
74
|
get lastLoadReport(): StateLoadReport | null;
|
|
58
75
|
load(): Promise<AppState>;
|
|
76
|
+
/** Synchronous (awaited) atomic write of a migrated state, via the private-file writer. */
|
|
77
|
+
private persistMigration;
|
|
59
78
|
/**
|
|
60
79
|
* Side-effect-free variant of load() for diagnostic callers (doctor): parses
|
|
61
|
-
* and reports exactly what load() would drop/repair, but never writes
|
|
62
|
-
* quarantine backup, never renames a corrupt file,
|
|
63
|
-
* {@link lastLoadReport}.
|
|
80
|
+
* and reports exactly what load() would drop/repair/migrate, but never writes
|
|
81
|
+
* a quarantine backup, never renames a corrupt file, never persists pending
|
|
82
|
+
* logical_session_id migrations, and does not touch {@link lastLoadReport}.
|
|
64
83
|
*/
|
|
65
84
|
inspect(): Promise<StateLoadInspection>;
|
|
66
85
|
private readAndParse;
|
package/dist/state/types.d.ts
CHANGED
|
@@ -20,6 +20,14 @@ export interface LogicalSession {
|
|
|
20
20
|
agent: string;
|
|
21
21
|
workspace: string;
|
|
22
22
|
transport_session: string;
|
|
23
|
+
/**
|
|
24
|
+
* Immutable identity of this logical session (UUIDv4), assigned once at
|
|
25
|
+
* create/attach time. Never changes across rename, display-name, agent,
|
|
26
|
+
* workspace, or transport-binding updates; never reused after the alias is
|
|
27
|
+
* deleted. Legacy records missing the field are migrated once at load time
|
|
28
|
+
* and persisted before startup proceeds.
|
|
29
|
+
*/
|
|
30
|
+
logical_session_id: string;
|
|
23
31
|
source?: LogicalSessionSource;
|
|
24
32
|
agent_session_id?: string;
|
|
25
33
|
agent_session_title?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ganglion/xacpx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acpx",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"build:relay": "bun run build:relay-web && bun run clean:relay && bun build ./packages/relay/src/cli.ts --outdir ./packages/relay/dist --target node --external ws --external hono --external @hono/node-server --external @ganglion/xacpx-relay-protocol && tsc -p packages/relay/tsconfig.json && bun run bundle:relay-web",
|
|
55
55
|
"clean:channel-relay": "node -e \"require('node:fs').rmSync('packages/channel-relay/dist', { recursive: true, force: true })\"",
|
|
56
56
|
"build:channel-relay": "bun run build:plugin-api && bun run build:relay-protocol && bun run clean:channel-relay && bun build ./packages/channel-relay/src/index.ts --outdir ./packages/channel-relay/dist --target node --external xacpx --external ws --external @ganglion/xacpx-relay-protocol && tsc -p packages/channel-relay/tsconfig.json",
|
|
57
|
+
"pack:rmux-bridge": "node ./scripts/pack-rmux-bridge-platform.mjs",
|
|
57
58
|
"clean:relay-web": "node -e \"require('node:fs').rmSync('packages/relay-web/dist',{recursive:true,force:true})\"",
|
|
58
59
|
"build:relay-web": "bun run build:relay-protocol && bun run clean:relay-web && bun run --cwd packages/relay-web build",
|
|
59
60
|
"test:web": "bun run --cwd packages/relay-web test",
|