@ganglion/xacpx 0.8.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/LICENSE +21 -0
- package/README.md +570 -0
- package/config.example.json +44 -0
- package/dist/bridge/bridge-main.js +2133 -0
- package/dist/channels/channel-scope.d.ts +17 -0
- package/dist/channels/cli/provider.d.ts +73 -0
- package/dist/channels/cli/registry.d.ts +7 -0
- package/dist/channels/cli/weixin-provider.d.ts +2 -0
- package/dist/channels/create-channel.d.ts +16 -0
- package/dist/channels/media-store.d.ts +29 -0
- package/dist/channels/media-types.d.ts +28 -0
- package/dist/channels/outbound-media-safety.d.ts +7 -0
- package/dist/channels/plugin.d.ts +9 -0
- package/dist/channels/types.d.ts +124 -0
- package/dist/channels/weixin-channel.d.ts +25 -0
- package/dist/cli.js +47745 -0
- package/dist/commands/command-hints.d.ts +11 -0
- package/dist/commands/command-list.d.ts +3 -0
- package/dist/commands/config-clone.d.ts +2 -0
- package/dist/commands/handlers/agent-handler.d.ts +6 -0
- package/dist/commands/handlers/config-handler.d.ts +5 -0
- package/dist/commands/handlers/later-handler.d.ts +21 -0
- package/dist/commands/handlers/orchestration-handler.d.ts +16 -0
- package/dist/commands/handlers/permission-handler.d.ts +9 -0
- package/dist/commands/handlers/session-handler.d.ts +39 -0
- package/dist/commands/handlers/session-list-marker.d.ts +1 -0
- package/dist/commands/handlers/workspace-handler.d.ts +8 -0
- package/dist/commands/help/help-registry.d.ts +4 -0
- package/dist/commands/help/help-types.d.ts +12 -0
- package/dist/commands/parse-command.d.ts +178 -0
- package/dist/commands/router-types.d.ts +144 -0
- package/dist/commands/workspace-name.d.ts +4 -0
- package/dist/commands/workspace-path.d.ts +4 -0
- package/dist/config/agent-templates.d.ts +4 -0
- package/dist/config/config-store.d.ts +13 -0
- package/dist/config/load-config.d.ts +10 -0
- package/dist/config/resolve-agent-command.d.ts +2 -0
- package/dist/config/types.d.ts +85 -0
- package/dist/formatting/render-text.d.ts +23 -0
- package/dist/logging/app-logger.d.ts +23 -0
- package/dist/logging/rotating-file-writer.d.ts +2 -0
- package/dist/orchestration/async-mutex.d.ts +4 -0
- package/dist/orchestration/build-coordinator-prompt.d.ts +66 -0
- package/dist/orchestration/orchestration-service.d.ts +471 -0
- package/dist/orchestration/orchestration-types.d.ts +181 -0
- package/dist/orchestration/progress-line-parser.d.ts +19 -0
- package/dist/orchestration/render-delegate-group-result.d.ts +6 -0
- package/dist/orchestration/render-delegate-question-package.d.ts +21 -0
- package/dist/orchestration/render-delegate-result.d.ts +2 -0
- package/dist/orchestration/task-watch-timeouts.d.ts +5 -0
- package/dist/perf/perf-log-writer.d.ts +25 -0
- package/dist/perf/perf-tracer.d.ts +54 -0
- package/dist/plugin-api.d.ts +18 -0
- package/dist/plugin-api.js +341 -0
- package/dist/plugins/compatibility.d.ts +18 -0
- package/dist/plugins/known-plugins.d.ts +9 -0
- package/dist/plugins/types.d.ts +31 -0
- package/dist/runtime/conversation-executor.d.ts +7 -0
- package/dist/runtime/core-env.d.ts +28 -0
- package/dist/runtime/core-home.d.ts +31 -0
- package/dist/runtime/turn-lane.d.ts +2 -0
- package/dist/scheduled/parse-later-time.d.ts +11 -0
- package/dist/scheduled/scheduled-render.d.ts +7 -0
- package/dist/scheduled/scheduled-service.d.ts +41 -0
- package/dist/scheduled/scheduled-types.d.ts +29 -0
- package/dist/sessions/active-turn-registry.d.ts +6 -0
- package/dist/sessions/session-service.d.ts +118 -0
- package/dist/state/state-store.d.ts +8 -0
- package/dist/state/types.d.ts +51 -0
- package/dist/transport/tool-event-mode.d.ts +14 -0
- package/dist/transport/types.d.ts +129 -0
- package/dist/util/path.d.ts +4 -0
- package/dist/util/private-file.d.ts +26 -0
- package/dist/util/sanitize.d.ts +10 -0
- package/dist/util/text.d.ts +3 -0
- package/dist/version.d.ts +3 -0
- package/dist/weixin/agent/interface.d.ts +79 -0
- package/dist/weixin/api/api.d.ts +76 -0
- package/dist/weixin/api/config-cache.d.ts +35 -0
- package/dist/weixin/api/session-guard.d.ts +17 -0
- package/dist/weixin/api/types.d.ts +203 -0
- package/dist/weixin/auth/accounts.d.ts +69 -0
- package/dist/weixin/auth/login-qr.d.ts +37 -0
- package/dist/weixin/bot.d.ts +67 -0
- package/dist/weixin/cdn/aes-ecb.d.ts +6 -0
- package/dist/weixin/cdn/cdn-upload.d.ts +17 -0
- package/dist/weixin/cdn/cdn-url.d.ts +11 -0
- package/dist/weixin/cdn/pic-decrypt.d.ts +9 -0
- package/dist/weixin/cdn/upload.d.ts +42 -0
- package/dist/weixin/index.d.ts +6 -0
- package/dist/weixin/media/media-download.d.ts +18 -0
- package/dist/weixin/media/mime.d.ts +6 -0
- package/dist/weixin/media/silk-transcode.d.ts +8 -0
- package/dist/weixin/messaging/completion-notice.d.ts +2 -0
- package/dist/weixin/messaging/debug-mode.d.ts +9 -0
- package/dist/weixin/messaging/deliver-coordinator-message.d.ts +22 -0
- package/dist/weixin/messaging/deliver-orchestration-task-notice.d.ts +18 -0
- package/dist/weixin/messaging/deliver-orchestration-task-progress.d.ts +16 -0
- package/dist/weixin/messaging/error-notice.d.ts +13 -0
- package/dist/weixin/messaging/execute-chat-turn.d.ts +12 -0
- package/dist/weixin/messaging/final-heads-up.d.ts +5 -0
- package/dist/weixin/messaging/foreground-gate.d.ts +3 -0
- package/dist/weixin/messaging/handle-weixin-message-turn.d.ts +36 -0
- package/dist/weixin/messaging/inbound.d.ts +87 -0
- package/dist/weixin/messaging/markdown-filter.d.ts +45 -0
- package/dist/weixin/messaging/orchestration-notice-accounts.d.ts +2 -0
- package/dist/weixin/messaging/quota-errors.d.ts +8 -0
- package/dist/weixin/messaging/quota-manager.d.ts +58 -0
- package/dist/weixin/messaging/scheduled-turn.d.ts +22 -0
- package/dist/weixin/messaging/send-errors.d.ts +39 -0
- package/dist/weixin/messaging/send-media.d.ts +23 -0
- package/dist/weixin/messaging/send-orchestration-notice.d.ts +10 -0
- package/dist/weixin/messaging/send.d.ts +73 -0
- package/dist/weixin/messaging/slash-commands.d.ts +40 -0
- package/dist/weixin/monitor/consumer-lock.d.ts +24 -0
- package/dist/weixin/monitor/monitor.d.ts +38 -0
- package/dist/weixin/storage/ensure-dir.d.ts +1 -0
- package/dist/weixin/storage/state-dir.d.ts +2 -0
- package/dist/weixin/storage/sync-buf.d.ts +20 -0
- package/dist/weixin/util/logger.d.ts +14 -0
- package/dist/weixin/util/random.d.ts +10 -0
- package/dist/weixin/util/redact.d.ts +21 -0
- package/package.json +93 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const WEACPX_PLUGIN_API_VERSION: 1;
|
|
2
|
+
export declare const WEACPX_PLUGIN_API_SUPPORTED_VERSIONS: readonly number[];
|
|
3
|
+
export declare const WEACPX_PLUGIN_MIN_CORE_VERSION: "0.5.0";
|
|
4
|
+
export declare function normalizeCoreVersionForCompat(version: string): string;
|
|
5
|
+
export declare function compareSemver(a: string, b: string): -1 | 0 | 1;
|
|
6
|
+
export declare function isVersionSatisfied(current: string, requirement: string): boolean;
|
|
7
|
+
export interface PluginCompatibilityMetadata {
|
|
8
|
+
apiVersion?: unknown;
|
|
9
|
+
minWeacpxVersion?: unknown;
|
|
10
|
+
compatibleWeacpxVersions?: unknown;
|
|
11
|
+
minXacpxVersion?: unknown;
|
|
12
|
+
compatibleXacpxVersions?: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface PluginCompatibilityContext {
|
|
15
|
+
packageName: string;
|
|
16
|
+
currentWeacpxVersion: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function validatePluginCompatibility(metadata: PluginCompatibilityMetadata, context: PluginCompatibilityContext): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface KnownPlugin {
|
|
2
|
+
packageName: string;
|
|
3
|
+
channels: string[];
|
|
4
|
+
description: string;
|
|
5
|
+
official: true;
|
|
6
|
+
}
|
|
7
|
+
export declare function listKnownPlugins(): KnownPlugin[];
|
|
8
|
+
export declare function findKnownPluginByChannel(channelType: string): KnownPlugin | null;
|
|
9
|
+
export declare function getMovedChannelInstallHint(channelType: string): string | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ChannelPluginDefinition } from "../channels/plugin.js";
|
|
2
|
+
import { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION } from "./compatibility.js";
|
|
3
|
+
export { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, };
|
|
4
|
+
export interface WeacpxPlugin {
|
|
5
|
+
apiVersion: 1;
|
|
6
|
+
name?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Minimum core version required by this plugin (e.g. "0.8.0").
|
|
9
|
+
* First-party plugins must declare this; third-party plugins are encouraged to.
|
|
10
|
+
*
|
|
11
|
+
* The core was renamed weacpx→xacpx at 0.8.0. New plugins should prefer
|
|
12
|
+
* {@link minXacpxVersion}; the legacy `minWeacpxVersion` is still read for
|
|
13
|
+
* already-published plugins (when both are present, `minXacpxVersion` wins).
|
|
14
|
+
*/
|
|
15
|
+
minWeacpxVersion?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Optional explicit core compatibility range, e.g. ">=0.3.3" or "^0.3.3".
|
|
18
|
+
* If both a min version and a compatibility range are set, both must hold.
|
|
19
|
+
*/
|
|
20
|
+
compatibleWeacpxVersions?: string;
|
|
21
|
+
/** Preferred (post-rename) alias of {@link minWeacpxVersion}. */
|
|
22
|
+
minXacpxVersion?: string;
|
|
23
|
+
/** Preferred (post-rename) alias of {@link compatibleWeacpxVersions}. */
|
|
24
|
+
compatibleXacpxVersions?: string;
|
|
25
|
+
channels?: ChannelPluginDefinition[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Post-rename alias for {@link WeacpxPlugin}. New plugins should author against
|
|
29
|
+
* `XacpxPlugin`; the legacy name remains exported for backward compatibility.
|
|
30
|
+
*/
|
|
31
|
+
export type XacpxPlugin = WeacpxPlugin;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ConversationExecutorLane = "normal" | "control";
|
|
2
|
+
type ConversationTask<T> = () => Promise<T>;
|
|
3
|
+
export type ConversationExecutor = {
|
|
4
|
+
run<T>(conversationId: string, lane: ConversationExecutorLane, task: ConversationTask<T>, sessionKey?: string): Promise<T>;
|
|
5
|
+
};
|
|
6
|
+
export declare function createConversationExecutor(): ConversationExecutor;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized environment-variable access for the core (`xacpx`).
|
|
3
|
+
*
|
|
4
|
+
* The project was renamed `weacpx` → `xacpx` at 0.8.0. To keep existing
|
|
5
|
+
* deployments working, every core environment variable is read through
|
|
6
|
+
* {@link coreEnv}, which prefers the new `XACPX_` prefix but falls back to the
|
|
7
|
+
* legacy `WEACPX_` one. This is the single seam the rename hooks into — callers
|
|
8
|
+
* pass the bare suffix (e.g. `"CONFIG"`), never the full prefixed name.
|
|
9
|
+
*
|
|
10
|
+
* When the core *sets* an env var for one of its own subprocesses (daemon /
|
|
11
|
+
* bridge / mcp handshakes), it writes the canonical {@link coreEnvName} (the
|
|
12
|
+
* new `XACPX_` prefix); the same-generation reader resolves it via `coreEnv`,
|
|
13
|
+
* while any externally-set legacy `WEACPX_` value still wins fallback.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Read a core env var by its suffix, preferring `XACPX_<suffix>` and falling
|
|
17
|
+
* back to the legacy `WEACPX_<suffix>`. Returns `undefined` if neither is set.
|
|
18
|
+
*/
|
|
19
|
+
export declare function coreEnv(suffix: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The canonical (new-prefix) env var name for a suffix, e.g.
|
|
22
|
+
* `coreEnvName("DAEMON_RUN")` → `"XACPX_DAEMON_RUN"`. Use this when the core
|
|
23
|
+
* writes an env var for its own subprocess so the value is set under the
|
|
24
|
+
* current name; readers still resolve it through {@link coreEnv}.
|
|
25
|
+
*/
|
|
26
|
+
export declare function coreEnvName(suffix: string): string;
|
|
27
|
+
/** The legacy env var name for a suffix, e.g. `"WEACPX_CONFIG"`. */
|
|
28
|
+
export declare function legacyCoreEnvName(suffix: string): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-user state directory name (`<home>/.xacpx/`). This is the SINGLE
|
|
3
|
+
* source of truth for that name; every config / state / runtime / plugin path
|
|
4
|
+
* is built on top of it.
|
|
5
|
+
*
|
|
6
|
+
* The project was renamed `weacpx` → `xacpx` at 0.8.0. New installs use
|
|
7
|
+
* `~/.xacpx`; existing `~/.weacpx` directories are migrated once on first run
|
|
8
|
+
* (see `migrate-core-home.ts`). Until that migration runs (or while it is
|
|
9
|
+
* intentionally skipped because a legacy daemon is still alive),
|
|
10
|
+
* {@link coreHomeDir} keeps resolving to the legacy directory so the process
|
|
11
|
+
* operates on existing state rather than a fresh empty tree.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CORE_HOME_DIR_NAME = ".xacpx";
|
|
14
|
+
/** The pre-rename state directory name, kept for one-time migration / fallback. */
|
|
15
|
+
export declare const CORE_HOME_LEGACY_DIR_NAME = ".weacpx";
|
|
16
|
+
/**
|
|
17
|
+
* The core state root for a given user home.
|
|
18
|
+
*
|
|
19
|
+
* Resolution order: prefer `<home>/.xacpx` if it exists; otherwise fall back to
|
|
20
|
+
* an existing legacy `<home>/.weacpx` (so we keep reading/writing pre-rename
|
|
21
|
+
* state until it is migrated); otherwise return `<home>/.xacpx` for a fresh
|
|
22
|
+
* install. Pass the home directory the caller already resolved — this helper
|
|
23
|
+
* imposes no home-resolution policy of its own.
|
|
24
|
+
*/
|
|
25
|
+
export declare function coreHomeDir(home: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Display form for user-facing hints (e.g. "请查看日志:~/.xacpx/runtime/...").
|
|
28
|
+
* Keeps printed paths single-sourced with the canonical directory name. Always
|
|
29
|
+
* uses "/" separators since it is for display, not filesystem access.
|
|
30
|
+
*/
|
|
31
|
+
export declare function coreHomeDisplayPath(...segments: string[]): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type LaterTimeParseErrorCode = "missing_time" | "unrecognized_time" | "missing_message" | "past_today_time" | "too_soon" | "out_of_range";
|
|
2
|
+
export type LaterTimeParseResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
executeAt: Date;
|
|
5
|
+
messageStartIndex: number;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
code: LaterTimeParseErrorCode;
|
|
9
|
+
value?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function parseLaterTime(tokens: string[], now?: Date): LaterTimeParseResult;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ScheduledTaskRecord } from "./scheduled-types";
|
|
2
|
+
export declare function renderLaterHelp(): string;
|
|
3
|
+
export declare function renderLaterUnsupportedChannel(): string;
|
|
4
|
+
export declare function renderTaskCreated(task: ScheduledTaskRecord, displaySession: string): string;
|
|
5
|
+
export declare function renderLaterList(tasks: ScheduledTaskRecord[], displaySession: (internalAlias: string) => string): string;
|
|
6
|
+
export declare function preview(text: string): string;
|
|
7
|
+
export declare function formatLocalDateTime(date: Date): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AsyncMutex } from "../orchestration/async-mutex";
|
|
2
|
+
import type { StateStore } from "../state/state-store";
|
|
3
|
+
import type { AppState } from "../state/types";
|
|
4
|
+
import type { ScheduledSessionMode, ScheduledTaskRecord } from "./scheduled-types";
|
|
5
|
+
export interface CreateScheduledTaskInput {
|
|
6
|
+
chatKey: string;
|
|
7
|
+
sessionAlias: string;
|
|
8
|
+
executeAt: Date;
|
|
9
|
+
message: string;
|
|
10
|
+
sessionMode?: ScheduledSessionMode;
|
|
11
|
+
agent?: string;
|
|
12
|
+
workspace?: string;
|
|
13
|
+
accountId?: string;
|
|
14
|
+
replyContextToken?: string;
|
|
15
|
+
sourceLabel?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ScheduledTaskServiceOptions {
|
|
18
|
+
now?: () => Date;
|
|
19
|
+
generateId?: () => string;
|
|
20
|
+
stateMutex?: AsyncMutex;
|
|
21
|
+
}
|
|
22
|
+
export declare class ScheduledTaskService {
|
|
23
|
+
private readonly state;
|
|
24
|
+
private readonly stateStore;
|
|
25
|
+
private readonly now;
|
|
26
|
+
private readonly generateId;
|
|
27
|
+
private readonly stateMutex;
|
|
28
|
+
private readonly claimedInThisSession;
|
|
29
|
+
constructor(state: AppState, stateStore: Pick<StateStore, "save">, options?: ScheduledTaskServiceOptions);
|
|
30
|
+
createTask(input: CreateScheduledTaskInput): Promise<ScheduledTaskRecord>;
|
|
31
|
+
listPending(): ScheduledTaskRecord[];
|
|
32
|
+
cancelPending(inputId: string): Promise<boolean>;
|
|
33
|
+
markStartupMissed(): Promise<void>;
|
|
34
|
+
claimDueTasks(): Promise<ScheduledTaskRecord[]>;
|
|
35
|
+
markExecuted(id: string): Promise<void>;
|
|
36
|
+
markFailed(id: string, error: unknown): Promise<void>;
|
|
37
|
+
private nextId;
|
|
38
|
+
private mutate;
|
|
39
|
+
private save;
|
|
40
|
+
}
|
|
41
|
+
export declare function normalizeId(input: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const LATER_MIN_DELAY_MS = 10000;
|
|
2
|
+
export declare const LATER_MAX_DELAY_MS: number;
|
|
3
|
+
export declare const LATER_MESSAGE_PREVIEW_CHARS = 120;
|
|
4
|
+
export type ScheduledTaskStatus = "pending" | "triggering" | "executed" | "cancelled" | "missed" | "failed";
|
|
5
|
+
export type ScheduledSessionMode = "temp" | "bound";
|
|
6
|
+
export interface ScheduledTaskRecord {
|
|
7
|
+
id: string;
|
|
8
|
+
chat_key: string;
|
|
9
|
+
session_alias: string;
|
|
10
|
+
/** Absent ⇒ "bound" (legacy tasks created before temp mode existed). */
|
|
11
|
+
session_mode?: ScheduledSessionMode;
|
|
12
|
+
/** Agent snapshot at creation; only set for "temp" tasks. */
|
|
13
|
+
agent?: string;
|
|
14
|
+
/** Workspace snapshot at creation; only set for "temp" tasks. */
|
|
15
|
+
workspace?: string;
|
|
16
|
+
execute_at: string;
|
|
17
|
+
message: string;
|
|
18
|
+
status: ScheduledTaskStatus;
|
|
19
|
+
created_at: string;
|
|
20
|
+
account_id?: string;
|
|
21
|
+
reply_context_token?: string;
|
|
22
|
+
source_label?: string;
|
|
23
|
+
triggered_at?: string;
|
|
24
|
+
executed_at?: string;
|
|
25
|
+
cancelled_at?: string;
|
|
26
|
+
missed_at?: string;
|
|
27
|
+
failed_at?: string;
|
|
28
|
+
last_error?: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface ActiveTurnRegistry {
|
|
2
|
+
markActive(chatKey: string, alias: string): void;
|
|
3
|
+
markInactive(chatKey: string, alias: string): void;
|
|
4
|
+
isActive(chatKey: string, alias: string): boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function createActiveTurnRegistry(): ActiveTurnRegistry;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { AppConfig } from "../config/types";
|
|
2
|
+
import { AsyncMutex } from "../orchestration/async-mutex";
|
|
3
|
+
import type { StateStore } from "../state/state-store";
|
|
4
|
+
import type { AppState, BackgroundResult } from "../state/types";
|
|
5
|
+
import type { AgentSession, ResolvedSession } from "../transport/types";
|
|
6
|
+
interface SessionListItem {
|
|
7
|
+
alias: string;
|
|
8
|
+
internalAlias: string;
|
|
9
|
+
agent: string;
|
|
10
|
+
workspace: string;
|
|
11
|
+
isCurrent: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionSwitchResult {
|
|
14
|
+
alias: string;
|
|
15
|
+
agent: string;
|
|
16
|
+
workspace: string;
|
|
17
|
+
previousAlias?: string;
|
|
18
|
+
}
|
|
19
|
+
export type FuzzyAliasResult = {
|
|
20
|
+
kind: "match";
|
|
21
|
+
alias: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "ambiguous";
|
|
24
|
+
candidates: Array<{
|
|
25
|
+
alias: string;
|
|
26
|
+
agent: string;
|
|
27
|
+
workspace: string;
|
|
28
|
+
}>;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "none";
|
|
31
|
+
};
|
|
32
|
+
interface NativeSessionAttachmentInput {
|
|
33
|
+
alias: string;
|
|
34
|
+
agent: string;
|
|
35
|
+
workspace: string;
|
|
36
|
+
transportSession: string;
|
|
37
|
+
transportAgentCommand?: string;
|
|
38
|
+
agentSessionId: string;
|
|
39
|
+
title?: string | null;
|
|
40
|
+
updatedAt?: string;
|
|
41
|
+
}
|
|
42
|
+
interface NativeSessionListInput {
|
|
43
|
+
agent: string;
|
|
44
|
+
workspace?: string;
|
|
45
|
+
cwd: string;
|
|
46
|
+
sessions: AgentSession[];
|
|
47
|
+
nextCursor?: string | null;
|
|
48
|
+
}
|
|
49
|
+
interface NativeSessionListResult {
|
|
50
|
+
agent: string;
|
|
51
|
+
workspace?: string;
|
|
52
|
+
cwd: string;
|
|
53
|
+
sessions: AgentSession[];
|
|
54
|
+
nextCursor?: string | null;
|
|
55
|
+
}
|
|
56
|
+
interface SessionServiceOptions {
|
|
57
|
+
stateMutex?: AsyncMutex;
|
|
58
|
+
now?: () => number;
|
|
59
|
+
}
|
|
60
|
+
export declare class SessionService {
|
|
61
|
+
private readonly config;
|
|
62
|
+
private readonly stateStore;
|
|
63
|
+
private readonly state;
|
|
64
|
+
private readonly stateMutex;
|
|
65
|
+
private readonly now;
|
|
66
|
+
constructor(config: AppConfig, stateStore: Pick<StateStore, "save">, state: AppState, options?: SessionServiceOptions);
|
|
67
|
+
createSession(alias: string, agent: string, workspace: string): Promise<ResolvedSession>;
|
|
68
|
+
/**
|
|
69
|
+
* All currently-known logical sessions resolved to transport sessions, deduped by
|
|
70
|
+
* transport session. Sessions whose agent or workspace is no longer registered are
|
|
71
|
+
* skipped (toResolvedSession would throw). Used by shutdown cleanup to reap warm
|
|
72
|
+
* acpx queue owners; never throws.
|
|
73
|
+
*/
|
|
74
|
+
listAllResolvedSessions(): ResolvedSession[];
|
|
75
|
+
resolveSession(alias: string, agent: string, workspace: string, transportSession: string): ResolvedSession;
|
|
76
|
+
attachSession(alias: string, agent: string, workspace: string, transportSession: string, transportAgentCommand?: string): Promise<ResolvedSession>;
|
|
77
|
+
attachNativeSession(input: NativeSessionAttachmentInput): Promise<ResolvedSession>;
|
|
78
|
+
getSession(alias: string): Promise<ResolvedSession | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Synchronously resolve a session by its internal alias (as stored in state).
|
|
81
|
+
* Returns null if the alias is unknown or if the referenced agent/workspace is
|
|
82
|
+
* no longer registered (i.e. toResolvedSession would throw).
|
|
83
|
+
*
|
|
84
|
+
* Used by handlePrompt to honour a `boundSessionAlias` captured at dispatch
|
|
85
|
+
* time without requiring an async state mutation.
|
|
86
|
+
*/
|
|
87
|
+
getResolvedSessionByInternalAlias(alias: string): ResolvedSession | null;
|
|
88
|
+
peekCurrentSessionAlias(chatKey: string): string | undefined;
|
|
89
|
+
getPreferredSessionForTransport(transportSession: string): Promise<ResolvedSession | null>;
|
|
90
|
+
findAttachedNativeSession(chatKey: string, agent: string, agentSessionId: string): Promise<ResolvedSession | null>;
|
|
91
|
+
useSession(chatKey: string, alias: string): Promise<SessionSwitchResult>;
|
|
92
|
+
usePreviousSession(chatKey: string): Promise<SessionSwitchResult | null>;
|
|
93
|
+
setBackgroundResult(chatKey: string, alias: string, result: BackgroundResult): Promise<void>;
|
|
94
|
+
takeBackgroundResult(chatKey: string, alias: string): Promise<BackgroundResult | null>;
|
|
95
|
+
listBackgroundResultAliases(chatKey: string): string[];
|
|
96
|
+
resolveFuzzyAlias(chatKey: string, fragment: string): FuzzyAliasResult;
|
|
97
|
+
resolveAliasForChat(chatKey: string, displayAlias: string): Promise<string>;
|
|
98
|
+
buildDefaultTransportSessionForChat(chatKey: string, displayAlias: string): string;
|
|
99
|
+
listInternalAliases(): string[];
|
|
100
|
+
setCurrentSessionMode(chatKey: string, modeId: string | undefined): Promise<void>;
|
|
101
|
+
setCurrentSessionReplyMode(chatKey: string, replyMode: "stream" | "final" | "verbose" | undefined): Promise<void>;
|
|
102
|
+
getCurrentSession(chatKey: string): Promise<ResolvedSession | null>;
|
|
103
|
+
listSessions(chatKey: string): Promise<SessionListItem[]>;
|
|
104
|
+
countAliasesSharingTransport(transportSession: string, excludeAlias?: string): number;
|
|
105
|
+
removeSession(alias: string): Promise<{
|
|
106
|
+
wasActive: boolean;
|
|
107
|
+
}>;
|
|
108
|
+
cacheNativeSessionList(chatKey: string, input: NativeSessionListInput): Promise<void>;
|
|
109
|
+
getNativeSessionList(chatKey: string, ttlMs?: number): Promise<NativeSessionListResult | null>;
|
|
110
|
+
private deleteNativeSessionListIfCurrent;
|
|
111
|
+
private toResolvedSession;
|
|
112
|
+
setSessionTransportAgentCommand(alias: string, transportAgentCommand: string | undefined): Promise<void>;
|
|
113
|
+
private mutate;
|
|
114
|
+
private persist;
|
|
115
|
+
private createLogicalSession;
|
|
116
|
+
private validateSession;
|
|
117
|
+
}
|
|
118
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type AppState } from "./types";
|
|
2
|
+
export declare function parseState(raw: unknown, path: string): AppState;
|
|
3
|
+
export declare class StateStore {
|
|
4
|
+
private readonly path;
|
|
5
|
+
constructor(path: string);
|
|
6
|
+
load(): Promise<AppState>;
|
|
7
|
+
save(state: AppState): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type OrchestrationState } from "../orchestration/orchestration-types";
|
|
2
|
+
import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
|
|
3
|
+
export type LogicalSessionSource = "weacpx" | "agent-side";
|
|
4
|
+
export interface NativeSessionCacheEntry {
|
|
5
|
+
session_id: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
title?: string | null;
|
|
8
|
+
updated_at?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface NativeSessionListCacheRecord {
|
|
11
|
+
created_at: string;
|
|
12
|
+
agent: string;
|
|
13
|
+
workspace?: string;
|
|
14
|
+
cwd: string;
|
|
15
|
+
sessions: NativeSessionCacheEntry[];
|
|
16
|
+
next_cursor?: string | null;
|
|
17
|
+
}
|
|
18
|
+
export interface LogicalSession {
|
|
19
|
+
alias: string;
|
|
20
|
+
agent: string;
|
|
21
|
+
workspace: string;
|
|
22
|
+
transport_session: string;
|
|
23
|
+
source?: LogicalSessionSource;
|
|
24
|
+
agent_session_id?: string;
|
|
25
|
+
agent_session_title?: string;
|
|
26
|
+
agent_session_updated_at?: string;
|
|
27
|
+
attached_at?: string;
|
|
28
|
+
transport_agent_command?: string;
|
|
29
|
+
mode_id?: string;
|
|
30
|
+
reply_mode?: "stream" | "final" | "verbose";
|
|
31
|
+
created_at: string;
|
|
32
|
+
last_used_at: string;
|
|
33
|
+
}
|
|
34
|
+
export interface BackgroundResult {
|
|
35
|
+
text: string;
|
|
36
|
+
status: "done" | "error";
|
|
37
|
+
finished_at: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ChatContextState {
|
|
40
|
+
current_session: string;
|
|
41
|
+
previous_session?: string;
|
|
42
|
+
background_results?: Record<string, BackgroundResult>;
|
|
43
|
+
}
|
|
44
|
+
export interface AppState {
|
|
45
|
+
sessions: Record<string, LogicalSession>;
|
|
46
|
+
chat_contexts: Record<string, ChatContextState>;
|
|
47
|
+
native_session_lists: Record<string, NativeSessionListCacheRecord>;
|
|
48
|
+
orchestration: OrchestrationState;
|
|
49
|
+
scheduled_tasks: Record<string, ScheduledTaskRecord>;
|
|
50
|
+
}
|
|
51
|
+
export declare function createEmptyState(): AppState;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolUseEvent } from "../channels/types.js";
|
|
2
|
+
export type ToolEventMode = "text" | "structured" | "both";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the effective tool-event rendering mode.
|
|
5
|
+
*
|
|
6
|
+
* Resolution order (hard contract — preserves Phase 0 invariant):
|
|
7
|
+
* 1. Explicit `toolEventMode` always wins.
|
|
8
|
+
* 2. `onToolEvent` present → "structured" (structured consumer, suppress text tool calls).
|
|
9
|
+
* 3. Default → "text" (legacy text tool calls; no structured consumer).
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveToolEventMode(input?: {
|
|
12
|
+
toolEventMode?: ToolEventMode;
|
|
13
|
+
onToolEvent?: (event: ToolUseEvent) => void | Promise<void>;
|
|
14
|
+
}): ToolEventMode;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { NonInteractivePermissions, PermissionMode } from "../config/types";
|
|
2
|
+
import type { QuotaManager } from "../weixin/messaging/quota-manager.js";
|
|
3
|
+
import type { ToolUseEvent } from "../channels/types.js";
|
|
4
|
+
import type { ToolEventMode } from "./tool-event-mode.js";
|
|
5
|
+
export type { ToolEventMode } from "./tool-event-mode.js";
|
|
6
|
+
export interface ReplyQuotaContext {
|
|
7
|
+
chatKey: string;
|
|
8
|
+
quota: QuotaManager;
|
|
9
|
+
}
|
|
10
|
+
export interface PromptMedia {
|
|
11
|
+
type: "image" | "audio" | "video" | "file";
|
|
12
|
+
filePath: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
fileName?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface PermissionPolicy {
|
|
17
|
+
permissionMode: PermissionMode;
|
|
18
|
+
nonInteractivePermissions: NonInteractivePermissions;
|
|
19
|
+
permissionPolicy?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ResolvedSession {
|
|
22
|
+
alias: string;
|
|
23
|
+
agent: string;
|
|
24
|
+
agentCommand?: string;
|
|
25
|
+
workspace: string;
|
|
26
|
+
transportSession: string;
|
|
27
|
+
source?: "weacpx" | "agent-side";
|
|
28
|
+
agentSessionId?: string;
|
|
29
|
+
agentSessionTitle?: string;
|
|
30
|
+
agentSessionUpdatedAt?: string;
|
|
31
|
+
attachedAt?: string;
|
|
32
|
+
mcpCoordinatorSession?: string;
|
|
33
|
+
mcpSourceHandle?: string;
|
|
34
|
+
modeId?: string;
|
|
35
|
+
replyMode?: "stream" | "final" | "verbose";
|
|
36
|
+
cwd: string;
|
|
37
|
+
/**
|
|
38
|
+
* True for a non-persisted, single-use session (e.g. a `/later` temp-mode
|
|
39
|
+
* scheduled run). Transport errors for such a session must not suggest
|
|
40
|
+
* `/session new`/`attach`, and missing-session recovery (which mutates
|
|
41
|
+
* persisted state by alias) does not apply.
|
|
42
|
+
*/
|
|
43
|
+
transient?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface AgentSession {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
cwd?: string;
|
|
48
|
+
title?: string | null;
|
|
49
|
+
updatedAt?: string;
|
|
50
|
+
_meta?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
export interface AgentSessionListQuery {
|
|
53
|
+
agent: string;
|
|
54
|
+
agentCommand?: string;
|
|
55
|
+
cwd: string;
|
|
56
|
+
cursor?: string;
|
|
57
|
+
filterCwd?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface AgentSessionListResult {
|
|
60
|
+
source: "agent";
|
|
61
|
+
sessions: AgentSession[];
|
|
62
|
+
cursor?: string;
|
|
63
|
+
nextCursor?: string | null;
|
|
64
|
+
cwd?: string;
|
|
65
|
+
}
|
|
66
|
+
export type EnsureSessionProgressStage = "spawn" | "initializing" | "ready";
|
|
67
|
+
export type EnsureSessionProgress = EnsureSessionProgressStage | {
|
|
68
|
+
kind: "note";
|
|
69
|
+
text: string;
|
|
70
|
+
};
|
|
71
|
+
export type PromptMediaInput = PromptMedia | PromptMedia[];
|
|
72
|
+
export interface PromptOptions {
|
|
73
|
+
onSegment?: (text: string) => void | Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Structured side-channel for tool calls. See `toolEventMode` for routing.
|
|
76
|
+
*
|
|
77
|
+
* Async semantics: callbacks are invoked in event order and serialized —
|
|
78
|
+
* each invocation is awaited before the next is dispatched. The transport
|
|
79
|
+
* waits for all callbacks to settle before resolving the prompt. If any
|
|
80
|
+
* invocation throws or returns a rejected promise, the prompt rejects
|
|
81
|
+
* with the first observed error (matching `onSegment` behavior).
|
|
82
|
+
*/
|
|
83
|
+
onToolEvent?: (event: ToolUseEvent) => void | Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Optional structured side-channel for the agent's thinking/reasoning.
|
|
86
|
+
*
|
|
87
|
+
* Each acpx `agent_thought_chunk` is forwarded raw (no buffering, no
|
|
88
|
+
* paragraph splitting). Channels that register this callback opt in to
|
|
89
|
+
* receiving thoughts and are responsible for their own accumulation /
|
|
90
|
+
* rendering. When omitted, thought chunks are dropped at the transport
|
|
91
|
+
* boundary — the built-in WeChat channel does not register it.
|
|
92
|
+
*
|
|
93
|
+
* Async semantics match `onSegment`: invocations are serialized and the
|
|
94
|
+
* transport awaits all of them before resolving the prompt; the first
|
|
95
|
+
* error observed rejects the prompt.
|
|
96
|
+
*/
|
|
97
|
+
onThought?: (chunk: string) => void | Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* How tool_call / tool_call_update events are surfaced for this prompt.
|
|
100
|
+
*
|
|
101
|
+
* - "text" (default when no handler): legacy emoji-prefixed segments in the reply stream.
|
|
102
|
+
* - "structured" (default when a handler is provided): events go to `onToolEvent` only.
|
|
103
|
+
* - "both": events go to `onToolEvent` AND legacy text segments — useful for migration.
|
|
104
|
+
*
|
|
105
|
+
* Resolved at the transport boundary via `resolveToolEventMode`.
|
|
106
|
+
*/
|
|
107
|
+
toolEventMode?: ToolEventMode;
|
|
108
|
+
media?: PromptMediaInput;
|
|
109
|
+
}
|
|
110
|
+
export interface SessionTransport {
|
|
111
|
+
ensureSession(session: ResolvedSession, onProgress?: (progress: EnsureSessionProgress) => void): Promise<void>;
|
|
112
|
+
tailSessionHistory(session: ResolvedSession, lines: number): Promise<{
|
|
113
|
+
text: string;
|
|
114
|
+
}>;
|
|
115
|
+
prompt(session: ResolvedSession, text: string, reply?: (text: string) => Promise<void>, replyContext?: ReplyQuotaContext, options?: PromptOptions): Promise<{
|
|
116
|
+
text: string;
|
|
117
|
+
}>;
|
|
118
|
+
setMode(session: ResolvedSession, modeId: string): Promise<void>;
|
|
119
|
+
cancel(session: ResolvedSession): Promise<{
|
|
120
|
+
cancelled: boolean;
|
|
121
|
+
message: string;
|
|
122
|
+
}>;
|
|
123
|
+
hasSession(session: ResolvedSession): Promise<boolean>;
|
|
124
|
+
listAgentSessions?(query: AgentSessionListQuery): Promise<AgentSessionListResult | undefined>;
|
|
125
|
+
resumeAgentSession?(session: ResolvedSession, agentSessionId: string): Promise<void>;
|
|
126
|
+
removeSession?(session: ResolvedSession): Promise<void>;
|
|
127
|
+
updatePermissionPolicy?(policy: PermissionPolicy): Promise<void>;
|
|
128
|
+
dispose?(): Promise<void>;
|
|
129
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare function writePrivateFileAtomic(path: string, content: string): Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* Synchronous private-file write for hot-path callers that cannot await
|
|
4
|
+
* (e.g. per-message weixin credential/sync-buf/context-token persistence).
|
|
5
|
+
* Atomic via write-file-atomic's temp+rename, created at 0600 so the secret is
|
|
6
|
+
* never momentarily world-readable. No cross-process lock: weixin's per-account
|
|
7
|
+
* consumer lock already serializes the single writing daemon.
|
|
8
|
+
*/
|
|
9
|
+
interface WritePrivateFileSyncDeps {
|
|
10
|
+
platform?: NodeJS.Platform;
|
|
11
|
+
atomicWrite?: (path: string, content: string) => void;
|
|
12
|
+
directWrite?: (path: string, content: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function writePrivateFileSync(path: string, content: string, deps?: WritePrivateFileSyncDeps): void;
|
|
15
|
+
interface RetryTransientWriteOptions {
|
|
16
|
+
platform?: NodeJS.Platform;
|
|
17
|
+
maxAttempts?: number;
|
|
18
|
+
baseDelayMs?: number;
|
|
19
|
+
maxDelayMs?: number;
|
|
20
|
+
delay?: (ms: number) => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export declare function retryTransientWriteErrors(run: () => Promise<void>, options?: RetryTransientWriteOptions): Promise<void>;
|
|
23
|
+
export declare const __privateFileForTests: {
|
|
24
|
+
retryTransientWriteErrors: typeof retryTransientWriteErrors;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SanitizeOptions {
|
|
2
|
+
allow?: RegExp;
|
|
3
|
+
deny?: RegExp;
|
|
4
|
+
replacement?: string;
|
|
5
|
+
collapse?: boolean;
|
|
6
|
+
trim?: boolean;
|
|
7
|
+
lowercase?: boolean;
|
|
8
|
+
fallback?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function sanitizeString(input: string, options?: SanitizeOptions): string;
|