weacpx 0.5.2 → 0.6.1
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/README.md +15 -3
- package/dist/bridge/bridge-main.js +160 -4
- package/dist/channels/channel-scope.d.ts +8 -0
- package/dist/channels/types.d.ts +11 -0
- package/dist/channels/weixin-channel.d.ts +1 -0
- package/dist/cli.js +1115 -119
- 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 +37 -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 +175 -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/formatting/render-text.d.ts +23 -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/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/plugin-api.d.ts +1 -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/session-service.d.ts +83 -0
- package/dist/state/state-store.d.ts +8 -0
- package/dist/state/types.d.ts +44 -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/sanitize.d.ts +10 -0
- package/dist/util/text.d.ts +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/weixin/auth/accounts.d.ts +0 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2088,36 +2088,56 @@ var init_private_file = __esm(() => {
|
|
|
2088
2088
|
import_write_file_atomic = __toESM(require_lib(), 1);
|
|
2089
2089
|
});
|
|
2090
2090
|
|
|
2091
|
-
// src/
|
|
2092
|
-
import { access } from "node:fs/promises";
|
|
2093
|
-
import { homedir } from "node:os";
|
|
2091
|
+
// src/util/path.ts
|
|
2094
2092
|
import path from "node:path";
|
|
2095
|
-
|
|
2093
|
+
import { homedir } from "node:os";
|
|
2094
|
+
function normalizePath(input) {
|
|
2096
2095
|
const expanded = expandHome(input);
|
|
2097
2096
|
if (isWindowsLikePath(expanded)) {
|
|
2098
2097
|
return path.win32.normalize(expanded).replace(/\\/g, "/");
|
|
2099
2098
|
}
|
|
2100
2099
|
return path.posix.normalize(expanded.replace(/\\/g, "/"));
|
|
2101
2100
|
}
|
|
2102
|
-
function
|
|
2103
|
-
const normalized =
|
|
2101
|
+
function basenameForPath(input) {
|
|
2102
|
+
const normalized = normalizePath(input);
|
|
2104
2103
|
if (ROOT_PATH_RE.test(normalized)) {
|
|
2105
2104
|
return normalized;
|
|
2106
2105
|
}
|
|
2107
2106
|
const base = path.posix.basename(normalized);
|
|
2108
2107
|
return base || normalized;
|
|
2109
2108
|
}
|
|
2110
|
-
function
|
|
2111
|
-
const normalizedLeft =
|
|
2112
|
-
const normalizedRight =
|
|
2109
|
+
function isSamePath(left, right) {
|
|
2110
|
+
const normalizedLeft = normalizePath(left);
|
|
2111
|
+
const normalizedRight = normalizePath(right);
|
|
2113
2112
|
if (isWindowsLikePath(normalizedLeft) || isWindowsLikePath(normalizedRight)) {
|
|
2114
2113
|
return normalizedLeft.toLowerCase() === normalizedRight.toLowerCase();
|
|
2115
2114
|
}
|
|
2116
2115
|
return normalizedLeft === normalizedRight;
|
|
2117
2116
|
}
|
|
2117
|
+
function isWindowsLikePath(input) {
|
|
2118
|
+
return WINDOWS_DRIVE_PATH_RE.test(input) || WINDOWS_UNC_PATH_RE.test(input);
|
|
2119
|
+
}
|
|
2118
2120
|
function expandHome(input) {
|
|
2119
2121
|
return input.startsWith("~") ? homedir() + input.slice(1) : input;
|
|
2120
2122
|
}
|
|
2123
|
+
var WINDOWS_DRIVE_PATH_RE, WINDOWS_UNC_PATH_RE, ROOT_PATH_RE;
|
|
2124
|
+
var init_path = __esm(() => {
|
|
2125
|
+
WINDOWS_DRIVE_PATH_RE = /^[a-zA-Z]:[\\/]/;
|
|
2126
|
+
WINDOWS_UNC_PATH_RE = /^\\\\/;
|
|
2127
|
+
ROOT_PATH_RE = /^(\/|[a-zA-Z]:\/?)$/;
|
|
2128
|
+
});
|
|
2129
|
+
|
|
2130
|
+
// src/commands/workspace-path.ts
|
|
2131
|
+
import { access } from "node:fs/promises";
|
|
2132
|
+
function normalizeWorkspacePath(input) {
|
|
2133
|
+
return normalizePath(input);
|
|
2134
|
+
}
|
|
2135
|
+
function basenameForWorkspacePath(input) {
|
|
2136
|
+
return basenameForPath(input);
|
|
2137
|
+
}
|
|
2138
|
+
function sameWorkspacePath(left, right) {
|
|
2139
|
+
return isSamePath(left, right);
|
|
2140
|
+
}
|
|
2121
2141
|
async function pathExists(filePath) {
|
|
2122
2142
|
try {
|
|
2123
2143
|
await access(filePath);
|
|
@@ -2126,14 +2146,8 @@ async function pathExists(filePath) {
|
|
|
2126
2146
|
return false;
|
|
2127
2147
|
}
|
|
2128
2148
|
}
|
|
2129
|
-
function isWindowsLikePath(input) {
|
|
2130
|
-
return WINDOWS_DRIVE_PATH_RE.test(input) || WINDOWS_UNC_PATH_RE.test(input);
|
|
2131
|
-
}
|
|
2132
|
-
var WINDOWS_DRIVE_PATH_RE, WINDOWS_UNC_PATH_RE, ROOT_PATH_RE;
|
|
2133
2149
|
var init_workspace_path = __esm(() => {
|
|
2134
|
-
|
|
2135
|
-
WINDOWS_UNC_PATH_RE = /^\\\\/;
|
|
2136
|
-
ROOT_PATH_RE = /^(\/|[a-zA-Z]:\/?)$/;
|
|
2150
|
+
init_path();
|
|
2137
2151
|
});
|
|
2138
2152
|
|
|
2139
2153
|
// src/config/resolve-agent-command.ts
|
|
@@ -9688,8 +9702,10 @@ function readVersion(moduleUrl = import.meta.url) {
|
|
|
9688
9702
|
}
|
|
9689
9703
|
return "unknown";
|
|
9690
9704
|
}
|
|
9691
|
-
var PACKAGE_NAME = "weacpx";
|
|
9692
|
-
var init_version = () => {
|
|
9705
|
+
var PACKAGE_NAME = "weacpx", WEACPX_CORE_VERSION;
|
|
9706
|
+
var init_version = __esm(() => {
|
|
9707
|
+
WEACPX_CORE_VERSION = readVersion();
|
|
9708
|
+
});
|
|
9693
9709
|
|
|
9694
9710
|
// src/orchestration/task-watch-timeouts.ts
|
|
9695
9711
|
var DEFAULT_TASK_WATCH_TIMEOUT_MS = 60000, MAX_TASK_WATCH_TIMEOUT_MS, DEFAULT_TASK_WATCH_POLL_INTERVAL_MS = 1000, MAX_TASK_WATCH_POLL_INTERVAL_MS = 1e4, TASK_WATCH_RPC_TIMEOUT_PADDING_MS = 5000;
|
|
@@ -9713,10 +9729,60 @@ var init_quota_errors = __esm(() => {
|
|
|
9713
9729
|
};
|
|
9714
9730
|
});
|
|
9715
9731
|
|
|
9732
|
+
// src/util/sanitize.ts
|
|
9733
|
+
function sanitizeString(input, options = {}) {
|
|
9734
|
+
const {
|
|
9735
|
+
replacement = "-",
|
|
9736
|
+
collapse = false,
|
|
9737
|
+
trim = false,
|
|
9738
|
+
lowercase: lowercase2 = false,
|
|
9739
|
+
fallback
|
|
9740
|
+
} = options;
|
|
9741
|
+
let result = lowercase2 ? input.toLowerCase() : input;
|
|
9742
|
+
if (options.allow) {
|
|
9743
|
+
const pattern = new RegExp(`[^${options.allow.source.slice(1, -1)}]+`, "g");
|
|
9744
|
+
result = result.replace(pattern, replacement);
|
|
9745
|
+
} else if (options.deny) {
|
|
9746
|
+
result = result.replace(options.deny, replacement);
|
|
9747
|
+
}
|
|
9748
|
+
if (collapse) {
|
|
9749
|
+
const escaped = escapeRegExp(replacement);
|
|
9750
|
+
result = result.replace(new RegExp(`${escaped}+`, "g"), replacement);
|
|
9751
|
+
}
|
|
9752
|
+
if (trim) {
|
|
9753
|
+
const escaped = escapeRegExp(replacement);
|
|
9754
|
+
result = result.replace(new RegExp(`^${escaped}+|${escaped}+$`, "g"), "");
|
|
9755
|
+
}
|
|
9756
|
+
if (fallback !== undefined && result.length === 0) {
|
|
9757
|
+
return fallback;
|
|
9758
|
+
}
|
|
9759
|
+
return result;
|
|
9760
|
+
}
|
|
9761
|
+
function escapeRegExp(s) {
|
|
9762
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9763
|
+
}
|
|
9764
|
+
|
|
9765
|
+
// src/util/text.ts
|
|
9766
|
+
function truncateText(text, maxLength, ellipsis = "…") {
|
|
9767
|
+
if (text.length <= maxLength)
|
|
9768
|
+
return text;
|
|
9769
|
+
return text.slice(0, maxLength - ellipsis.length) + ellipsis;
|
|
9770
|
+
}
|
|
9771
|
+
function escapeForDoubleQuotes(input) {
|
|
9772
|
+
return input.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
9773
|
+
}
|
|
9774
|
+
function quoteIfNeeded(input) {
|
|
9775
|
+
return `"${escapeForDoubleQuotes(input)}"`;
|
|
9776
|
+
}
|
|
9777
|
+
|
|
9716
9778
|
// src/commands/workspace-name.ts
|
|
9717
9779
|
function sanitizeWorkspaceName(input, fallback = "workspace") {
|
|
9718
|
-
|
|
9719
|
-
|
|
9780
|
+
return sanitizeString(input.trim(), {
|
|
9781
|
+
allow: /[a-zA-Z0-9._-]/,
|
|
9782
|
+
replacement: "-",
|
|
9783
|
+
trim: true,
|
|
9784
|
+
fallback
|
|
9785
|
+
});
|
|
9720
9786
|
}
|
|
9721
9787
|
function allocateWorkspaceName(base, existing) {
|
|
9722
9788
|
if (!Object.prototype.hasOwnProperty.call(existing, base))
|
|
@@ -9732,13 +9798,11 @@ function isWorkspaceNameValid(input) {
|
|
|
9732
9798
|
function quoteWorkspaceNameIfNeeded(input) {
|
|
9733
9799
|
if (isWorkspaceNameValid(input))
|
|
9734
9800
|
return input;
|
|
9735
|
-
return
|
|
9801
|
+
return quoteIfNeeded(input);
|
|
9736
9802
|
}
|
|
9737
|
-
var VALID_WORKSPACE_NAME_RE
|
|
9803
|
+
var VALID_WORKSPACE_NAME_RE;
|
|
9738
9804
|
var init_workspace_name = __esm(() => {
|
|
9739
9805
|
VALID_WORKSPACE_NAME_RE = /^[a-zA-Z0-9._-]+$/;
|
|
9740
|
-
UNSAFE_RUN_RE = /[^a-zA-Z0-9._-]+/g;
|
|
9741
|
-
TRIM_DASHES_RE = /^-+|-+$/g;
|
|
9742
9806
|
});
|
|
9743
9807
|
|
|
9744
9808
|
// src/orchestration/orchestration-types.ts
|
|
@@ -9759,6 +9823,7 @@ function createEmptyState() {
|
|
|
9759
9823
|
return {
|
|
9760
9824
|
sessions: {},
|
|
9761
9825
|
chat_contexts: {},
|
|
9826
|
+
native_session_lists: {},
|
|
9762
9827
|
orchestration: createEmptyOrchestrationState(),
|
|
9763
9828
|
scheduled_tasks: {}
|
|
9764
9829
|
};
|
|
@@ -9977,11 +10042,14 @@ function parseOrchestrationState(raw, path3) {
|
|
|
9977
10042
|
function isReplyMode2(value) {
|
|
9978
10043
|
return value === "stream" || value === "final" || value === "verbose";
|
|
9979
10044
|
}
|
|
10045
|
+
function isSessionSource(value) {
|
|
10046
|
+
return value === undefined || value === "weacpx" || value === "agent-side";
|
|
10047
|
+
}
|
|
9980
10048
|
function isSessionRecord(value) {
|
|
9981
10049
|
if (!isRecord2(value)) {
|
|
9982
10050
|
return false;
|
|
9983
10051
|
}
|
|
9984
|
-
return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && isOptionalString(value.transport_agent_command) && isOptionalString(value.mode_id) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
10052
|
+
return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && 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.mode_id) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
9985
10053
|
}
|
|
9986
10054
|
function parseSessions(raw, path3) {
|
|
9987
10055
|
const sessions = {};
|
|
@@ -10006,6 +10074,30 @@ function parseChatContexts(raw, path3) {
|
|
|
10006
10074
|
}
|
|
10007
10075
|
return chatContexts;
|
|
10008
10076
|
}
|
|
10077
|
+
function isNativeSessionCacheEntry(value) {
|
|
10078
|
+
if (!isRecord2(value)) {
|
|
10079
|
+
return false;
|
|
10080
|
+
}
|
|
10081
|
+
return isString(value.session_id) && isOptionalString(value.cwd) && (value.title === undefined || value.title === null || isString(value.title)) && isOptionalString(value.updated_at);
|
|
10082
|
+
}
|
|
10083
|
+
function isNativeSessionListCacheRecord(value) {
|
|
10084
|
+
if (!isRecord2(value)) {
|
|
10085
|
+
return false;
|
|
10086
|
+
}
|
|
10087
|
+
return isString(value.created_at) && isString(value.agent) && isOptionalString(value.workspace) && isString(value.cwd) && Array.isArray(value.sessions) && value.sessions.every(isNativeSessionCacheEntry) && (value.next_cursor === undefined || value.next_cursor === null || isString(value.next_cursor));
|
|
10088
|
+
}
|
|
10089
|
+
function parseNativeSessionLists(raw) {
|
|
10090
|
+
if (!isRecord2(raw)) {
|
|
10091
|
+
return {};
|
|
10092
|
+
}
|
|
10093
|
+
const nativeSessionLists = {};
|
|
10094
|
+
for (const [chatKey, value] of Object.entries(raw)) {
|
|
10095
|
+
if (isNativeSessionListCacheRecord(value)) {
|
|
10096
|
+
nativeSessionLists[chatKey] = value;
|
|
10097
|
+
}
|
|
10098
|
+
}
|
|
10099
|
+
return nativeSessionLists;
|
|
10100
|
+
}
|
|
10009
10101
|
function isScheduledTaskStatus(value) {
|
|
10010
10102
|
return value === "pending" || value === "triggering" || value === "executed" || value === "cancelled" || value === "missed" || value === "failed";
|
|
10011
10103
|
}
|
|
@@ -10050,6 +10142,7 @@ function parseState(raw, path3) {
|
|
|
10050
10142
|
return {
|
|
10051
10143
|
sessions: parsedSessions,
|
|
10052
10144
|
chat_contexts: parseChatContexts(chatContexts, path3),
|
|
10145
|
+
native_session_lists: parseNativeSessionLists(raw.native_session_lists),
|
|
10053
10146
|
orchestration,
|
|
10054
10147
|
scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, path3)
|
|
10055
10148
|
};
|
|
@@ -10167,6 +10260,13 @@ function resolveSessionAliasForInput(channelId, displayAlias, existingAliases) {
|
|
|
10167
10260
|
}
|
|
10168
10261
|
return scopedAlias;
|
|
10169
10262
|
}
|
|
10263
|
+
function scopeDisplayAliasToInternal(channelId, displayAlias) {
|
|
10264
|
+
const normalized = displayAlias.trim();
|
|
10265
|
+
if (normalized.length === 0) {
|
|
10266
|
+
throw new Error("display session alias must be non-empty");
|
|
10267
|
+
}
|
|
10268
|
+
return channelId === "weixin" ? normalized : toInternalSessionAlias(channelId, normalized);
|
|
10269
|
+
}
|
|
10170
10270
|
function buildDefaultTransportSession(channelId, displayAlias) {
|
|
10171
10271
|
const normalized = displayAlias.trim();
|
|
10172
10272
|
if (normalized.length === 0) {
|
|
@@ -10252,7 +10352,7 @@ function renderLaterList(tasks, displaySession) {
|
|
|
10252
10352
|
`).trimEnd();
|
|
10253
10353
|
}
|
|
10254
10354
|
function preview(text) {
|
|
10255
|
-
return text
|
|
10355
|
+
return truncateText(text, LATER_MESSAGE_PREVIEW_CHARS);
|
|
10256
10356
|
}
|
|
10257
10357
|
function formatLocalDateTime(date4) {
|
|
10258
10358
|
const weekdays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
|
|
@@ -10398,7 +10498,10 @@ class ScheduledTaskService {
|
|
|
10398
10498
|
}
|
|
10399
10499
|
nextId() {
|
|
10400
10500
|
for (let attempt = 0;attempt < 20; attempt += 1) {
|
|
10401
|
-
const id = normalizeId(this.generateId())
|
|
10501
|
+
const id = sanitizeString(normalizeId(this.generateId()), {
|
|
10502
|
+
allow: /[0-9a-z]/,
|
|
10503
|
+
replacement: ""
|
|
10504
|
+
}).slice(0, 6);
|
|
10402
10505
|
if (id.length >= 4 && !this.state.scheduled_tasks[id])
|
|
10403
10506
|
return id;
|
|
10404
10507
|
}
|
|
@@ -10412,12 +10515,16 @@ class ScheduledTaskService {
|
|
|
10412
10515
|
}
|
|
10413
10516
|
}
|
|
10414
10517
|
function normalizeId(input) {
|
|
10415
|
-
return input.trim()
|
|
10518
|
+
return sanitizeString(input.trim(), {
|
|
10519
|
+
deny: /^#/,
|
|
10520
|
+
replacement: "",
|
|
10521
|
+
lowercase: true
|
|
10522
|
+
});
|
|
10416
10523
|
}
|
|
10417
10524
|
var init_scheduled_service = () => {};
|
|
10418
10525
|
|
|
10419
10526
|
// src/plugins/plugin-home.ts
|
|
10420
|
-
import { mkdir as mkdir6, writeFile as writeFile4 } from "node:fs/promises";
|
|
10527
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
10421
10528
|
import { homedir as homedir3 } from "node:os";
|
|
10422
10529
|
import { join as join3 } from "node:path";
|
|
10423
10530
|
function coerceMissing(value) {
|
|
@@ -10441,6 +10548,27 @@ function resolvePluginHome(input = {}) {
|
|
|
10441
10548
|
const home = coerceMissing(input.home) ?? coerceMissing(process.env.HOME) ?? homedir3();
|
|
10442
10549
|
return join3(home, ".weacpx", "plugins");
|
|
10443
10550
|
}
|
|
10551
|
+
async function normalizePluginHomeManifest(pluginHome) {
|
|
10552
|
+
const manifestPath = join3(pluginHome, "package.json");
|
|
10553
|
+
let raw;
|
|
10554
|
+
try {
|
|
10555
|
+
raw = await readFile6(manifestPath, "utf8");
|
|
10556
|
+
} catch {
|
|
10557
|
+
return false;
|
|
10558
|
+
}
|
|
10559
|
+
let parsed;
|
|
10560
|
+
try {
|
|
10561
|
+
parsed = JSON.parse(raw);
|
|
10562
|
+
} catch {
|
|
10563
|
+
return false;
|
|
10564
|
+
}
|
|
10565
|
+
const normalized = JSON.stringify(parsed, null, 2) + `
|
|
10566
|
+
`;
|
|
10567
|
+
if (normalized === raw)
|
|
10568
|
+
return false;
|
|
10569
|
+
await writeFile4(manifestPath, normalized, { mode: 384 });
|
|
10570
|
+
return true;
|
|
10571
|
+
}
|
|
10444
10572
|
async function ensurePluginHome(pluginHome) {
|
|
10445
10573
|
await mkdir6(pluginHome, { recursive: true, mode: 448 });
|
|
10446
10574
|
await writeFile4(join3(pluginHome, "package.json"), JSON.stringify({ private: true, type: "module" }, null, 2) + `
|
|
@@ -10479,7 +10607,11 @@ var init_state_dir = () => {};
|
|
|
10479
10607
|
import fs3 from "node:fs";
|
|
10480
10608
|
import path4 from "node:path";
|
|
10481
10609
|
function normalizeAccountId(raw) {
|
|
10482
|
-
return raw.trim()
|
|
10610
|
+
return sanitizeString(raw.trim(), {
|
|
10611
|
+
deny: /[@.]/g,
|
|
10612
|
+
replacement: "-",
|
|
10613
|
+
lowercase: true
|
|
10614
|
+
});
|
|
10483
10615
|
}
|
|
10484
10616
|
function deriveRawAccountId(normalizedId) {
|
|
10485
10617
|
if (normalizedId.endsWith("-im-bot")) {
|
|
@@ -12988,16 +13120,24 @@ class RuntimeMediaStore {
|
|
|
12988
13120
|
}
|
|
12989
13121
|
function sanitizeMediaFileName(fileName, mimeType) {
|
|
12990
13122
|
const base = path7.basename(fileName.trim() || "attachment");
|
|
12991
|
-
const
|
|
12992
|
-
|
|
13123
|
+
const safe = sanitizeString(base, {
|
|
13124
|
+
deny: /[\\/:*?"<>|\s]+/g,
|
|
13125
|
+
replacement: "-",
|
|
13126
|
+
trim: true,
|
|
13127
|
+
fallback: "attachment"
|
|
13128
|
+
});
|
|
12993
13129
|
const ext = path7.extname(safe);
|
|
12994
13130
|
if (ext)
|
|
12995
13131
|
return safe;
|
|
12996
13132
|
return `${safe}${extensionFromMime(mimeType)}`;
|
|
12997
13133
|
}
|
|
12998
13134
|
function safePathSegment(value) {
|
|
12999
|
-
|
|
13000
|
-
|
|
13135
|
+
return sanitizeString(value, {
|
|
13136
|
+
allow: /[A-Za-z0-9._-]/,
|
|
13137
|
+
replacement: "_",
|
|
13138
|
+
trim: true,
|
|
13139
|
+
fallback: "unknown"
|
|
13140
|
+
});
|
|
13001
13141
|
}
|
|
13002
13142
|
async function uniqueFileName(dir, baseName) {
|
|
13003
13143
|
const ext = path7.extname(baseName);
|
|
@@ -15985,7 +16125,7 @@ var init_scheduled_turn = __esm(() => {
|
|
|
15985
16125
|
});
|
|
15986
16126
|
|
|
15987
16127
|
// src/weixin/monitor/consumer-lock.ts
|
|
15988
|
-
import { mkdir as mkdir8, open as open3, readFile as
|
|
16128
|
+
import { mkdir as mkdir8, open as open3, readFile as readFile7, rm as rm6 } from "node:fs/promises";
|
|
15989
16129
|
import { dirname as dirname8, join as join5 } from "node:path";
|
|
15990
16130
|
import { homedir as homedir4 } from "node:os";
|
|
15991
16131
|
function createWeixinConsumerLock(options = {}) {
|
|
@@ -16067,7 +16207,7 @@ function createWeixinConsumerLock(options = {}) {
|
|
|
16067
16207
|
}
|
|
16068
16208
|
async function loadLockMetadata(path14) {
|
|
16069
16209
|
try {
|
|
16070
|
-
const raw = await
|
|
16210
|
+
const raw = await readFile7(path14, "utf8");
|
|
16071
16211
|
const parsed = JSON.parse(raw);
|
|
16072
16212
|
if (!parsed || typeof parsed.pid !== "number" || !parsed.mode || !parsed.configPath || !parsed.statePath) {
|
|
16073
16213
|
return null;
|
|
@@ -16110,6 +16250,7 @@ var init_consumer_lock = __esm(() => {
|
|
|
16110
16250
|
// src/channels/weixin-channel.ts
|
|
16111
16251
|
class WeixinChannel {
|
|
16112
16252
|
id = "weixin";
|
|
16253
|
+
nativeSessionListFormat = "cards";
|
|
16113
16254
|
agent = null;
|
|
16114
16255
|
quota = null;
|
|
16115
16256
|
logger = null;
|
|
@@ -16748,7 +16889,7 @@ var init_app_logger = __esm(() => {
|
|
|
16748
16889
|
});
|
|
16749
16890
|
|
|
16750
16891
|
// src/transport/acpx-session-index.ts
|
|
16751
|
-
import { readFile as
|
|
16892
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
16752
16893
|
import { homedir as homedir5 } from "node:os";
|
|
16753
16894
|
import { resolve as resolve2 } from "node:path";
|
|
16754
16895
|
async function resolveSessionAgentCommandFromIndex(session) {
|
|
@@ -16757,7 +16898,7 @@ async function resolveSessionAgentCommandFromIndex(session) {
|
|
|
16757
16898
|
return;
|
|
16758
16899
|
}
|
|
16759
16900
|
try {
|
|
16760
|
-
const raw = await
|
|
16901
|
+
const raw = await readFile11(resolve2(home, ".acpx", "sessions", "index.json"), "utf8");
|
|
16761
16902
|
const parsed = JSON.parse(raw);
|
|
16762
16903
|
const targetCwd = resolve2(session.cwd);
|
|
16763
16904
|
const match = parsed.entries?.find((entry) => entry.name === session.transportSession && entry.cwd === targetCwd && typeof entry.agentCommand === "string" && entry.agentCommand.trim().length > 0);
|
|
@@ -16917,6 +17058,7 @@ var init_command_list = __esm(() => {
|
|
|
16917
17058
|
"/pm",
|
|
16918
17059
|
"/session",
|
|
16919
17060
|
"/ss",
|
|
17061
|
+
"/ssn",
|
|
16920
17062
|
"/workspace",
|
|
16921
17063
|
"/ws",
|
|
16922
17064
|
"/use",
|
|
@@ -16999,6 +17141,51 @@ function parseCommand(input) {
|
|
|
16999
17141
|
if (command === "/session" && parts[1] === "rm" && parts[2] && parts.length === 3) {
|
|
17000
17142
|
return { kind: "session.rm", alias: parts[2] };
|
|
17001
17143
|
}
|
|
17144
|
+
if (command === "/ssn") {
|
|
17145
|
+
if (parts.length === 1) {
|
|
17146
|
+
return { kind: "session.native.list" };
|
|
17147
|
+
}
|
|
17148
|
+
const identifier = parts[1] ?? "";
|
|
17149
|
+
if (/^\d+$/.test(identifier)) {
|
|
17150
|
+
const selected = readNativeAttachCommand(parts, 1);
|
|
17151
|
+
if (!selected) {
|
|
17152
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17153
|
+
}
|
|
17154
|
+
return selected.alias ? { kind: "session.native.select", identifier, alias: selected.alias } : { kind: "session.native.select", identifier };
|
|
17155
|
+
}
|
|
17156
|
+
if (parts[1] === "attach") {
|
|
17157
|
+
if (!parts[2]) {
|
|
17158
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17159
|
+
}
|
|
17160
|
+
const attached = readNativeAttachCommand(parts, 2);
|
|
17161
|
+
if (attached) {
|
|
17162
|
+
return attached;
|
|
17163
|
+
}
|
|
17164
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17165
|
+
}
|
|
17166
|
+
const nativeList = readNativeListCommand(parts, 1);
|
|
17167
|
+
if (nativeList) {
|
|
17168
|
+
return nativeList;
|
|
17169
|
+
}
|
|
17170
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17171
|
+
}
|
|
17172
|
+
if (command === "/session" && parts[1] === "native") {
|
|
17173
|
+
const nativeList = readNativeListCommand(parts, 2);
|
|
17174
|
+
if (nativeList) {
|
|
17175
|
+
return nativeList;
|
|
17176
|
+
}
|
|
17177
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17178
|
+
}
|
|
17179
|
+
if (command === "/session" && parts[1] === "attach" && parts[2] === "native") {
|
|
17180
|
+
if (!parts[3]) {
|
|
17181
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17182
|
+
}
|
|
17183
|
+
const attached = readNativeAttachCommand(parts, 3);
|
|
17184
|
+
if (attached) {
|
|
17185
|
+
return attached;
|
|
17186
|
+
}
|
|
17187
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17188
|
+
}
|
|
17002
17189
|
if (command === "/group" && parts[1] === "new" && parts.length > 2) {
|
|
17003
17190
|
const title = parts.slice(2).join(" ");
|
|
17004
17191
|
if (title.trim().length > 0) {
|
|
@@ -17264,6 +17451,97 @@ function readSessionShortcutTarget(parts, startIndex) {
|
|
|
17264
17451
|
}
|
|
17265
17452
|
return null;
|
|
17266
17453
|
}
|
|
17454
|
+
function readNativeListCommand(parts, startIndex) {
|
|
17455
|
+
let agent = "";
|
|
17456
|
+
let cwd = "";
|
|
17457
|
+
let workspace = "";
|
|
17458
|
+
let all = false;
|
|
17459
|
+
let cursor = "";
|
|
17460
|
+
let invalid = false;
|
|
17461
|
+
if (startIndex < parts.length && !parts[startIndex]?.startsWith("-")) {
|
|
17462
|
+
agent = parts[startIndex] ?? "";
|
|
17463
|
+
startIndex += 1;
|
|
17464
|
+
}
|
|
17465
|
+
for (let index = startIndex;index < parts.length; index += 1) {
|
|
17466
|
+
const part = parts[index];
|
|
17467
|
+
if (part === "--all") {
|
|
17468
|
+
all = true;
|
|
17469
|
+
continue;
|
|
17470
|
+
}
|
|
17471
|
+
if (part === "--cursor") {
|
|
17472
|
+
const value = parts[index + 1] ?? "";
|
|
17473
|
+
if (index + 1 >= parts.length || value.startsWith("-")) {
|
|
17474
|
+
invalid = true;
|
|
17475
|
+
break;
|
|
17476
|
+
}
|
|
17477
|
+
cursor = value;
|
|
17478
|
+
index += 1;
|
|
17479
|
+
continue;
|
|
17480
|
+
}
|
|
17481
|
+
if (part === "--cwd" || part === "-d") {
|
|
17482
|
+
const value = parts[index + 1] ?? "";
|
|
17483
|
+
if (index + 1 >= parts.length || value.startsWith("-") || workspace) {
|
|
17484
|
+
invalid = true;
|
|
17485
|
+
break;
|
|
17486
|
+
}
|
|
17487
|
+
cwd = value;
|
|
17488
|
+
index += 1;
|
|
17489
|
+
continue;
|
|
17490
|
+
}
|
|
17491
|
+
if (part === "--ws" || part === "-ws") {
|
|
17492
|
+
const value = parts[index + 1] ?? "";
|
|
17493
|
+
if (index + 1 >= parts.length || value.startsWith("-") || cwd) {
|
|
17494
|
+
invalid = true;
|
|
17495
|
+
break;
|
|
17496
|
+
}
|
|
17497
|
+
workspace = value;
|
|
17498
|
+
index += 1;
|
|
17499
|
+
continue;
|
|
17500
|
+
}
|
|
17501
|
+
invalid = true;
|
|
17502
|
+
break;
|
|
17503
|
+
}
|
|
17504
|
+
if (invalid) {
|
|
17505
|
+
return null;
|
|
17506
|
+
}
|
|
17507
|
+
const result = {
|
|
17508
|
+
kind: "session.native.list"
|
|
17509
|
+
};
|
|
17510
|
+
if (agent.trim().length > 0)
|
|
17511
|
+
result.agent = agent;
|
|
17512
|
+
if (cwd.trim().length > 0)
|
|
17513
|
+
result.cwd = cwd;
|
|
17514
|
+
if (workspace.trim().length > 0)
|
|
17515
|
+
result.workspace = workspace;
|
|
17516
|
+
if (all)
|
|
17517
|
+
result.all = true;
|
|
17518
|
+
if (cursor.trim().length > 0)
|
|
17519
|
+
result.cursor = cursor;
|
|
17520
|
+
return Object.keys(result).length > 1 ? result : { kind: "session.native.list" };
|
|
17521
|
+
}
|
|
17522
|
+
function readNativeAttachCommand(parts, identifierIndex) {
|
|
17523
|
+
const identifier = parts[identifierIndex] ?? "";
|
|
17524
|
+
let alias = "";
|
|
17525
|
+
for (let index = identifierIndex + 1;index < parts.length; index += 1) {
|
|
17526
|
+
if (parts[index] === "-a" || parts[index] === "--alias") {
|
|
17527
|
+
const value = parts[index + 1] ?? "";
|
|
17528
|
+
if (index + 1 >= parts.length || value.startsWith("-")) {
|
|
17529
|
+
return null;
|
|
17530
|
+
}
|
|
17531
|
+
alias = value;
|
|
17532
|
+
index += 1;
|
|
17533
|
+
continue;
|
|
17534
|
+
}
|
|
17535
|
+
return null;
|
|
17536
|
+
}
|
|
17537
|
+
if (identifier.trim().length === 0 || identifier.startsWith("-")) {
|
|
17538
|
+
return null;
|
|
17539
|
+
}
|
|
17540
|
+
if (alias.trim().length > 0) {
|
|
17541
|
+
return { kind: "session.native.attach", identifier, alias };
|
|
17542
|
+
}
|
|
17543
|
+
return { kind: "session.native.attach", identifier };
|
|
17544
|
+
}
|
|
17267
17545
|
function normalizeCommand(command) {
|
|
17268
17546
|
if (command === "/ss")
|
|
17269
17547
|
return "/session";
|
|
@@ -17501,6 +17779,9 @@ var init_command_policy = __esm(() => {
|
|
|
17501
17779
|
"session.shortcut": "/session",
|
|
17502
17780
|
"session.shortcut.new": "/session",
|
|
17503
17781
|
"session.attach": "/session attach",
|
|
17782
|
+
"session.native.list": "/ssn",
|
|
17783
|
+
"session.native.select": "/ssn",
|
|
17784
|
+
"session.native.attach": "/ssn attach",
|
|
17504
17785
|
"later.create": "/later",
|
|
17505
17786
|
"later.list": "/later list",
|
|
17506
17787
|
"later.cancel": "/later cancel"
|
|
@@ -18118,7 +18399,7 @@ async function buildCoordinatorPrompt(input) {
|
|
|
18118
18399
|
|
|
18119
18400
|
`) : input.userText ?? "";
|
|
18120
18401
|
if (input.maxPromptLength && promptText.length > input.maxPromptLength) {
|
|
18121
|
-
promptText = promptText
|
|
18402
|
+
promptText = truncateText(promptText, input.maxPromptLength, "...");
|
|
18122
18403
|
}
|
|
18123
18404
|
return {
|
|
18124
18405
|
promptText,
|
|
@@ -18161,7 +18442,7 @@ async function handleSessions(context, chatKey) {
|
|
|
18161
18442
|
}
|
|
18162
18443
|
async function handleSessionNew(context, chatKey, alias, agent, workspace) {
|
|
18163
18444
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
18164
|
-
const internalAlias =
|
|
18445
|
+
const internalAlias = scopeDisplayAliasToInternal(channelId, alias);
|
|
18165
18446
|
const session = context.lifecycle.resolveSession(internalAlias, agent, workspace, `${workspace}:${internalAlias}`);
|
|
18166
18447
|
const releaseTransportReservation = await context.lifecycle.reserveTransportSession(session.transportSession);
|
|
18167
18448
|
try {
|
|
@@ -18192,7 +18473,7 @@ async function handleSessionShortcut(context, chatKey, agent, target, createNew)
|
|
|
18192
18473
|
}
|
|
18193
18474
|
async function handleSessionAttach(context, chatKey, alias, agent, workspace, transportSession) {
|
|
18194
18475
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
18195
|
-
const internalAlias =
|
|
18476
|
+
const internalAlias = scopeDisplayAliasToInternal(channelId, alias);
|
|
18196
18477
|
const attached = context.lifecycle.resolveSession(internalAlias, agent, workspace, transportSession);
|
|
18197
18478
|
const releaseTransportReservation = await context.lifecycle.reserveTransportSession(attached.transportSession);
|
|
18198
18479
|
try {
|
|
@@ -18559,7 +18840,7 @@ async function markCoordinatorResultsInjectionFailed(context, taskIds, groupIds,
|
|
|
18559
18840
|
});
|
|
18560
18841
|
}
|
|
18561
18842
|
}
|
|
18562
|
-
var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500, sessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
|
|
18843
|
+
var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500, sessionHelp, nativeSessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
|
|
18563
18844
|
var init_session_handler = __esm(() => {
|
|
18564
18845
|
init_build_coordinator_prompt();
|
|
18565
18846
|
init_channel_scope();
|
|
@@ -18567,7 +18848,7 @@ var init_session_handler = __esm(() => {
|
|
|
18567
18848
|
sessionHelp = {
|
|
18568
18849
|
topic: "session",
|
|
18569
18850
|
aliases: ["ss", "sessions"],
|
|
18570
|
-
summary: "
|
|
18851
|
+
summary: "创建、复用、切换和重置 weacpx 逻辑会话。",
|
|
18571
18852
|
commands: [
|
|
18572
18853
|
{ usage: "/sessions", description: "查看当前会话列表" },
|
|
18573
18854
|
{ usage: "/session 或 /ss", description: "查看会话列表" },
|
|
@@ -18575,12 +18856,48 @@ var init_session_handler = __esm(() => {
|
|
|
18575
18856
|
{ usage: "/ss new <agent> (-d <path> | --ws <name>)", description: "强制新建会话" },
|
|
18576
18857
|
{ usage: "/ss new <alias> -a <name> --ws <name>", description: "按指定配置新建会话" },
|
|
18577
18858
|
{ usage: "/ss attach <alias> -a <name> --ws <name> --name <transport-session>", description: "绑定已有会话" },
|
|
18859
|
+
{ usage: "/ssn 或 /help ssn", description: "接入本地 native 会话(Codex 等 Agent 原生会话)" },
|
|
18578
18860
|
{ usage: "/session tail [N]", description: "补拉当前会话的历史输出(默认 50 行)" },
|
|
18579
18861
|
{ usage: "/session rm <alias>", description: "删除逻辑会话" },
|
|
18580
18862
|
{ usage: "/use <alias>", description: "切换当前会话" },
|
|
18581
18863
|
{ usage: "/session reset 或 /clear", description: "重置当前会话上下文" }
|
|
18582
18864
|
],
|
|
18583
|
-
examples: [
|
|
18865
|
+
examples: [
|
|
18866
|
+
"/ss codex -d /absolute/path/to/repo",
|
|
18867
|
+
"/ssn",
|
|
18868
|
+
"/ssn 1",
|
|
18869
|
+
"/use backend-fix",
|
|
18870
|
+
"/session rm old-session",
|
|
18871
|
+
"/session reset"
|
|
18872
|
+
]
|
|
18873
|
+
};
|
|
18874
|
+
nativeSessionHelp = {
|
|
18875
|
+
topic: "native",
|
|
18876
|
+
aliases: ["ssn", "native-session"],
|
|
18877
|
+
summary: "接入 Codex 等 Agent 的本地原生会话。",
|
|
18878
|
+
commands: [
|
|
18879
|
+
{ usage: "/ssn", description: "按当前 weacpx 会话上下文查看本地 native 会话" },
|
|
18880
|
+
{ usage: "/ssn <agent> --ws <workspace>", description: "查询指定工作区的本地 native 会话;只有一个候选时自动接入" },
|
|
18881
|
+
{ usage: "/ssn <agent> -d <path>", description: "按本机绝对路径查询;只有一个候选时自动接入" },
|
|
18882
|
+
{ usage: "/ssn <agent> --ws <workspace> --all", description: "跨 cwd 查看该 agent 的 native 会话" },
|
|
18883
|
+
{ usage: "/ssn 1", description: "接入或切换到最近一次列表里的第 1 个候选" },
|
|
18884
|
+
{ usage: "/ssn 1 -a <alias>", description: "接入第 1 个候选并指定 weacpx 别名(推荐,无需完整 sessionId)" },
|
|
18885
|
+
{ usage: "/ssn attach <sessionId> -a <alias>", description: "按原生 sessionId 接入(适合已知完整 id),并指定 weacpx 别名" },
|
|
18886
|
+
{ usage: "/ss attach native <sessionId> -a <alias>", description: "/ssn attach 的长写法" }
|
|
18887
|
+
],
|
|
18888
|
+
examples: [
|
|
18889
|
+
"/ssn codex --ws backend",
|
|
18890
|
+
"/ssn codex -d /absolute/path/to/repo",
|
|
18891
|
+
"/ssn",
|
|
18892
|
+
"/ssn 1",
|
|
18893
|
+
"/ssn 1 -a fix-ci"
|
|
18894
|
+
],
|
|
18895
|
+
notes: [
|
|
18896
|
+
"/ss 管 weacpx 逻辑会话;/ssn 只负责查询和接入 Agent 原生会话。",
|
|
18897
|
+
"接入后继续发普通消息,会继续同一个 Agent 原生会话,不是复制一份新上下文。",
|
|
18898
|
+
"如果当前 acpx 或 Agent 不支持 native 会话,请继续使用 /ss。",
|
|
18899
|
+
"完整说明见 docs/native-sessions.md。"
|
|
18900
|
+
]
|
|
18584
18901
|
};
|
|
18585
18902
|
modeHelp = {
|
|
18586
18903
|
topic: "mode",
|
|
@@ -19543,6 +19860,7 @@ var init_help_registry = __esm(() => {
|
|
|
19543
19860
|
init_later_handler();
|
|
19544
19861
|
HELP_TOPICS = [
|
|
19545
19862
|
sessionHelp,
|
|
19863
|
+
nativeSessionHelp,
|
|
19546
19864
|
workspaceHelp,
|
|
19547
19865
|
agentHelp,
|
|
19548
19866
|
permissionHelp,
|
|
@@ -19574,11 +19892,33 @@ function handleHelp(topic) {
|
|
|
19574
19892
|
}
|
|
19575
19893
|
return { text: renderHelpTopic(entry) };
|
|
19576
19894
|
}
|
|
19895
|
+
function handleInvalidCommand(recognizedCommand) {
|
|
19896
|
+
const topicName = recognizedCommand.replace(/^\//, "");
|
|
19897
|
+
const entry = getHelpTopic(topicName);
|
|
19898
|
+
if (entry) {
|
|
19899
|
+
return { text: `命令格式不正确,请参考下面的用法:
|
|
19900
|
+
|
|
19901
|
+
${renderHelpTopic(entry)}` };
|
|
19902
|
+
}
|
|
19903
|
+
return {
|
|
19904
|
+
text: [
|
|
19905
|
+
"无法识别的命令格式。",
|
|
19906
|
+
"",
|
|
19907
|
+
"正确的会话创建格式:",
|
|
19908
|
+
"/session new <别名> --agent <Agent名> --ws <工作区名>",
|
|
19909
|
+
"",
|
|
19910
|
+
"例如:",
|
|
19911
|
+
"/session new demo --agent claude --ws weacpx"
|
|
19912
|
+
].join(`
|
|
19913
|
+
`)
|
|
19914
|
+
};
|
|
19915
|
+
}
|
|
19577
19916
|
function renderHelpIndex() {
|
|
19578
19917
|
const topics = listHelpTopics();
|
|
19579
19918
|
return [
|
|
19580
19919
|
"常用入口:",
|
|
19581
19920
|
"- /ss <agent> (-d <path> | --ws <name>) - 快速新建或切到会话",
|
|
19921
|
+
"- /ssn <agent> (-d <path> | --ws <name>) - 接入本地 Agent 原生会话",
|
|
19582
19922
|
"- /use <alias> - 切换当前会话",
|
|
19583
19923
|
"- /status - 查看当前会话状态",
|
|
19584
19924
|
"",
|
|
@@ -19587,7 +19927,7 @@ function renderHelpIndex() {
|
|
|
19587
19927
|
"",
|
|
19588
19928
|
"查看专题说明:",
|
|
19589
19929
|
"- /help <topic>",
|
|
19590
|
-
"- 例如:/help ss、/help ws、/help pm"
|
|
19930
|
+
"- 例如:/help ss、/help ssn、/help ws、/help pm"
|
|
19591
19931
|
].join(`
|
|
19592
19932
|
`);
|
|
19593
19933
|
}
|
|
@@ -19669,7 +20009,7 @@ async function handleSessionShortcutCommand(context, ops, chatKey, agent, target
|
|
|
19669
20009
|
});
|
|
19670
20010
|
const baseAlias = `${workspace.name}:${agent}`;
|
|
19671
20011
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
19672
|
-
const scopedBase = channelId
|
|
20012
|
+
const scopedBase = scopeDisplayAliasToInternal(channelId, baseAlias);
|
|
19673
20013
|
const alias = createNew ? await allocateUniqueSessionAlias(context, scopedBase, chatKey) : scopedBase;
|
|
19674
20014
|
const display = toDisplaySessionAlias(alias);
|
|
19675
20015
|
if (!createNew && await hasLogicalSession(context, alias, chatKey)) {
|
|
@@ -19798,6 +20138,404 @@ var init_session_shortcut_handler = __esm(() => {
|
|
|
19798
20138
|
init_channel_scope();
|
|
19799
20139
|
});
|
|
19800
20140
|
|
|
20141
|
+
// src/commands/handlers/native-session-handler.ts
|
|
20142
|
+
async function handleNativeSessionList(context, chatKey, input) {
|
|
20143
|
+
const target = await resolveNativeTarget(context, chatKey, input);
|
|
20144
|
+
if (isRouterResponse(target)) {
|
|
20145
|
+
return target;
|
|
20146
|
+
}
|
|
20147
|
+
const listAgentSessions = context.transport.listAgentSessions?.bind(context.transport);
|
|
20148
|
+
if (!listAgentSessions) {
|
|
20149
|
+
return { text: `当前 transport 不支持列出本地会话,请继续使用 /ss。
|
|
20150
|
+
说明:/help ssn` };
|
|
20151
|
+
}
|
|
20152
|
+
const query = {
|
|
20153
|
+
agent: target.agent,
|
|
20154
|
+
agentCommand: target.agentCommand,
|
|
20155
|
+
cwd: target.cwd,
|
|
20156
|
+
...input.cursor ? { cursor: input.cursor } : {},
|
|
20157
|
+
...input.all ? {} : { filterCwd: target.cwd }
|
|
20158
|
+
};
|
|
20159
|
+
let result;
|
|
20160
|
+
try {
|
|
20161
|
+
result = await listAgentSessions(query);
|
|
20162
|
+
} catch (error2) {
|
|
20163
|
+
return { text: renderNativeListError(target, error2) };
|
|
20164
|
+
}
|
|
20165
|
+
if (!result) {
|
|
20166
|
+
return { text: `当前 transport 不支持列出本地会话,请继续使用 /ss。
|
|
20167
|
+
说明:/help ssn` };
|
|
20168
|
+
}
|
|
20169
|
+
await context.sessions.cacheNativeSessionList(chatKey, {
|
|
20170
|
+
agent: target.agent,
|
|
20171
|
+
workspace: target.workspace,
|
|
20172
|
+
cwd: target.cwd,
|
|
20173
|
+
sessions: result.sessions,
|
|
20174
|
+
...result.nextCursor !== undefined ? { nextCursor: result.nextCursor } : {}
|
|
20175
|
+
});
|
|
20176
|
+
if (result.sessions.length === 0) {
|
|
20177
|
+
return {
|
|
20178
|
+
text: [
|
|
20179
|
+
`没有找到本地 ${target.agentDisplayName} 会话(${target.workspaceLabel})。`,
|
|
20180
|
+
`你可以稍后再试,或先通过 /ss 保持当前逻辑会话。`
|
|
20181
|
+
].join(`
|
|
20182
|
+
`)
|
|
20183
|
+
};
|
|
20184
|
+
}
|
|
20185
|
+
const explicitAttachTarget = Boolean(input.workspace || input.cwd);
|
|
20186
|
+
if (explicitAttachTarget && !input.all && !input.cursor && result.sessions.length === 1) {
|
|
20187
|
+
return await attachNativeSession(context, chatKey, target, result.sessions[0], undefined);
|
|
20188
|
+
}
|
|
20189
|
+
const attachedEntries = await buildAttachedEntries(context, chatKey, target.agent, result.sessions);
|
|
20190
|
+
const nativeSessionListOptions = { format: context.resolveNativeSessionListFormat?.(chatKey) ?? "table" };
|
|
20191
|
+
return {
|
|
20192
|
+
text: renderNativeSessionList(target, result, attachedEntries, Boolean(input.all), nativeSessionListOptions)
|
|
20193
|
+
};
|
|
20194
|
+
}
|
|
20195
|
+
async function handleNativeSessionSelect(context, chatKey, identifier, alias) {
|
|
20196
|
+
const trimmed = identifier.trim();
|
|
20197
|
+
if (!trimmed) {
|
|
20198
|
+
return { text: `请选择要切换的 native 会话编号或 sessionId。
|
|
20199
|
+
说明:/help ssn` };
|
|
20200
|
+
}
|
|
20201
|
+
if (/^[0-9]+$/.test(trimmed)) {
|
|
20202
|
+
const cached2 = await context.sessions.getNativeSessionList(chatKey, NATIVE_SESSION_CACHE_TTL_MS);
|
|
20203
|
+
if (!cached2 || cached2.sessions.length === 0) {
|
|
20204
|
+
return { text: `当前没有可用的 native 会话列表,请先执行 /ssn 再选择。
|
|
20205
|
+
说明:/help ssn` };
|
|
20206
|
+
}
|
|
20207
|
+
const index = Number(trimmed) - 1;
|
|
20208
|
+
const session = cached2.sessions[index];
|
|
20209
|
+
if (!session) {
|
|
20210
|
+
return { text: "编号超出范围,请先执行 /ssn 重新获取列表。" };
|
|
20211
|
+
}
|
|
20212
|
+
const target2 = await resolveTargetFromCachedSession(context, chatKey, cached2, session);
|
|
20213
|
+
if (isRouterResponse(target2)) {
|
|
20214
|
+
return target2;
|
|
20215
|
+
}
|
|
20216
|
+
return await attachNativeSession(context, chatKey, target2, session, alias);
|
|
20217
|
+
}
|
|
20218
|
+
const target = await resolveNativeTarget(context, chatKey, {});
|
|
20219
|
+
if (isRouterResponse(target)) {
|
|
20220
|
+
return target;
|
|
20221
|
+
}
|
|
20222
|
+
return await attachNativeSession(context, chatKey, target, { sessionId: trimmed }, alias);
|
|
20223
|
+
}
|
|
20224
|
+
async function attachNativeSession(context, chatKey, target, session, alias) {
|
|
20225
|
+
if (!context.transport.resumeAgentSession) {
|
|
20226
|
+
return { text: "当前 transport 不支持接入本地会话,请继续使用 /ss。" };
|
|
20227
|
+
}
|
|
20228
|
+
const nativeTarget = target;
|
|
20229
|
+
const existing = await context.sessions.findAttachedNativeSession(chatKey, nativeTarget.agent, session.sessionId);
|
|
20230
|
+
if (existing) {
|
|
20231
|
+
await context.sessions.useSession(chatKey, existing.alias);
|
|
20232
|
+
const displayAlias2 = toDisplaySessionAlias(existing.alias);
|
|
20233
|
+
return {
|
|
20234
|
+
text: `已切换到已接入的本地会话:${nativeTarget.agentDisplayName} · ${displayAlias2}`
|
|
20235
|
+
};
|
|
20236
|
+
}
|
|
20237
|
+
const requestedAlias = alias?.trim() || buildDefaultNativeAlias(nativeTarget.agent, session.sessionId);
|
|
20238
|
+
const displayAlias = await allocateUniqueNativeAlias(context, chatKey, requestedAlias);
|
|
20239
|
+
const internalAlias = scopeDisplayAliasToInternal(getChannelIdFromChatKey(chatKey), displayAlias);
|
|
20240
|
+
const transportSession = context.sessions.buildDefaultTransportSessionForChat(chatKey, displayAlias);
|
|
20241
|
+
const resolvedSession = context.lifecycle.resolveSession(internalAlias, nativeTarget.agent, nativeTarget.workspace, transportSession);
|
|
20242
|
+
const releaseReservation = await context.lifecycle.reserveTransportSession(resolvedSession.transportSession);
|
|
20243
|
+
try {
|
|
20244
|
+
try {
|
|
20245
|
+
await context.transport.resumeAgentSession(resolvedSession, session.sessionId);
|
|
20246
|
+
} catch (error2) {
|
|
20247
|
+
return { text: renderNativeResumeError(target, error2) };
|
|
20248
|
+
}
|
|
20249
|
+
const verified = await context.lifecycle.checkTransportSession(resolvedSession);
|
|
20250
|
+
if (!verified) {
|
|
20251
|
+
return { text: `本地 ${target.agentDisplayName} 会话接入失败:未检测到已恢复的后端会话。` };
|
|
20252
|
+
}
|
|
20253
|
+
await context.sessions.attachNativeSession({
|
|
20254
|
+
alias: internalAlias,
|
|
20255
|
+
agent: nativeTarget.agent,
|
|
20256
|
+
workspace: nativeTarget.workspace,
|
|
20257
|
+
transportSession,
|
|
20258
|
+
...target.agentCommand ? { transportAgentCommand: target.agentCommand } : {},
|
|
20259
|
+
agentSessionId: session.sessionId,
|
|
20260
|
+
title: session.title,
|
|
20261
|
+
updatedAt: session.updatedAt
|
|
20262
|
+
});
|
|
20263
|
+
await context.sessions.useSession(chatKey, internalAlias);
|
|
20264
|
+
await refreshAgentCommandBestEffort(context, internalAlias);
|
|
20265
|
+
return {
|
|
20266
|
+
text: `已接入本地 ${target.agentDisplayName} 会话并切换:${toDisplaySessionAlias(internalAlias)}`
|
|
20267
|
+
};
|
|
20268
|
+
} finally {
|
|
20269
|
+
await releaseReservation();
|
|
20270
|
+
}
|
|
20271
|
+
}
|
|
20272
|
+
async function resolveNativeTarget(context, chatKey, input) {
|
|
20273
|
+
const currentSession = await context.sessions.getCurrentSession(chatKey);
|
|
20274
|
+
const agent = input.agent?.trim() || currentSession?.agent || "";
|
|
20275
|
+
if (!agent) {
|
|
20276
|
+
return {
|
|
20277
|
+
text: `请先选择上下文,例如:
|
|
20278
|
+
/ssn codex --ws project
|
|
20279
|
+
/ssn codex -d /Users/me/project
|
|
20280
|
+
说明:/help ssn`
|
|
20281
|
+
};
|
|
20282
|
+
}
|
|
20283
|
+
const agentConfig = context.config?.agents[agent];
|
|
20284
|
+
if (!agentConfig) {
|
|
20285
|
+
return { text: `Agent「${agent}」未注册。` };
|
|
20286
|
+
}
|
|
20287
|
+
const workspaceResolution = await resolveNativeWorkspace(context, input, currentSession);
|
|
20288
|
+
if (isRouterResponse(workspaceResolution)) {
|
|
20289
|
+
return workspaceResolution;
|
|
20290
|
+
}
|
|
20291
|
+
return {
|
|
20292
|
+
agent,
|
|
20293
|
+
agentDisplayName: displayAgentName(agent),
|
|
20294
|
+
agentCommand: resolveAgentCommand(agentConfig.driver, agentConfig.command),
|
|
20295
|
+
workspace: workspaceResolution.workspace,
|
|
20296
|
+
workspaceLabel: workspaceResolution.workspaceLabel,
|
|
20297
|
+
cwd: workspaceResolution.cwd,
|
|
20298
|
+
source: workspaceResolution.source
|
|
20299
|
+
};
|
|
20300
|
+
}
|
|
20301
|
+
async function resolveTargetFromCachedSession(context, chatKey, cached2, session) {
|
|
20302
|
+
if (session.cwd && !sameWorkspacePath(session.cwd, cached2.cwd)) {
|
|
20303
|
+
return await resolveNativeTarget(context, chatKey, {
|
|
20304
|
+
agent: cached2.agent,
|
|
20305
|
+
cwd: session.cwd
|
|
20306
|
+
});
|
|
20307
|
+
}
|
|
20308
|
+
return await resolveNativeTarget(context, chatKey, {
|
|
20309
|
+
agent: cached2.agent,
|
|
20310
|
+
...cached2.workspace ? { workspace: cached2.workspace } : { cwd: cached2.cwd }
|
|
20311
|
+
});
|
|
20312
|
+
}
|
|
20313
|
+
async function resolveNativeWorkspace(context, input, currentSession) {
|
|
20314
|
+
if (input.workspace) {
|
|
20315
|
+
const workspaceConfig = context.config?.workspaces[input.workspace];
|
|
20316
|
+
if (!workspaceConfig) {
|
|
20317
|
+
return { text: `工作区「${input.workspace}」未注册。` };
|
|
20318
|
+
}
|
|
20319
|
+
return {
|
|
20320
|
+
workspace: input.workspace,
|
|
20321
|
+
workspaceLabel: input.workspace,
|
|
20322
|
+
cwd: workspaceConfig.cwd,
|
|
20323
|
+
source: "workspace"
|
|
20324
|
+
};
|
|
20325
|
+
}
|
|
20326
|
+
if (input.cwd) {
|
|
20327
|
+
const cwd = normalizeWorkspacePath(input.cwd);
|
|
20328
|
+
const existing = Object.entries(context.config?.workspaces ?? {}).find(([, workspace]) => sameWorkspacePath(workspace.cwd, cwd));
|
|
20329
|
+
if (existing) {
|
|
20330
|
+
return {
|
|
20331
|
+
workspace: existing[0],
|
|
20332
|
+
workspaceLabel: existing[0],
|
|
20333
|
+
cwd: existing[1].cwd,
|
|
20334
|
+
source: "cwd"
|
|
20335
|
+
};
|
|
20336
|
+
}
|
|
20337
|
+
if (!await pathExists(cwd)) {
|
|
20338
|
+
return { text: `工作区路径不存在:${input.cwd}` };
|
|
20339
|
+
}
|
|
20340
|
+
if (!context.configStore || !context.config) {
|
|
20341
|
+
return { text: "当前没有加载可写入的配置,无法根据路径创建工作区。" };
|
|
20342
|
+
}
|
|
20343
|
+
const workspaceName = allocateWorkspaceName(sanitizeWorkspaceName(basenameForWorkspacePath(cwd)), context.config.workspaces);
|
|
20344
|
+
const updated = await context.configStore.upsertWorkspace(workspaceName, cwd);
|
|
20345
|
+
context.replaceConfig(updated);
|
|
20346
|
+
return {
|
|
20347
|
+
workspace: workspaceName,
|
|
20348
|
+
workspaceLabel: workspaceName,
|
|
20349
|
+
cwd,
|
|
20350
|
+
source: "cwd"
|
|
20351
|
+
};
|
|
20352
|
+
}
|
|
20353
|
+
if (currentSession) {
|
|
20354
|
+
return {
|
|
20355
|
+
workspace: currentSession.workspace,
|
|
20356
|
+
workspaceLabel: currentSession.workspace,
|
|
20357
|
+
cwd: currentSession.cwd,
|
|
20358
|
+
source: "workspace"
|
|
20359
|
+
};
|
|
20360
|
+
}
|
|
20361
|
+
return {
|
|
20362
|
+
text: `请先选择上下文,例如:
|
|
20363
|
+
/ssn codex --ws project
|
|
20364
|
+
/ssn codex -d /Users/me/project
|
|
20365
|
+
说明:/help ssn`
|
|
20366
|
+
};
|
|
20367
|
+
}
|
|
20368
|
+
async function buildAttachedEntries(context, chatKey, agent, sessions) {
|
|
20369
|
+
const currentSession = await context.sessions.getCurrentSession(chatKey);
|
|
20370
|
+
return await Promise.all(sessions.map(async (session) => {
|
|
20371
|
+
const attached = await context.sessions.findAttachedNativeSession(chatKey, agent, session.sessionId);
|
|
20372
|
+
if (!attached) {
|
|
20373
|
+
return { session };
|
|
20374
|
+
}
|
|
20375
|
+
return {
|
|
20376
|
+
session,
|
|
20377
|
+
attached: {
|
|
20378
|
+
alias: attached.alias,
|
|
20379
|
+
displayAlias: toDisplaySessionAlias(attached.alias),
|
|
20380
|
+
isCurrent: currentSession?.alias === attached.alias
|
|
20381
|
+
}
|
|
20382
|
+
};
|
|
20383
|
+
}));
|
|
20384
|
+
}
|
|
20385
|
+
function renderNativeSessionList(target, result, entries, includeAll, options = {}) {
|
|
20386
|
+
if (options.format === "cards") {
|
|
20387
|
+
return renderNativeSessionCardList(target, result, entries, includeAll);
|
|
20388
|
+
}
|
|
20389
|
+
return renderNativeSessionTableList(target, result, entries, includeAll);
|
|
20390
|
+
}
|
|
20391
|
+
function renderNativeSessionTableList(target, result, entries, includeAll) {
|
|
20392
|
+
const lines = [`本地 ${target.agentDisplayName} 会话(${target.workspaceLabel}):`];
|
|
20393
|
+
lines.push("| # | 标题 | 更新时间 | ID |");
|
|
20394
|
+
lines.push("|---|---|---|---|");
|
|
20395
|
+
entries.forEach((entry, index) => {
|
|
20396
|
+
const title = escapeMarkdownTableCell(renderNativeSessionTitle(entry.session.title, entry.session.sessionId));
|
|
20397
|
+
const updatedAt = entry.session.updatedAt ? formatNativeSessionTime(entry.session.updatedAt) : "-";
|
|
20398
|
+
const idParts = [entry.session.sessionId];
|
|
20399
|
+
if (entry.attached) {
|
|
20400
|
+
idParts.push(`已接入:${entry.attached.displayAlias}${entry.attached.isCurrent ? " [当前]" : ""}`);
|
|
20401
|
+
}
|
|
20402
|
+
lines.push(`| ${index + 1} | ${title} | ${escapeMarkdownTableCell(updatedAt)} | ${escapeMarkdownTableCell(idParts.join(" · "))} |`);
|
|
20403
|
+
});
|
|
20404
|
+
lines.push("");
|
|
20405
|
+
lines.push("操作:");
|
|
20406
|
+
lines.push("接入:/ssn 1");
|
|
20407
|
+
lines.push("指定别名:/ssn 1 -a fix-ci");
|
|
20408
|
+
lines.push("说明:/help ssn");
|
|
20409
|
+
if (result.nextCursor) {
|
|
20410
|
+
lines.push(`更多:${renderNextPageCommand(target, result.nextCursor, includeAll)}`);
|
|
20411
|
+
}
|
|
20412
|
+
return lines.join(`
|
|
20413
|
+
`);
|
|
20414
|
+
}
|
|
20415
|
+
function renderNativeSessionCardList(target, result, entries, includeAll) {
|
|
20416
|
+
const lines = [
|
|
20417
|
+
`本地 ${target.agentDisplayName} 会话(${target.workspaceLabel}):`,
|
|
20418
|
+
"回复编号接入,ID 尾号用于区分。"
|
|
20419
|
+
];
|
|
20420
|
+
entries.forEach((entry, index) => {
|
|
20421
|
+
const title = renderNativeSessionTitle(entry.session.title, entry.session.sessionId);
|
|
20422
|
+
const updatedAt = entry.session.updatedAt ? formatNativeSessionTime(entry.session.updatedAt) : "-";
|
|
20423
|
+
lines.push("");
|
|
20424
|
+
lines.push(`【${index + 1}】 ${title}`);
|
|
20425
|
+
lines.push(`时间:${updatedAt}`);
|
|
20426
|
+
lines.push(`ID:${formatSessionIdTail(entry.session.sessionId)}`);
|
|
20427
|
+
if (entry.attached) {
|
|
20428
|
+
lines.push(`已接入:${entry.attached.displayAlias}${entry.attached.isCurrent ? " [当前]" : ""}`);
|
|
20429
|
+
}
|
|
20430
|
+
});
|
|
20431
|
+
lines.push("");
|
|
20432
|
+
lines.push("操作:");
|
|
20433
|
+
lines.push("接入:/ssn 1");
|
|
20434
|
+
lines.push("指定别名:/ssn 1 -a fix-ci");
|
|
20435
|
+
lines.push("说明:/help ssn");
|
|
20436
|
+
if (result.nextCursor) {
|
|
20437
|
+
lines.push(`更多:${renderNextPageCommand(target, result.nextCursor, includeAll)}`);
|
|
20438
|
+
}
|
|
20439
|
+
return lines.join(`
|
|
20440
|
+
`);
|
|
20441
|
+
}
|
|
20442
|
+
function renderNativeSessionTitle(title, fallback) {
|
|
20443
|
+
const normalized = (title?.trim() || fallback).replace(/\s+/g, " ");
|
|
20444
|
+
const maxLength = 60;
|
|
20445
|
+
return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}…` : normalized;
|
|
20446
|
+
}
|
|
20447
|
+
function buildDefaultNativeAlias(agent, sessionId) {
|
|
20448
|
+
return `${agent}-${sessionIdTail(sessionId)}`;
|
|
20449
|
+
}
|
|
20450
|
+
function formatSessionIdTail(sessionId) {
|
|
20451
|
+
const tail = sessionIdTail(sessionId);
|
|
20452
|
+
return tail.length < sessionId.trim().length ? `…${tail}` : tail;
|
|
20453
|
+
}
|
|
20454
|
+
function sessionIdTail(sessionId) {
|
|
20455
|
+
const trimmed = sessionId.trim();
|
|
20456
|
+
if (trimmed.length <= 8) {
|
|
20457
|
+
return trimmed;
|
|
20458
|
+
}
|
|
20459
|
+
return trimmed.slice(-8);
|
|
20460
|
+
}
|
|
20461
|
+
function formatNativeSessionTime(value) {
|
|
20462
|
+
const date4 = new Date(value);
|
|
20463
|
+
if (Number.isNaN(date4.getTime())) {
|
|
20464
|
+
return value;
|
|
20465
|
+
}
|
|
20466
|
+
const pad = (input) => String(input).padStart(2, "0");
|
|
20467
|
+
return `${date4.getFullYear()}-${pad(date4.getMonth() + 1)}-${pad(date4.getDate())} ${pad(date4.getHours())}:${pad(date4.getMinutes())}`;
|
|
20468
|
+
}
|
|
20469
|
+
function escapeMarkdownTableCell(value) {
|
|
20470
|
+
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
20471
|
+
}
|
|
20472
|
+
function renderNextPageCommand(target, nextCursor, includeAll) {
|
|
20473
|
+
const scope = target.source === "workspace" && target.workspace ? `--ws ${target.workspace}` : `-d ${target.cwd}`;
|
|
20474
|
+
const allFlag = includeAll ? " --all" : "";
|
|
20475
|
+
return `/ssn ${target.agent} ${scope}${allFlag} --cursor ${nextCursor}`;
|
|
20476
|
+
}
|
|
20477
|
+
async function allocateUniqueNativeAlias(context, chatKey, baseDisplayAlias) {
|
|
20478
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
20479
|
+
const visible = await context.sessions.listSessions(chatKey);
|
|
20480
|
+
const existing = new Set(visible.map((session) => session.internalAlias));
|
|
20481
|
+
const base = baseDisplayAlias.trim() || "native-session";
|
|
20482
|
+
const transportFor = (candidate) => context.sessions.buildDefaultTransportSessionForChat(chatKey, candidate);
|
|
20483
|
+
const isFree = (candidate) => !existing.has(scopeDisplayAliasToInternal(channelId, candidate)) && context.sessions.countAliasesSharingTransport(transportFor(candidate)) === 0;
|
|
20484
|
+
if (isFree(base)) {
|
|
20485
|
+
return base;
|
|
20486
|
+
}
|
|
20487
|
+
let suffix = 2;
|
|
20488
|
+
while (!isFree(`${base}-${suffix}`)) {
|
|
20489
|
+
suffix += 1;
|
|
20490
|
+
}
|
|
20491
|
+
return `${base}-${suffix}`;
|
|
20492
|
+
}
|
|
20493
|
+
async function refreshAgentCommandBestEffort(context, alias) {
|
|
20494
|
+
try {
|
|
20495
|
+
await context.lifecycle.refreshSessionTransportAgentCommand(alias);
|
|
20496
|
+
} catch (error2) {
|
|
20497
|
+
await context.logger.error("session.native.agent_command_refresh_failed", "failed to refresh native session agent command", {
|
|
20498
|
+
alias,
|
|
20499
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
20500
|
+
});
|
|
20501
|
+
}
|
|
20502
|
+
}
|
|
20503
|
+
function renderNativeListError(target, error2) {
|
|
20504
|
+
return [
|
|
20505
|
+
`本地 ${target.agentDisplayName} 会话查询失败:${formatErrorMessage(error2)}`,
|
|
20506
|
+
"请确认 acpx/Agent 支持 native 会话查询,或继续使用 /ss。",
|
|
20507
|
+
"说明:/help ssn"
|
|
20508
|
+
].join(`
|
|
20509
|
+
`);
|
|
20510
|
+
}
|
|
20511
|
+
function renderNativeResumeError(target, error2) {
|
|
20512
|
+
return [
|
|
20513
|
+
`本地 ${target.agentDisplayName} 会话接入失败:${formatErrorMessage(error2)}`,
|
|
20514
|
+
"请确认 acpx/Agent 支持 native 会话恢复,或继续使用 /ss。",
|
|
20515
|
+
"说明:/help ssn"
|
|
20516
|
+
].join(`
|
|
20517
|
+
`);
|
|
20518
|
+
}
|
|
20519
|
+
function formatErrorMessage(error2) {
|
|
20520
|
+
return error2 instanceof Error ? error2.message : String(error2);
|
|
20521
|
+
}
|
|
20522
|
+
function isRouterResponse(value) {
|
|
20523
|
+
return typeof value.text === "string";
|
|
20524
|
+
}
|
|
20525
|
+
function displayAgentName(agent) {
|
|
20526
|
+
if (!agent) {
|
|
20527
|
+
return agent;
|
|
20528
|
+
}
|
|
20529
|
+
return agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
20530
|
+
}
|
|
20531
|
+
var NATIVE_SESSION_CACHE_TTL_MS;
|
|
20532
|
+
var init_native_session_handler = __esm(() => {
|
|
20533
|
+
init_channel_scope();
|
|
20534
|
+
init_workspace_name();
|
|
20535
|
+
init_workspace_path();
|
|
20536
|
+
NATIVE_SESSION_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
20537
|
+
});
|
|
20538
|
+
|
|
19801
20539
|
// src/commands/handlers/session-recovery-handler.ts
|
|
19802
20540
|
function renderTransportError(session, error2) {
|
|
19803
20541
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -20265,6 +21003,7 @@ class CommandRouter {
|
|
|
20265
21003
|
quota;
|
|
20266
21004
|
scheduled;
|
|
20267
21005
|
scheduledDelivery;
|
|
21006
|
+
resolveNativeSessionListFormat;
|
|
20268
21007
|
logger;
|
|
20269
21008
|
autoInstall = autoInstallOptionalDep;
|
|
20270
21009
|
discoverPaths = discoverParentPackagePaths;
|
|
@@ -20274,7 +21013,7 @@ class CommandRouter {
|
|
|
20274
21013
|
__setDiscoverPathsForTest(fn) {
|
|
20275
21014
|
this.discoverPaths = fn;
|
|
20276
21015
|
}
|
|
20277
|
-
constructor(sessions, transport, config2, configStore, logger2, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration, quota, scheduled, scheduledDelivery) {
|
|
21016
|
+
constructor(sessions, transport, config2, configStore, logger2, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration, quota, scheduled, scheduledDelivery, resolveNativeSessionListFormat) {
|
|
20278
21017
|
this.sessions = sessions;
|
|
20279
21018
|
this.transport = transport;
|
|
20280
21019
|
this.config = config2;
|
|
@@ -20284,6 +21023,7 @@ class CommandRouter {
|
|
|
20284
21023
|
this.quota = quota;
|
|
20285
21024
|
this.scheduled = scheduled;
|
|
20286
21025
|
this.scheduledDelivery = scheduledDelivery;
|
|
21026
|
+
this.resolveNativeSessionListFormat = resolveNativeSessionListFormat;
|
|
20287
21027
|
this.logger = logger2 ?? createNoopAppLogger();
|
|
20288
21028
|
}
|
|
20289
21029
|
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan) {
|
|
@@ -20310,18 +21050,7 @@ class CommandRouter {
|
|
|
20310
21050
|
return await this.executeCommand(chatKey, command.kind, startedAt, async () => {
|
|
20311
21051
|
switch (command.kind) {
|
|
20312
21052
|
case "invalid":
|
|
20313
|
-
return
|
|
20314
|
-
text: [
|
|
20315
|
-
"无法识别的命令格式。",
|
|
20316
|
-
"",
|
|
20317
|
-
"正确的会话创建格式:",
|
|
20318
|
-
"/session new <别名> --agent <Agent名> --ws <工作区名>",
|
|
20319
|
-
"",
|
|
20320
|
-
"例如:",
|
|
20321
|
-
"/session new demo --agent claude --ws weacpx"
|
|
20322
|
-
].join(`
|
|
20323
|
-
`)
|
|
20324
|
-
};
|
|
21053
|
+
return handleInvalidCommand(command.recognizedCommand);
|
|
20325
21054
|
case "help":
|
|
20326
21055
|
return handleHelp(command.topic);
|
|
20327
21056
|
case "agents":
|
|
@@ -20358,6 +21087,12 @@ class CommandRouter {
|
|
|
20358
21087
|
return await handleSessionShortcut(this.createSessionHandlerContext(reply, perfSpan), chatKey, command.agent, command, true);
|
|
20359
21088
|
case "session.attach":
|
|
20360
21089
|
return await handleSessionAttach(this.createSessionHandlerContext(reply, perfSpan), chatKey, command.alias, command.agent, command.workspace, command.transportSession);
|
|
21090
|
+
case "session.native.list":
|
|
21091
|
+
return await handleNativeSessionList(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command);
|
|
21092
|
+
case "session.native.select":
|
|
21093
|
+
return await handleNativeSessionSelect(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.identifier, command.alias);
|
|
21094
|
+
case "session.native.attach":
|
|
21095
|
+
return await handleNativeSessionSelect(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.identifier, command.alias);
|
|
20361
21096
|
case "session.use":
|
|
20362
21097
|
return await handleSessionUse(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias);
|
|
20363
21098
|
case "mode.show":
|
|
@@ -20459,7 +21194,8 @@ class CommandRouter {
|
|
|
20459
21194
|
configStore: this.configStore,
|
|
20460
21195
|
logger: this.logger,
|
|
20461
21196
|
replaceConfig: (updated) => this.replaceConfig(updated),
|
|
20462
|
-
...this.quota ? { quota: this.quota } : {}
|
|
21197
|
+
...this.quota ? { quota: this.quota } : {},
|
|
21198
|
+
...this.resolveNativeSessionListFormat ? { resolveNativeSessionListFormat: this.resolveNativeSessionListFormat } : {}
|
|
20463
21199
|
};
|
|
20464
21200
|
}
|
|
20465
21201
|
createSessionHandlerContext(reply, perfSpan) {
|
|
@@ -20821,6 +21557,7 @@ var init_command_router = __esm(() => {
|
|
|
20821
21557
|
init_agent_handler();
|
|
20822
21558
|
init_workspace_handler();
|
|
20823
21559
|
init_session_shortcut_handler();
|
|
21560
|
+
init_native_session_handler();
|
|
20824
21561
|
init_later_handler();
|
|
20825
21562
|
init_session_recovery_handler();
|
|
20826
21563
|
init_auto_install_optional_dep();
|
|
@@ -23965,7 +24702,11 @@ class OrchestrationService {
|
|
|
23965
24702
|
}
|
|
23966
24703
|
workspaceLabelFromCwd(cwd) {
|
|
23967
24704
|
const base = basename2(cwd).trim() || "cwd";
|
|
23968
|
-
return base
|
|
24705
|
+
return sanitizeString(base, {
|
|
24706
|
+
allow: /[a-zA-Z0-9._-]/,
|
|
24707
|
+
replacement: "_",
|
|
24708
|
+
fallback: "cwd"
|
|
24709
|
+
});
|
|
23969
24710
|
}
|
|
23970
24711
|
cwdWorkerSessionPart(cwd) {
|
|
23971
24712
|
const label = this.workspaceLabelFromCwd(cwd);
|
|
@@ -25144,11 +25885,13 @@ class SessionService {
|
|
|
25144
25885
|
stateStore;
|
|
25145
25886
|
state;
|
|
25146
25887
|
stateMutex;
|
|
25888
|
+
now;
|
|
25147
25889
|
constructor(config2, stateStore, state, options = {}) {
|
|
25148
25890
|
this.config = config2;
|
|
25149
25891
|
this.stateStore = stateStore;
|
|
25150
25892
|
this.state = state;
|
|
25151
25893
|
this.stateMutex = options.stateMutex ?? new AsyncMutex;
|
|
25894
|
+
this.now = options.now ?? (() => Date.now());
|
|
25152
25895
|
}
|
|
25153
25896
|
async createSession(alias, agent, workspace) {
|
|
25154
25897
|
return await this.createLogicalSession(alias, agent, workspace, `${workspace}:${alias}`);
|
|
@@ -25182,6 +25925,14 @@ class SessionService {
|
|
|
25182
25925
|
async attachSession(alias, agent, workspace, transportSession, transportAgentCommand) {
|
|
25183
25926
|
return await this.createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand);
|
|
25184
25927
|
}
|
|
25928
|
+
async attachNativeSession(input) {
|
|
25929
|
+
return await this.createLogicalSession(input.alias, input.agent, input.workspace, input.transportSession, input.transportAgentCommand, {
|
|
25930
|
+
source: "agent-side",
|
|
25931
|
+
agentSessionId: input.agentSessionId,
|
|
25932
|
+
title: input.title,
|
|
25933
|
+
updatedAt: input.updatedAt
|
|
25934
|
+
});
|
|
25935
|
+
}
|
|
25185
25936
|
async getSession(alias) {
|
|
25186
25937
|
const session = this.state.sessions[alias];
|
|
25187
25938
|
if (!session) {
|
|
@@ -25196,6 +25947,22 @@ class SessionService {
|
|
|
25196
25947
|
const preferred = matches.find((session) => session.alias === expectedAlias && session.workspace === expectedWorkspace) ?? matches[0];
|
|
25197
25948
|
return preferred ? this.toResolvedSession(preferred) : null;
|
|
25198
25949
|
}
|
|
25950
|
+
async findAttachedNativeSession(chatKey, agent, agentSessionId) {
|
|
25951
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
25952
|
+
for (const session of Object.values(this.state.sessions)) {
|
|
25953
|
+
if (session.source !== "agent-side") {
|
|
25954
|
+
continue;
|
|
25955
|
+
}
|
|
25956
|
+
if (session.agent !== agent || session.agent_session_id !== agentSessionId) {
|
|
25957
|
+
continue;
|
|
25958
|
+
}
|
|
25959
|
+
if (!isSessionAliasVisibleInChannel(session.alias, channelId)) {
|
|
25960
|
+
continue;
|
|
25961
|
+
}
|
|
25962
|
+
return this.toResolvedSession(session);
|
|
25963
|
+
}
|
|
25964
|
+
return null;
|
|
25965
|
+
}
|
|
25199
25966
|
async useSession(chatKey, alias) {
|
|
25200
25967
|
await this.mutate(async () => {
|
|
25201
25968
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
@@ -25315,6 +26082,49 @@ class SessionService {
|
|
|
25315
26082
|
return { wasActive };
|
|
25316
26083
|
});
|
|
25317
26084
|
}
|
|
26085
|
+
async cacheNativeSessionList(chatKey, input) {
|
|
26086
|
+
await this.mutate(async () => {
|
|
26087
|
+
this.state.native_session_lists[chatKey] = {
|
|
26088
|
+
created_at: new Date(this.now()).toISOString(),
|
|
26089
|
+
agent: input.agent,
|
|
26090
|
+
...input.workspace !== undefined ? { workspace: input.workspace } : {},
|
|
26091
|
+
cwd: input.cwd,
|
|
26092
|
+
sessions: input.sessions.map((session) => ({
|
|
26093
|
+
session_id: session.sessionId,
|
|
26094
|
+
...session.cwd !== undefined ? { cwd: session.cwd } : {},
|
|
26095
|
+
...session.title !== undefined ? { title: session.title } : {},
|
|
26096
|
+
...session.updatedAt !== undefined ? { updated_at: session.updatedAt } : {}
|
|
26097
|
+
})),
|
|
26098
|
+
...input.nextCursor !== undefined ? { next_cursor: input.nextCursor } : {}
|
|
26099
|
+
};
|
|
26100
|
+
await this.persist();
|
|
26101
|
+
});
|
|
26102
|
+
}
|
|
26103
|
+
async getNativeSessionList(chatKey, ttlMs = 10 * 60 * 1000) {
|
|
26104
|
+
const cached2 = this.state.native_session_lists[chatKey];
|
|
26105
|
+
if (!cached2) {
|
|
26106
|
+
return null;
|
|
26107
|
+
}
|
|
26108
|
+
const createdAt = Date.parse(cached2.created_at);
|
|
26109
|
+
if (Number.isNaN(createdAt)) {
|
|
26110
|
+
return null;
|
|
26111
|
+
}
|
|
26112
|
+
if (this.now() - createdAt > ttlMs) {
|
|
26113
|
+
return null;
|
|
26114
|
+
}
|
|
26115
|
+
return {
|
|
26116
|
+
agent: cached2.agent,
|
|
26117
|
+
...cached2.workspace !== undefined ? { workspace: cached2.workspace } : {},
|
|
26118
|
+
cwd: cached2.cwd,
|
|
26119
|
+
sessions: cached2.sessions.map((session) => ({
|
|
26120
|
+
sessionId: session.session_id,
|
|
26121
|
+
...session.cwd !== undefined ? { cwd: session.cwd } : {},
|
|
26122
|
+
...session.title !== undefined ? { title: session.title } : {},
|
|
26123
|
+
...session.updated_at !== undefined ? { updatedAt: session.updated_at } : {}
|
|
26124
|
+
})),
|
|
26125
|
+
...cached2.next_cursor !== undefined ? { nextCursor: cached2.next_cursor } : {}
|
|
26126
|
+
};
|
|
26127
|
+
}
|
|
25318
26128
|
toResolvedSession(session) {
|
|
25319
26129
|
const agentConfig = this.config.agents[session.agent];
|
|
25320
26130
|
if (!agentConfig) {
|
|
@@ -25330,6 +26140,11 @@ class SessionService {
|
|
|
25330
26140
|
agentCommand: session.transport_agent_command ?? resolveAgentCommand(agentConfig.driver, agentConfig.command),
|
|
25331
26141
|
workspace: session.workspace,
|
|
25332
26142
|
transportSession: session.transport_session,
|
|
26143
|
+
source: session.source,
|
|
26144
|
+
agentSessionId: session.agent_session_id,
|
|
26145
|
+
agentSessionTitle: session.agent_session_title,
|
|
26146
|
+
agentSessionUpdatedAt: session.agent_session_updated_at,
|
|
26147
|
+
attachedAt: session.attached_at,
|
|
25333
26148
|
modeId: session.mode_id,
|
|
25334
26149
|
replyMode: session.reply_mode,
|
|
25335
26150
|
cwd: workspaceConfig.cwd
|
|
@@ -25357,20 +26172,25 @@ class SessionService {
|
|
|
25357
26172
|
async persist() {
|
|
25358
26173
|
await this.stateStore.save(this.state);
|
|
25359
26174
|
}
|
|
25360
|
-
async createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand) {
|
|
26175
|
+
async createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand, native) {
|
|
25361
26176
|
return await this.mutate(async () => {
|
|
25362
26177
|
this.validateSession(alias, agent, workspace);
|
|
25363
26178
|
if (this.state.orchestration.externalCoordinators[transportSession]) {
|
|
25364
26179
|
throw new Error(`transport session "${transportSession}" conflicts with an external coordinator`);
|
|
25365
26180
|
}
|
|
25366
26181
|
const existingSession = this.state.sessions[alias];
|
|
25367
|
-
const now = new Date().toISOString();
|
|
26182
|
+
const now = new Date(this.now()).toISOString();
|
|
25368
26183
|
const normalizedTransportAgentCommand = transportAgentCommand?.trim();
|
|
25369
26184
|
const session = {
|
|
25370
26185
|
alias,
|
|
25371
26186
|
agent,
|
|
25372
26187
|
workspace,
|
|
25373
26188
|
transport_session: transportSession,
|
|
26189
|
+
source: native?.source,
|
|
26190
|
+
agent_session_id: native?.agentSessionId,
|
|
26191
|
+
agent_session_title: native?.title ?? undefined,
|
|
26192
|
+
agent_session_updated_at: native?.updatedAt,
|
|
26193
|
+
attached_at: native ? now : undefined,
|
|
25374
26194
|
...normalizedTransportAgentCommand ? { transport_agent_command: normalizedTransportAgentCommand } : existingSession?.transport_agent_command ? { transport_agent_command: existingSession.transport_agent_command } : {},
|
|
25375
26195
|
mode_id: existingSession?.mode_id,
|
|
25376
26196
|
reply_mode: existingSession?.reply_mode,
|
|
@@ -25483,6 +26303,37 @@ class DebouncedStateStore {
|
|
|
25483
26303
|
}
|
|
25484
26304
|
}
|
|
25485
26305
|
|
|
26306
|
+
// src/commands/command-hints.ts
|
|
26307
|
+
function listWeacpxCommandHints() {
|
|
26308
|
+
const hints = [{ name: "/help", description: "查看命令帮助。" }];
|
|
26309
|
+
for (const topic of HELP_TOPICS) {
|
|
26310
|
+
const name = PRIMARY_COMMAND_BY_TOPIC[topic.topic];
|
|
26311
|
+
if (!name) {
|
|
26312
|
+
throw new Error(`command-hints: 未登记 help topic 的主命令: ${topic.topic}`);
|
|
26313
|
+
}
|
|
26314
|
+
hints.push({ name, description: topic.summary });
|
|
26315
|
+
}
|
|
26316
|
+
return hints;
|
|
26317
|
+
}
|
|
26318
|
+
var PRIMARY_COMMAND_BY_TOPIC;
|
|
26319
|
+
var init_command_hints = __esm(() => {
|
|
26320
|
+
init_help_registry();
|
|
26321
|
+
PRIMARY_COMMAND_BY_TOPIC = {
|
|
26322
|
+
session: "/session",
|
|
26323
|
+
native: "/ssn",
|
|
26324
|
+
workspace: "/workspace",
|
|
26325
|
+
agent: "/agent",
|
|
26326
|
+
permission: "/permission",
|
|
26327
|
+
config: "/config",
|
|
26328
|
+
orchestration: "/delegate",
|
|
26329
|
+
mode: "/mode",
|
|
26330
|
+
replymode: "/replymode",
|
|
26331
|
+
status: "/status",
|
|
26332
|
+
cancel: "/cancel",
|
|
26333
|
+
later: "/later"
|
|
26334
|
+
};
|
|
26335
|
+
});
|
|
26336
|
+
|
|
25486
26337
|
// src/run-console.ts
|
|
25487
26338
|
var exports_run_console = {};
|
|
25488
26339
|
__export(exports_run_console, {
|
|
@@ -25597,7 +26448,9 @@ async function runConsole(paths, deps) {
|
|
|
25597
26448
|
abortSignal: shutdownController.signal,
|
|
25598
26449
|
quota: runtime.quota,
|
|
25599
26450
|
logger: runtime.logger,
|
|
25600
|
-
perfTracer: runtime.perfTracer
|
|
26451
|
+
perfTracer: runtime.perfTracer,
|
|
26452
|
+
commandHints: listWeacpxCommandHints(),
|
|
26453
|
+
coreVersion: WEACPX_CORE_VERSION
|
|
25601
26454
|
});
|
|
25602
26455
|
channelStartPromise.catch(() => {});
|
|
25603
26456
|
let channelStartSettled = false;
|
|
@@ -25715,6 +26568,8 @@ async function runCleanupSequence(input) {
|
|
|
25715
26568
|
}
|
|
25716
26569
|
var init_run_console = __esm(() => {
|
|
25717
26570
|
init_consumer_lock();
|
|
26571
|
+
init_command_hints();
|
|
26572
|
+
init_version();
|
|
25718
26573
|
});
|
|
25719
26574
|
|
|
25720
26575
|
// src/transport/acpx-bridge/acpx-bridge-protocol.ts
|
|
@@ -26167,6 +27022,18 @@ class AcpxBridgeTransport {
|
|
|
26167
27022
|
lines
|
|
26168
27023
|
});
|
|
26169
27024
|
}
|
|
27025
|
+
async listAgentSessions(query) {
|
|
27026
|
+
return await this.client.request("listAgentSessions", { ...query });
|
|
27027
|
+
}
|
|
27028
|
+
async resumeAgentSession(session, agentSessionId) {
|
|
27029
|
+
await this.client.request("resumeAgentSession", {
|
|
27030
|
+
agent: session.agent,
|
|
27031
|
+
...session.agentCommand ? { agentCommand: session.agentCommand } : {},
|
|
27032
|
+
cwd: session.cwd,
|
|
27033
|
+
name: session.transportSession,
|
|
27034
|
+
agentSessionId
|
|
27035
|
+
});
|
|
27036
|
+
}
|
|
26170
27037
|
async prompt(session, text, reply, replyContext, options) {
|
|
26171
27038
|
const sink = reply ? createQuotaGatedReplySink({
|
|
26172
27039
|
reply,
|
|
@@ -26759,7 +27626,7 @@ var init_node_pty_helper = () => {};
|
|
|
26759
27626
|
// src/transport/acpx-queue-owner-launcher.ts
|
|
26760
27627
|
import { createHash as createHash3 } from "node:crypto";
|
|
26761
27628
|
import { spawn as spawn8 } from "node:child_process";
|
|
26762
|
-
import { readFile as
|
|
27629
|
+
import { readFile as readFile12, unlink } from "node:fs/promises";
|
|
26763
27630
|
import { homedir as homedir8 } from "node:os";
|
|
26764
27631
|
import { join as join13 } from "node:path";
|
|
26765
27632
|
function buildWeacpxMcpServerSpec(input) {
|
|
@@ -26915,7 +27782,7 @@ async function terminateAcpxQueueOwner(sessionId) {
|
|
|
26915
27782
|
const lockPath = queueLockFilePath(sessionId);
|
|
26916
27783
|
let owner;
|
|
26917
27784
|
try {
|
|
26918
|
-
owner = JSON.parse(await
|
|
27785
|
+
owner = JSON.parse(await readFile12(lockPath, "utf8"));
|
|
26919
27786
|
} catch {
|
|
26920
27787
|
return;
|
|
26921
27788
|
}
|
|
@@ -26943,7 +27810,7 @@ function resolveDefaultWeacpxCommand(env) {
|
|
|
26943
27810
|
return "weacpx";
|
|
26944
27811
|
}
|
|
26945
27812
|
function quoteCommandPart(value) {
|
|
26946
|
-
return
|
|
27813
|
+
return quoteIfNeeded(value);
|
|
26947
27814
|
}
|
|
26948
27815
|
var init_acpx_queue_owner_launcher = __esm(() => {
|
|
26949
27816
|
init_spawn_command();
|
|
@@ -26962,6 +27829,60 @@ function permissionModeToFlag(permissionMode) {
|
|
|
26962
27829
|
}
|
|
26963
27830
|
}
|
|
26964
27831
|
|
|
27832
|
+
// src/transport/agent-session-list.ts
|
|
27833
|
+
function isUnknownFilterCwdOption(output) {
|
|
27834
|
+
return /(?:unknown|unrecognized) option/i.test(output) && output.includes("--filter-cwd");
|
|
27835
|
+
}
|
|
27836
|
+
async function runAgentSessionList(options) {
|
|
27837
|
+
let result = await options.runList(true);
|
|
27838
|
+
let filterLocally = false;
|
|
27839
|
+
if (result.code !== 0 && options.filterCwd && isUnknownFilterCwdOption(result.stdout + result.stderr)) {
|
|
27840
|
+
result = await options.runList(false);
|
|
27841
|
+
filterLocally = true;
|
|
27842
|
+
}
|
|
27843
|
+
if (result.code !== 0) {
|
|
27844
|
+
if ((result.stdout + result.stderr).includes("sessionCapabilities.list")) {
|
|
27845
|
+
return;
|
|
27846
|
+
}
|
|
27847
|
+
throw new Error(options.formatError(result));
|
|
27848
|
+
}
|
|
27849
|
+
return parseAgentSessionListOutput(result.stdout, filterLocally ? options.filterCwd : undefined);
|
|
27850
|
+
}
|
|
27851
|
+
function parseAgentSessionListOutput(stdout2, filterCwd) {
|
|
27852
|
+
let parsed;
|
|
27853
|
+
try {
|
|
27854
|
+
parsed = JSON.parse(stdout2);
|
|
27855
|
+
} catch {
|
|
27856
|
+
throw new Error("failed to parse acpx sessions list output");
|
|
27857
|
+
}
|
|
27858
|
+
if (!isAgentSessionListResult(parsed)) {
|
|
27859
|
+
return;
|
|
27860
|
+
}
|
|
27861
|
+
return filterCwd ? filterAgentSessionListByCwd(parsed, filterCwd) : parsed;
|
|
27862
|
+
}
|
|
27863
|
+
function isAgentSessionListResult(value) {
|
|
27864
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
27865
|
+
return false;
|
|
27866
|
+
const record3 = value;
|
|
27867
|
+
if (record3.source !== "agent" || !Array.isArray(record3.sessions))
|
|
27868
|
+
return false;
|
|
27869
|
+
return record3.sessions.every((session) => {
|
|
27870
|
+
if (!session || typeof session !== "object" || Array.isArray(session))
|
|
27871
|
+
return false;
|
|
27872
|
+
const item = session;
|
|
27873
|
+
return typeof item.sessionId === "string";
|
|
27874
|
+
});
|
|
27875
|
+
}
|
|
27876
|
+
function filterAgentSessionListByCwd(result, cwd) {
|
|
27877
|
+
return {
|
|
27878
|
+
...result,
|
|
27879
|
+
sessions: result.sessions.filter((session) => session.cwd && isSamePath(session.cwd, cwd))
|
|
27880
|
+
};
|
|
27881
|
+
}
|
|
27882
|
+
var init_agent_session_list = __esm(() => {
|
|
27883
|
+
init_path();
|
|
27884
|
+
});
|
|
27885
|
+
|
|
26965
27886
|
// src/transport/acpx-cli/acpx-cli-transport.ts
|
|
26966
27887
|
import { createRequire as createRequire5 } from "node:module";
|
|
26967
27888
|
import { spawn as spawn9 } from "node:child_process";
|
|
@@ -27071,6 +27992,23 @@ class AcpxCliTransport {
|
|
|
27071
27992
|
timeoutMs: this.sessionInitTimeoutMs
|
|
27072
27993
|
});
|
|
27073
27994
|
}
|
|
27995
|
+
async listAgentSessions(query) {
|
|
27996
|
+
return await runAgentSessionList({
|
|
27997
|
+
filterCwd: query.filterCwd,
|
|
27998
|
+
runList: async (includeFilterCwd) => {
|
|
27999
|
+
const args = this.buildAgentQueryArgs(query, "json", [
|
|
28000
|
+
"sessions",
|
|
28001
|
+
"list",
|
|
28002
|
+
...includeFilterCwd && query.filterCwd ? ["--filter-cwd", query.filterCwd] : [],
|
|
28003
|
+
...query.cursor ? ["--cursor", query.cursor] : []
|
|
28004
|
+
]);
|
|
28005
|
+
return await this.runCommandWithTimeout(this.runCommand, args, {
|
|
28006
|
+
timeoutMs: this.sessionInitTimeoutMs
|
|
28007
|
+
});
|
|
28008
|
+
},
|
|
28009
|
+
formatError: (result) => normalizeCommandError(result) ?? `command failed with exit code ${result.code}`
|
|
28010
|
+
});
|
|
28011
|
+
}
|
|
27074
28012
|
async tailSessionHistory(session, lines) {
|
|
27075
28013
|
const candidates = [
|
|
27076
28014
|
["sessions", "history", "quiet", "-s", session.transportSession, String(lines)],
|
|
@@ -27139,6 +28077,20 @@ ${baseText}` : "" };
|
|
|
27139
28077
|
message: output.trim()
|
|
27140
28078
|
};
|
|
27141
28079
|
}
|
|
28080
|
+
async resumeAgentSession(session, agentSessionId) {
|
|
28081
|
+
const args = this.buildArgs(session, [
|
|
28082
|
+
"sessions",
|
|
28083
|
+
"new",
|
|
28084
|
+
"--name",
|
|
28085
|
+
session.transportSession,
|
|
28086
|
+
"--resume-session",
|
|
28087
|
+
agentSessionId
|
|
28088
|
+
]);
|
|
28089
|
+
const runResume = session.agentCommand ? this.run : this.runWithPty;
|
|
28090
|
+
await runResume.call(this, args, {
|
|
28091
|
+
timeoutMs: this.sessionInitTimeoutMs
|
|
28092
|
+
});
|
|
28093
|
+
}
|
|
27142
28094
|
async updatePermissionPolicy(policy) {
|
|
27143
28095
|
this.permissionMode = policy.permissionMode;
|
|
27144
28096
|
this.nonInteractivePermissions = policy.nonInteractivePermissions;
|
|
@@ -27372,6 +28324,13 @@ ${baseText}` : "" };
|
|
|
27372
28324
|
}
|
|
27373
28325
|
return [...prefix, session.agent, ...tail2];
|
|
27374
28326
|
}
|
|
28327
|
+
buildAgentQueryArgs(query, format, tail2) {
|
|
28328
|
+
const prefix = ["--format", format, "--cwd", query.cwd, ...this.buildPermissionArgs()];
|
|
28329
|
+
if (query.agentCommand) {
|
|
28330
|
+
return [...prefix, "--agent", query.agentCommand, ...tail2];
|
|
28331
|
+
}
|
|
28332
|
+
return [...prefix, query.agent, ...tail2];
|
|
28333
|
+
}
|
|
27375
28334
|
buildPromptArgs(session, text, promptFile) {
|
|
27376
28335
|
const prefix = [
|
|
27377
28336
|
"--format",
|
|
@@ -27437,9 +28396,34 @@ var init_acpx_cli_transport = __esm(() => {
|
|
|
27437
28396
|
init_node_pty_helper();
|
|
27438
28397
|
init_terminate_process_tree();
|
|
27439
28398
|
init_acpx_queue_owner_launcher();
|
|
28399
|
+
init_agent_session_list();
|
|
27440
28400
|
require4 = createRequire5(import.meta.url);
|
|
27441
28401
|
});
|
|
27442
28402
|
|
|
28403
|
+
// src/util/async.ts
|
|
28404
|
+
function settleWithinTimeout(work, timeoutMs) {
|
|
28405
|
+
return new Promise((resolve3) => {
|
|
28406
|
+
let settled = false;
|
|
28407
|
+
const finish = () => {
|
|
28408
|
+
if (!settled) {
|
|
28409
|
+
settled = true;
|
|
28410
|
+
resolve3();
|
|
28411
|
+
}
|
|
28412
|
+
};
|
|
28413
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
28414
|
+
if (typeof timer.unref === "function") {
|
|
28415
|
+
timer.unref();
|
|
28416
|
+
}
|
|
28417
|
+
work.then(() => {
|
|
28418
|
+
clearTimeout(timer);
|
|
28419
|
+
finish();
|
|
28420
|
+
}, () => {
|
|
28421
|
+
clearTimeout(timer);
|
|
28422
|
+
finish();
|
|
28423
|
+
});
|
|
28424
|
+
});
|
|
28425
|
+
}
|
|
28426
|
+
|
|
27443
28427
|
// src/transport/queue-owner-reaper.ts
|
|
27444
28428
|
import { spawn as spawn10 } from "node:child_process";
|
|
27445
28429
|
async function reapQueueOwners(acpxCommand, targets, deps = {}) {
|
|
@@ -27470,28 +28454,6 @@ async function reapQueueOwners(acpxCommand, targets, deps = {}) {
|
|
|
27470
28454
|
await settleWithinTimeout(Promise.all(unique.map(reapOne)), timeoutMs);
|
|
27471
28455
|
return { terminated, attempted: unique.length };
|
|
27472
28456
|
}
|
|
27473
|
-
function settleWithinTimeout(work, timeoutMs) {
|
|
27474
|
-
return new Promise((resolve3) => {
|
|
27475
|
-
let settled = false;
|
|
27476
|
-
const finish = () => {
|
|
27477
|
-
if (!settled) {
|
|
27478
|
-
settled = true;
|
|
27479
|
-
resolve3();
|
|
27480
|
-
}
|
|
27481
|
-
};
|
|
27482
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
27483
|
-
if (typeof timer.unref === "function") {
|
|
27484
|
-
timer.unref();
|
|
27485
|
-
}
|
|
27486
|
-
work.then(() => {
|
|
27487
|
-
clearTimeout(timer);
|
|
27488
|
-
finish();
|
|
27489
|
-
}, () => {
|
|
27490
|
-
clearTimeout(timer);
|
|
27491
|
-
finish();
|
|
27492
|
-
});
|
|
27493
|
-
});
|
|
27494
|
-
}
|
|
27495
28457
|
async function defaultResolveRecordId(acpxCommand, target) {
|
|
27496
28458
|
const args = [
|
|
27497
28459
|
"--format",
|
|
@@ -27650,6 +28612,9 @@ class MessageChannelRegistry {
|
|
|
27650
28612
|
}
|
|
27651
28613
|
await channel.sendScheduledMessage(input);
|
|
27652
28614
|
}
|
|
28615
|
+
nativeSessionListFormat(chatKey) {
|
|
28616
|
+
return this.getByChatKey(chatKey)?.nativeSessionListFormat ?? "table";
|
|
28617
|
+
}
|
|
27653
28618
|
createConsumerLocks() {
|
|
27654
28619
|
const result = [];
|
|
27655
28620
|
for (const channel of this.channels.values()) {
|
|
@@ -28234,7 +29199,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
28234
29199
|
listScheduledTasksFromRoute: async (input) => await listScheduledTasksFromRoute(input, { state, scheduled: scheduledService }),
|
|
28235
29200
|
cancelScheduledTaskFromRoute: async (input) => await cancelScheduledTaskFromRoute(input, { state, scheduled: scheduledService })
|
|
28236
29201
|
});
|
|
28237
|
-
const router = new CommandRouter(sessions, transport, config2, configStore, logger2, undefined, orchestration, quota, scheduledService, deps.channel?.supportsScheduledMessages ? { supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel) } : undefined);
|
|
29202
|
+
const router = new CommandRouter(sessions, transport, config2, configStore, logger2, undefined, orchestration, quota, scheduledService, deps.channel?.supportsScheduledMessages ? { supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel) } : undefined, deps.channel?.nativeSessionListFormat ? deps.channel.nativeSessionListFormat.bind(deps.channel) : undefined);
|
|
28238
29203
|
const agent = new ConsoleAgent(router, logger2);
|
|
28239
29204
|
const scheduledScheduler = new ScheduledTaskScheduler(scheduledService, {
|
|
28240
29205
|
dispatchTask: buildScheduledDispatchTask({
|
|
@@ -42027,16 +42992,15 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
42027
42992
|
},
|
|
42028
42993
|
{
|
|
42029
42994
|
name: "task_get",
|
|
42030
|
-
description: "Fetch a single task under the current coordinator,
|
|
42995
|
+
description: "Fetch a single task under the current coordinator: its summary, latest progress, and — once terminal — the worker's final result. Prefer task_watch to follow a task; its terminal result already carries the output, so a follow-up task_get is unnecessary. Reach for task_get to recover a task you lost track of, to inspect one that requires attention, or to re-read the original delegated prompt. The full prompt is included only for needs_confirmation tasks unless you pass includePrompt:true.",
|
|
42031
42996
|
inputSchema: exports_external.object({
|
|
42032
|
-
taskId: exports_external.string().min(1)
|
|
42997
|
+
taskId: exports_external.string().min(1),
|
|
42998
|
+
includePrompt: exports_external.boolean().optional()
|
|
42033
42999
|
}).strict(),
|
|
42034
43000
|
handler: async (args) => await asToolResult(async () => {
|
|
42035
|
-
const
|
|
42036
|
-
|
|
42037
|
-
|
|
42038
|
-
});
|
|
42039
|
-
return createSuccessResult(task ? renderTaskSummary(task) : "Task not found.", { task });
|
|
43001
|
+
const { taskId, includePrompt } = args;
|
|
43002
|
+
const task = await transport.getTask({ coordinatorSession, taskId });
|
|
43003
|
+
return createSuccessResult(task ? renderTaskSummary(task, { includePrompt: includePrompt ?? false }) : "Task not found.", { task });
|
|
42040
43004
|
})
|
|
42041
43005
|
},
|
|
42042
43006
|
{
|
|
@@ -42275,12 +43239,23 @@ function renderTaskWatchResult(result) {
|
|
|
42275
43239
|
const events = result.events.length > 0 ? [
|
|
42276
43240
|
"- Events:",
|
|
42277
43241
|
...result.events.map((event) => {
|
|
42278
|
-
const
|
|
42279
|
-
return ` - #${event.seq} ${event.type} at ${event.at}${
|
|
43242
|
+
const detail2 = event.summary ?? event.message ?? event.status ?? "";
|
|
43243
|
+
return ` - #${event.seq} ${event.type} at ${event.at}${detail2 ? `: ${detail2}` : ""}`;
|
|
42280
43244
|
})
|
|
42281
43245
|
] : ["- Events: none"];
|
|
42282
|
-
const
|
|
42283
|
-
|
|
43246
|
+
const detail = [];
|
|
43247
|
+
if (result.status === "terminal") {
|
|
43248
|
+
const resultText = result.task.resultText?.trim() ?? "";
|
|
43249
|
+
const summary = result.task.summary?.trim() ?? "";
|
|
43250
|
+
if (resultText.length > 0)
|
|
43251
|
+
detail.push(`- Result: ${resultText}`);
|
|
43252
|
+
else if (summary.length > 0)
|
|
43253
|
+
detail.push(`- Summary: ${summary}`);
|
|
43254
|
+
} else if (result.status === "attention_required" && result.task.openQuestion) {
|
|
43255
|
+
detail.push(`- Open question: ${result.task.openQuestion.question}`);
|
|
43256
|
+
}
|
|
43257
|
+
const next = result.status === "terminal" ? "Next: summarize this result for the user." : result.status === "attention_required" ? "Next: resolve the pending question / contested review with the recommended action tool (coordinator_answer_question or coordinator_review_contested_result); call task_get only if you need more detail." : `Next: call task_watch again with afterSeq=${result.nextAfterSeq} to keep watching, preferably as an MCP task if your client supports background task execution.`;
|
|
43258
|
+
return [...header, ...events, ...detail, next].join(`
|
|
42284
43259
|
`);
|
|
42285
43260
|
}
|
|
42286
43261
|
function createSuccessResult(text, structuredContent) {
|
|
@@ -42296,7 +43271,7 @@ function createErrorResult(message) {
|
|
|
42296
43271
|
};
|
|
42297
43272
|
}
|
|
42298
43273
|
function renderDelegateSuccess(result) {
|
|
42299
|
-
const next = result.status === "needs_confirmation" ? `Next: this delegation requires user approval. Tell the user, then call task_approve or task_cancel based on their response.` : result.status === "queued" ? `Next: task "${result.taskId}" is queued (agent at parallel capacity). It will start automatically when a slot frees. Call task_watch to long-poll
|
|
43274
|
+
const next = result.status === "needs_confirmation" ? `Next: this delegation requires user approval. Tell the user, then call task_approve or task_cancel based on their response.` : result.status === "queued" ? `Next: task "${result.taskId}" is queued (agent at parallel capacity). It will start automatically when a slot frees. Call task_watch to long-poll until it runs and then finishes — the terminal watch carries the result. Use task_list only to resurvey in-flight tasks.` : `Next: task "${result.taskId}" is running. Return this taskId to the user, then call task_watch to long-poll until it finishes — the terminal watch carries the worker's result, so no follow-up task_get is needed. Use task_list only to resurvey in-flight tasks.`;
|
|
42300
43275
|
return [`Delegation task "${result.taskId}" created.`, `- Status: ${result.status}`, next].join(`
|
|
42301
43276
|
`);
|
|
42302
43277
|
}
|
|
@@ -42340,7 +43315,7 @@ function renderTaskListItem(task) {
|
|
|
42340
43315
|
].filter(Boolean).map((item) => `; ${item}`).join("");
|
|
42341
43316
|
return `- ${task.taskId} [${task.status}] ${task.targetAgent}${role} -> ${task.workerSession ?? "unassigned"}${group}${source}${summary}${reliability}`;
|
|
42342
43317
|
}
|
|
42343
|
-
function renderTaskSummary(task) {
|
|
43318
|
+
function renderTaskSummary(task, options = {}) {
|
|
42344
43319
|
const header = [
|
|
42345
43320
|
`Task "${task.taskId}"`,
|
|
42346
43321
|
`- Status: ${task.status}`,
|
|
@@ -42355,7 +43330,9 @@ function renderTaskSummary(task) {
|
|
|
42355
43330
|
if (task.status === "needs_confirmation") {
|
|
42356
43331
|
header.push(`- Source: ${task.sourceKind} / ${task.sourceHandle}${task.role ? ` / ${task.role}` : ""}`);
|
|
42357
43332
|
}
|
|
42358
|
-
|
|
43333
|
+
if (task.status === "needs_confirmation" || options.includePrompt) {
|
|
43334
|
+
header.push(`- Task: ${task.task}`);
|
|
43335
|
+
}
|
|
42359
43336
|
if (task.summary.trim().length > 0)
|
|
42360
43337
|
header.push(`- Summary: ${task.summary}`);
|
|
42361
43338
|
if (task.lastProgressSummary)
|
|
@@ -42406,7 +43383,7 @@ function renderTaskApprovalSuccess(task) {
|
|
|
42406
43383
|
return [
|
|
42407
43384
|
`Task "${task.taskId}" approved.`,
|
|
42408
43385
|
`- Current status: ${task.status}`,
|
|
42409
|
-
`Next:
|
|
43386
|
+
`Next: call task_watch to long-poll until the worker finishes — the terminal watch returns the result directly, so no follow-up task_get is needed. Use task_list only to resurvey in-flight tasks.`
|
|
42410
43387
|
].join(`
|
|
42411
43388
|
`);
|
|
42412
43389
|
}
|
|
@@ -42904,13 +43881,24 @@ function renderWatchMcpTaskResult(result, watchTaskId) {
|
|
|
42904
43881
|
const events = result.events.length > 0 ? [
|
|
42905
43882
|
"Events:",
|
|
42906
43883
|
...result.events.map((event) => {
|
|
42907
|
-
const
|
|
42908
|
-
return `- #${event.seq} ${event.type} at ${event.at}${
|
|
43884
|
+
const detail2 = event.summary ?? event.message ?? event.status ?? "";
|
|
43885
|
+
return `- #${event.seq} ${event.type} at ${event.at}${detail2 ? `: ${detail2}` : ""}`;
|
|
42909
43886
|
})
|
|
42910
43887
|
] : ["Events: none"];
|
|
42911
|
-
const
|
|
43888
|
+
const detail = [];
|
|
43889
|
+
if (result.status === "terminal") {
|
|
43890
|
+
const resultText = result.task.resultText.trim();
|
|
43891
|
+
const summary = result.task.summary.trim();
|
|
43892
|
+
if (resultText.length > 0)
|
|
43893
|
+
detail.push(`Result: ${resultText}`);
|
|
43894
|
+
else if (summary.length > 0)
|
|
43895
|
+
detail.push(`Summary: ${summary}`);
|
|
43896
|
+
} else if (result.status === "attention_required" && result.task.openQuestion) {
|
|
43897
|
+
detail.push(`Open question: ${result.task.openQuestion.question}`);
|
|
43898
|
+
}
|
|
43899
|
+
const next = result.status === "terminal" ? "Next: summarize this result for the user." : result.status === "attention_required" ? "Next: resolve the pending question / contested review with the recommended action tool (coordinator_answer_question or coordinator_review_contested_result)." : `Next: call task_watch again with afterSeq=${result.nextAfterSeq} to keep watching.`;
|
|
42912
43900
|
return {
|
|
42913
|
-
content: [{ type: "text", text: [...header, ...events, next].join(`
|
|
43901
|
+
content: [{ type: "text", text: [...header, ...events, ...detail, next].join(`
|
|
42914
43902
|
`) }],
|
|
42915
43903
|
structuredContent: { watchTaskId, ...result }
|
|
42916
43904
|
};
|
|
@@ -43270,8 +44258,14 @@ function inferExternalCoordinatorSession(input) {
|
|
|
43270
44258
|
return `external_${sanitizeMcpClientName(input.clientName)}:${suffix}`;
|
|
43271
44259
|
}
|
|
43272
44260
|
function sanitizeMcpClientName(input) {
|
|
43273
|
-
|
|
43274
|
-
|
|
44261
|
+
return sanitizeString((input ?? "").trim(), {
|
|
44262
|
+
allow: /[a-z0-9._-]/,
|
|
44263
|
+
replacement: "-",
|
|
44264
|
+
lowercase: true,
|
|
44265
|
+
collapse: true,
|
|
44266
|
+
trim: true,
|
|
44267
|
+
fallback: "mcp-host"
|
|
44268
|
+
});
|
|
43275
44269
|
}
|
|
43276
44270
|
|
|
43277
44271
|
// src/mcp/parse-string-flag.ts
|
|
@@ -43396,11 +44390,12 @@ function resolveTemplateChoice(answer, names) {
|
|
|
43396
44390
|
// src/cli-update.ts
|
|
43397
44391
|
init_plugin_home();
|
|
43398
44392
|
import { spawn as spawn4 } from "node:child_process";
|
|
43399
|
-
import { readFile as
|
|
44393
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
43400
44394
|
import { dirname as dirname9, join as join7 } from "node:path";
|
|
43401
44395
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
43402
44396
|
|
|
43403
44397
|
// src/plugins/package-manager.ts
|
|
44398
|
+
init_plugin_home();
|
|
43404
44399
|
import { spawn as spawn3 } from "node:child_process";
|
|
43405
44400
|
async function defaultRunCommand(command, args, options) {
|
|
43406
44401
|
await new Promise((resolve, reject) => {
|
|
@@ -43441,6 +44436,7 @@ async function detectPackageManager(runCommand) {
|
|
|
43441
44436
|
async function installPluginPackage(input) {
|
|
43442
44437
|
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
43443
44438
|
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
44439
|
+
await normalizePluginHomeManifest(input.pluginHome);
|
|
43444
44440
|
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
43445
44441
|
if (packageManager === "bun") {
|
|
43446
44442
|
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
@@ -43678,7 +44674,7 @@ async function readPackageName() {
|
|
|
43678
44674
|
const here = dirname9(fileURLToPath2(import.meta.url));
|
|
43679
44675
|
for (const candidate of [join7(here, "..", "package.json"), join7(here, "..", "..", "package.json")]) {
|
|
43680
44676
|
try {
|
|
43681
|
-
const parsed = JSON.parse(await
|
|
44677
|
+
const parsed = JSON.parse(await readFile8(candidate, "utf8"));
|
|
43682
44678
|
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
43683
44679
|
return parsed.name.trim();
|
|
43684
44680
|
} catch {}
|
|
@@ -44301,7 +45297,7 @@ async function setChannelAccountEnabled(type, accountId, enabled, rawArgs, deps)
|
|
|
44301
45297
|
|
|
44302
45298
|
// src/plugins/plugin-cli.ts
|
|
44303
45299
|
init_plugin_home();
|
|
44304
|
-
import { readFile as
|
|
45300
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
44305
45301
|
import { isAbsolute, join as join9, resolve } from "node:path";
|
|
44306
45302
|
init_plugin_loader();
|
|
44307
45303
|
init_validate_plugin();
|
|
@@ -44311,14 +45307,14 @@ init_channel_scope();
|
|
|
44311
45307
|
init_plugin_loader();
|
|
44312
45308
|
init_validate_plugin();
|
|
44313
45309
|
init_known_plugins();
|
|
44314
|
-
import { readFile as
|
|
45310
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
44315
45311
|
import { join as join8 } from "node:path";
|
|
44316
45312
|
function suggestedPluginPackageForChannel(type) {
|
|
44317
45313
|
return findKnownPluginByChannel(type)?.packageName ?? `<npm-package-that-provides-${type}>`;
|
|
44318
45314
|
}
|
|
44319
45315
|
async function readDependencyEntries(pluginHome) {
|
|
44320
45316
|
try {
|
|
44321
|
-
const raw = await
|
|
45317
|
+
const raw = await readFile9(join8(pluginHome, "package.json"), "utf8");
|
|
44322
45318
|
const parsed = JSON.parse(raw);
|
|
44323
45319
|
const out = {};
|
|
44324
45320
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -44416,11 +45412,11 @@ async function inspectPlugins(input) {
|
|
|
44416
45412
|
// src/plugins/plugin-cli.ts
|
|
44417
45413
|
init_known_plugins();
|
|
44418
45414
|
function looksLikePath(spec) {
|
|
44419
|
-
return spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/") ||
|
|
45415
|
+
return spec === "." || spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/") || spec.startsWith(".\\") || spec.startsWith("..\\") || spec.startsWith("\\") || /^[a-zA-Z]:[\\/]/.test(spec) || isAbsolute(spec);
|
|
44420
45416
|
}
|
|
44421
45417
|
async function readDependencyEntries2(pluginHome) {
|
|
44422
45418
|
try {
|
|
44423
|
-
const raw = await
|
|
45419
|
+
const raw = await readFile10(join9(pluginHome, "package.json"), "utf8");
|
|
44424
45420
|
const parsed = JSON.parse(raw);
|
|
44425
45421
|
const out = {};
|
|
44426
45422
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -44446,7 +45442,7 @@ async function resolveLocalPluginName(installSpec, pluginHome, namesBeforeInstal
|
|
|
44446
45442
|
return name;
|
|
44447
45443
|
}
|
|
44448
45444
|
try {
|
|
44449
|
-
const raw = await
|
|
45445
|
+
const raw = await readFile10(join9(installSpec, "package.json"), "utf8");
|
|
44450
45446
|
const parsed = JSON.parse(raw);
|
|
44451
45447
|
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
44452
45448
|
return parsed.name.trim();
|