@openacp/cli 2026.405.2 → 2026.406.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{channel-DstweC6V.d.ts → channel-CKXNnTy4.d.ts} +1 -0
- package/dist/cli.js +686 -457
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +29 -14
- package/dist/index.js +481 -267
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1104,7 +1104,7 @@ Declare in \`permissions\` array. Only request what you need.
|
|
|
1104
1104
|
|
|
1105
1105
|
Calling a method without the required permission throws \`PluginPermissionError\`.
|
|
1106
1106
|
|
|
1107
|
-
## Middleware Hooks (
|
|
1107
|
+
## Middleware Hooks (19 total)
|
|
1108
1108
|
|
|
1109
1109
|
Register with \`ctx.registerMiddleware(hook, { priority?, handler })\`. Return \`null\` to block the flow, call \`next()\` to continue.
|
|
1110
1110
|
|
|
@@ -1757,6 +1757,104 @@ var init_security_guard = __esm({
|
|
|
1757
1757
|
}
|
|
1758
1758
|
});
|
|
1759
1759
|
|
|
1760
|
+
// src/core/events.ts
|
|
1761
|
+
var Hook, BusEvent, SessionEv;
|
|
1762
|
+
var init_events = __esm({
|
|
1763
|
+
"src/core/events.ts"() {
|
|
1764
|
+
"use strict";
|
|
1765
|
+
Hook = {
|
|
1766
|
+
// --- Message flow ---
|
|
1767
|
+
/** Incoming message from any adapter — modifiable, can block. */
|
|
1768
|
+
MESSAGE_INCOMING: "message:incoming",
|
|
1769
|
+
/** Outgoing message before it reaches the adapter — modifiable, can block. */
|
|
1770
|
+
MESSAGE_OUTGOING: "message:outgoing",
|
|
1771
|
+
// --- Agent / turn lifecycle ---
|
|
1772
|
+
/** Before a user prompt is sent to the agent — modifiable, can block. */
|
|
1773
|
+
AGENT_BEFORE_PROMPT: "agent:beforePrompt",
|
|
1774
|
+
/** Before an agent event is dispatched — modifiable, can block. */
|
|
1775
|
+
AGENT_BEFORE_EVENT: "agent:beforeEvent",
|
|
1776
|
+
/** After an agent event is dispatched — read-only, fire-and-forget. */
|
|
1777
|
+
AGENT_AFTER_EVENT: "agent:afterEvent",
|
|
1778
|
+
/** Before the current prompt is cancelled — modifiable, can block. */
|
|
1779
|
+
AGENT_BEFORE_CANCEL: "agent:beforeCancel",
|
|
1780
|
+
/** Before the agent is switched — modifiable, can block. */
|
|
1781
|
+
AGENT_BEFORE_SWITCH: "agent:beforeSwitch",
|
|
1782
|
+
/** After the agent has been switched — read-only, fire-and-forget. */
|
|
1783
|
+
AGENT_AFTER_SWITCH: "agent:afterSwitch",
|
|
1784
|
+
// --- Turn boundaries ---
|
|
1785
|
+
/** Turn started — read-only, fire-and-forget. */
|
|
1786
|
+
TURN_START: "turn:start",
|
|
1787
|
+
/** Turn ended (always fires, even on error) — read-only, fire-and-forget. */
|
|
1788
|
+
TURN_END: "turn:end",
|
|
1789
|
+
// --- Session lifecycle ---
|
|
1790
|
+
/** Before a new session is created — modifiable, can block. */
|
|
1791
|
+
SESSION_BEFORE_CREATE: "session:beforeCreate",
|
|
1792
|
+
/** After a session is destroyed — read-only, fire-and-forget. */
|
|
1793
|
+
SESSION_AFTER_DESTROY: "session:afterDestroy",
|
|
1794
|
+
// --- Permissions ---
|
|
1795
|
+
/** Before a permission request is shown to the user — modifiable, can block. */
|
|
1796
|
+
PERMISSION_BEFORE_REQUEST: "permission:beforeRequest",
|
|
1797
|
+
/** After a permission request is resolved — read-only, fire-and-forget. */
|
|
1798
|
+
PERMISSION_AFTER_RESOLVE: "permission:afterResolve",
|
|
1799
|
+
// --- Config ---
|
|
1800
|
+
/** Before config options change — modifiable, can block. */
|
|
1801
|
+
CONFIG_BEFORE_CHANGE: "config:beforeChange",
|
|
1802
|
+
// --- Filesystem (agent-level) ---
|
|
1803
|
+
/** Before a file read operation — modifiable. */
|
|
1804
|
+
FS_BEFORE_READ: "fs:beforeRead",
|
|
1805
|
+
/** Before a file write operation — modifiable. */
|
|
1806
|
+
FS_BEFORE_WRITE: "fs:beforeWrite",
|
|
1807
|
+
// --- Terminal ---
|
|
1808
|
+
/** Before a terminal session is created — modifiable, can block. */
|
|
1809
|
+
TERMINAL_BEFORE_CREATE: "terminal:beforeCreate",
|
|
1810
|
+
/** After a terminal session exits — read-only, fire-and-forget. */
|
|
1811
|
+
TERMINAL_AFTER_EXIT: "terminal:afterExit"
|
|
1812
|
+
};
|
|
1813
|
+
BusEvent = {
|
|
1814
|
+
// --- Session lifecycle ---
|
|
1815
|
+
SESSION_CREATED: "session:created",
|
|
1816
|
+
SESSION_UPDATED: "session:updated",
|
|
1817
|
+
SESSION_DELETED: "session:deleted",
|
|
1818
|
+
SESSION_ENDED: "session:ended",
|
|
1819
|
+
SESSION_NAMED: "session:named",
|
|
1820
|
+
SESSION_THREAD_READY: "session:threadReady",
|
|
1821
|
+
SESSION_CONFIG_CHANGED: "session:configChanged",
|
|
1822
|
+
SESSION_AGENT_SWITCH: "session:agentSwitch",
|
|
1823
|
+
// --- Agent ---
|
|
1824
|
+
AGENT_EVENT: "agent:event",
|
|
1825
|
+
AGENT_PROMPT: "agent:prompt",
|
|
1826
|
+
// --- Permissions ---
|
|
1827
|
+
PERMISSION_REQUEST: "permission:request",
|
|
1828
|
+
PERMISSION_RESOLVED: "permission:resolved",
|
|
1829
|
+
// --- Message visibility ---
|
|
1830
|
+
MESSAGE_QUEUED: "message:queued",
|
|
1831
|
+
MESSAGE_PROCESSING: "message:processing",
|
|
1832
|
+
// --- System lifecycle ---
|
|
1833
|
+
KERNEL_BOOTED: "kernel:booted",
|
|
1834
|
+
SYSTEM_READY: "system:ready",
|
|
1835
|
+
SYSTEM_SHUTDOWN: "system:shutdown",
|
|
1836
|
+
SYSTEM_COMMANDS_READY: "system:commands-ready",
|
|
1837
|
+
// --- Plugin lifecycle ---
|
|
1838
|
+
PLUGIN_LOADED: "plugin:loaded",
|
|
1839
|
+
PLUGIN_FAILED: "plugin:failed",
|
|
1840
|
+
PLUGIN_DISABLED: "plugin:disabled",
|
|
1841
|
+
PLUGIN_UNLOADED: "plugin:unloaded",
|
|
1842
|
+
// --- Usage ---
|
|
1843
|
+
USAGE_RECORDED: "usage:recorded"
|
|
1844
|
+
};
|
|
1845
|
+
SessionEv = {
|
|
1846
|
+
AGENT_EVENT: "agent_event",
|
|
1847
|
+
PERMISSION_REQUEST: "permission_request",
|
|
1848
|
+
SESSION_END: "session_end",
|
|
1849
|
+
STATUS_CHANGE: "status_change",
|
|
1850
|
+
NAMED: "named",
|
|
1851
|
+
ERROR: "error",
|
|
1852
|
+
PROMPT_COUNT_CHANGED: "prompt_count_changed",
|
|
1853
|
+
TURN_STARTED: "turn_started"
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1760
1858
|
// src/plugins/security/index.ts
|
|
1761
1859
|
var security_exports = {};
|
|
1762
1860
|
__export(security_exports, {
|
|
@@ -1855,7 +1953,7 @@ function createSecurityPlugin() {
|
|
|
1855
1953
|
};
|
|
1856
1954
|
};
|
|
1857
1955
|
const guard = new SecurityGuard(getSecurityConfig, core.sessionManager);
|
|
1858
|
-
ctx.registerMiddleware(
|
|
1956
|
+
ctx.registerMiddleware(Hook.MESSAGE_INCOMING, {
|
|
1859
1957
|
handler: async (payload, next) => {
|
|
1860
1958
|
const access2 = await guard.checkAccess(payload);
|
|
1861
1959
|
if (!access2.allowed) {
|
|
@@ -1875,6 +1973,7 @@ var init_security = __esm({
|
|
|
1875
1973
|
"src/plugins/security/index.ts"() {
|
|
1876
1974
|
"use strict";
|
|
1877
1975
|
init_security_guard();
|
|
1976
|
+
init_events();
|
|
1878
1977
|
security_default = createSecurityPlugin();
|
|
1879
1978
|
}
|
|
1880
1979
|
});
|
|
@@ -3427,7 +3526,7 @@ var init_history_recorder = __esm({
|
|
|
3427
3526
|
}
|
|
3428
3527
|
states = /* @__PURE__ */ new Map();
|
|
3429
3528
|
debounceTimers = /* @__PURE__ */ new Map();
|
|
3430
|
-
onBeforePrompt(sessionId, text6, attachments) {
|
|
3529
|
+
onBeforePrompt(sessionId, text6, attachments, sourceAdapterId) {
|
|
3431
3530
|
let state = this.states.get(sessionId);
|
|
3432
3531
|
if (!state) {
|
|
3433
3532
|
state = {
|
|
@@ -3445,6 +3544,9 @@ var init_history_recorder = __esm({
|
|
|
3445
3544
|
if (attachments && attachments.length > 0) {
|
|
3446
3545
|
userTurn.attachments = attachments.map(toHistoryAttachment);
|
|
3447
3546
|
}
|
|
3547
|
+
if (sourceAdapterId) {
|
|
3548
|
+
userTurn.sourceAdapterId = sourceAdapterId;
|
|
3549
|
+
}
|
|
3448
3550
|
state.history.turns.push(userTurn);
|
|
3449
3551
|
const assistantTurn = {
|
|
3450
3552
|
index: state.history.turns.length,
|
|
@@ -3729,6 +3831,7 @@ var init_context = __esm({
|
|
|
3729
3831
|
init_history_provider();
|
|
3730
3832
|
init_history_recorder();
|
|
3731
3833
|
init_history_store();
|
|
3834
|
+
init_events();
|
|
3732
3835
|
contextPlugin = {
|
|
3733
3836
|
name: "@openacp/context",
|
|
3734
3837
|
version: "1.0.0",
|
|
@@ -3772,35 +3875,35 @@ var init_context = __esm({
|
|
|
3772
3875
|
manager.setHistoryStore(store);
|
|
3773
3876
|
manager.registerFlusher((sessionId) => recorder.flush(sessionId));
|
|
3774
3877
|
ctx.registerService("context", manager);
|
|
3775
|
-
ctx.registerMiddleware(
|
|
3878
|
+
ctx.registerMiddleware(Hook.AGENT_BEFORE_PROMPT, {
|
|
3776
3879
|
priority: 200,
|
|
3777
3880
|
handler: async (payload, next) => {
|
|
3778
|
-
recorder.onBeforePrompt(payload.sessionId, payload.text, payload.attachments);
|
|
3881
|
+
recorder.onBeforePrompt(payload.sessionId, payload.text, payload.attachments, payload.sourceAdapterId);
|
|
3779
3882
|
return next();
|
|
3780
3883
|
}
|
|
3781
3884
|
});
|
|
3782
|
-
ctx.registerMiddleware(
|
|
3885
|
+
ctx.registerMiddleware(Hook.AGENT_AFTER_EVENT, {
|
|
3783
3886
|
priority: 200,
|
|
3784
3887
|
handler: async (payload, next) => {
|
|
3785
3888
|
recorder.onAfterEvent(payload.sessionId, payload.event);
|
|
3786
3889
|
return next();
|
|
3787
3890
|
}
|
|
3788
3891
|
});
|
|
3789
|
-
ctx.registerMiddleware(
|
|
3892
|
+
ctx.registerMiddleware(Hook.TURN_END, {
|
|
3790
3893
|
priority: 200,
|
|
3791
3894
|
handler: async (payload, next) => {
|
|
3792
3895
|
await recorder.onTurnEnd(payload.sessionId, payload.stopReason);
|
|
3793
3896
|
return next();
|
|
3794
3897
|
}
|
|
3795
3898
|
});
|
|
3796
|
-
ctx.registerMiddleware(
|
|
3899
|
+
ctx.registerMiddleware(Hook.PERMISSION_AFTER_RESOLVE, {
|
|
3797
3900
|
priority: 200,
|
|
3798
3901
|
handler: async (payload, next) => {
|
|
3799
3902
|
recorder.onPermissionResolved(payload.sessionId, payload.requestId, payload.decision);
|
|
3800
3903
|
return next();
|
|
3801
3904
|
}
|
|
3802
3905
|
});
|
|
3803
|
-
ctx.registerMiddleware(
|
|
3906
|
+
ctx.registerMiddleware(Hook.SESSION_AFTER_DESTROY, {
|
|
3804
3907
|
priority: 200,
|
|
3805
3908
|
handler: async (payload, next) => {
|
|
3806
3909
|
await recorder.onSessionDestroy(payload.sessionId);
|
|
@@ -7886,6 +7989,7 @@ var MAX_SSE_CONNECTIONS, SSEManager;
|
|
|
7886
7989
|
var init_sse_manager = __esm({
|
|
7887
7990
|
"src/plugins/api-server/sse-manager.ts"() {
|
|
7888
7991
|
"use strict";
|
|
7992
|
+
init_events();
|
|
7889
7993
|
MAX_SSE_CONNECTIONS = 50;
|
|
7890
7994
|
SSEManager = class {
|
|
7891
7995
|
constructor(eventBus, getSessionStats, startedAt) {
|
|
@@ -7900,14 +8004,14 @@ var init_sse_manager = __esm({
|
|
|
7900
8004
|
setup() {
|
|
7901
8005
|
if (!this.eventBus) return;
|
|
7902
8006
|
const events = [
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
8007
|
+
BusEvent.SESSION_CREATED,
|
|
8008
|
+
BusEvent.SESSION_UPDATED,
|
|
8009
|
+
BusEvent.SESSION_DELETED,
|
|
8010
|
+
BusEvent.AGENT_EVENT,
|
|
8011
|
+
BusEvent.PERMISSION_REQUEST,
|
|
8012
|
+
BusEvent.PERMISSION_RESOLVED,
|
|
8013
|
+
BusEvent.MESSAGE_QUEUED,
|
|
8014
|
+
BusEvent.MESSAGE_PROCESSING
|
|
7911
8015
|
];
|
|
7912
8016
|
for (const eventName of events) {
|
|
7913
8017
|
const handler = (data) => {
|
|
@@ -7970,12 +8074,12 @@ data: ${JSON.stringify(data)}
|
|
|
7970
8074
|
|
|
7971
8075
|
`;
|
|
7972
8076
|
const sessionEvents = [
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
8077
|
+
BusEvent.AGENT_EVENT,
|
|
8078
|
+
BusEvent.PERMISSION_REQUEST,
|
|
8079
|
+
BusEvent.PERMISSION_RESOLVED,
|
|
8080
|
+
BusEvent.SESSION_UPDATED,
|
|
8081
|
+
BusEvent.MESSAGE_QUEUED,
|
|
8082
|
+
BusEvent.MESSAGE_PROCESSING
|
|
7979
8083
|
];
|
|
7980
8084
|
for (const res of this.sseConnections) {
|
|
7981
8085
|
const filter = res.sessionFilter;
|
|
@@ -8167,10 +8271,7 @@ var init_sessions = __esm({
|
|
|
8167
8271
|
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
8168
8272
|
offset: z.coerce.number().int().min(0).default(0)
|
|
8169
8273
|
});
|
|
8170
|
-
WorkspaceNameSchema = z.string().optional()
|
|
8171
|
-
(v) => v === void 0 || !v.startsWith("/") && !v.startsWith("~"),
|
|
8172
|
-
{ message: "workspace must be a relative name, not an absolute path" }
|
|
8173
|
-
);
|
|
8274
|
+
WorkspaceNameSchema = z.string().optional();
|
|
8174
8275
|
CreateSessionBodySchema = z.object({
|
|
8175
8276
|
agent: z.string().max(200).optional(),
|
|
8176
8277
|
workspace: WorkspaceNameSchema,
|
|
@@ -8185,7 +8286,7 @@ var init_sessions = __esm({
|
|
|
8185
8286
|
channel: z.string().max(200).optional()
|
|
8186
8287
|
});
|
|
8187
8288
|
AttachmentInputSchema = z.object({
|
|
8188
|
-
fileName: z.string().
|
|
8289
|
+
fileName: z.string().min(1).max(255),
|
|
8189
8290
|
mimeType: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9!#$&\-^_]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-^_.+]*$/, "mimeType must be a valid MIME type").max(200),
|
|
8190
8291
|
data: z.string().max(15e6)
|
|
8191
8292
|
// ~10 MB base64 ≈ 13.3 MB string
|
|
@@ -8317,15 +8418,22 @@ async function sessionRoutes(app, deps) {
|
|
|
8317
8418
|
const channelId = adapterId ?? "api";
|
|
8318
8419
|
const resolvedAgent = body.agent || deps.core.configManager.get().defaultAgent;
|
|
8319
8420
|
const agentDef = deps.core.agentCatalog.resolve(resolvedAgent);
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8421
|
+
let resolvedWorkspace;
|
|
8422
|
+
try {
|
|
8423
|
+
resolvedWorkspace = deps.core.configManager.resolveWorkspace(
|
|
8424
|
+
body.workspace || agentDef?.workingDirectory
|
|
8425
|
+
);
|
|
8426
|
+
} catch (err) {
|
|
8427
|
+
throw new BadRequestError(
|
|
8428
|
+
"INVALID_WORKSPACE",
|
|
8429
|
+
err instanceof Error ? err.message : "Invalid workspace path"
|
|
8430
|
+
);
|
|
8431
|
+
}
|
|
8323
8432
|
const session = await deps.core.createSession({
|
|
8324
8433
|
channelId,
|
|
8325
8434
|
agentName: resolvedAgent,
|
|
8326
8435
|
workingDirectory: resolvedWorkspace,
|
|
8327
|
-
createThread: !!adapter
|
|
8328
|
-
initialName: `\u{1F504} ${resolvedAgent} \u2014 New Session`
|
|
8436
|
+
createThread: !!adapter
|
|
8329
8437
|
});
|
|
8330
8438
|
return {
|
|
8331
8439
|
sessionId: session.id,
|
|
@@ -8833,6 +8941,7 @@ var init_config2 = __esm({
|
|
|
8833
8941
|
defaultAgent: z4.string(),
|
|
8834
8942
|
workspace: z4.object({
|
|
8835
8943
|
baseDir: z4.string().default("~/openacp-workspace"),
|
|
8944
|
+
allowExternalWorkspaces: z4.boolean().default(true),
|
|
8836
8945
|
security: z4.object({
|
|
8837
8946
|
allowedPaths: z4.array(z4.string()).default([]),
|
|
8838
8947
|
envWhitelist: z4.array(z4.string()).default([])
|
|
@@ -8953,13 +9062,22 @@ var init_config2 = __esm({
|
|
|
8953
9062
|
if (input2.startsWith("/") || input2.startsWith("~")) {
|
|
8954
9063
|
const resolved2 = expandHome3(input2);
|
|
8955
9064
|
const base = expandHome3(this.config.workspace.baseDir);
|
|
8956
|
-
|
|
8957
|
-
|
|
9065
|
+
const isInternal = resolved2 === base || resolved2.startsWith(base + path26.sep);
|
|
9066
|
+
if (!isInternal) {
|
|
9067
|
+
if (!this.config.workspace.allowExternalWorkspaces) {
|
|
9068
|
+
throw new Error(
|
|
9069
|
+
`Workspace path "${input2}" is outside base directory "${this.config.workspace.baseDir}". Set allowExternalWorkspaces: true to allow this.`
|
|
9070
|
+
);
|
|
9071
|
+
}
|
|
9072
|
+
if (!fs22.existsSync(resolved2)) {
|
|
9073
|
+
throw new Error(
|
|
9074
|
+
`Workspace path "${input2}" does not exist.`
|
|
9075
|
+
);
|
|
9076
|
+
}
|
|
8958
9077
|
return resolved2;
|
|
8959
9078
|
}
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
);
|
|
9079
|
+
fs22.mkdirSync(resolved2, { recursive: true });
|
|
9080
|
+
return resolved2;
|
|
8963
9081
|
}
|
|
8964
9082
|
const name = input2.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
8965
9083
|
if (name !== input2) {
|
|
@@ -10183,7 +10301,7 @@ function createApiServerPlugin() {
|
|
|
10183
10301
|
);
|
|
10184
10302
|
ctx.registerService("api-server", apiService);
|
|
10185
10303
|
cleanupInterval = setInterval(() => tokenStore.cleanup(), 60 * 60 * 1e3);
|
|
10186
|
-
ctx.on(
|
|
10304
|
+
ctx.on(BusEvent.SYSTEM_READY, async () => {
|
|
10187
10305
|
log15.info(
|
|
10188
10306
|
{ configPort: apiConfig.port, configHost: apiConfig.host },
|
|
10189
10307
|
"API server starting..."
|
|
@@ -10235,6 +10353,7 @@ var log15, cachedVersion, api_server_default;
|
|
|
10235
10353
|
var init_api_server = __esm({
|
|
10236
10354
|
"src/plugins/api-server/index.ts"() {
|
|
10237
10355
|
"use strict";
|
|
10356
|
+
init_events();
|
|
10238
10357
|
init_log();
|
|
10239
10358
|
log15 = createChildLogger({ module: "api-server" });
|
|
10240
10359
|
api_server_default = createApiServerPlugin();
|
|
@@ -10679,6 +10798,7 @@ var init_sse_adapter = __esm({
|
|
|
10679
10798
|
init_event_buffer();
|
|
10680
10799
|
init_adapter();
|
|
10681
10800
|
init_routes();
|
|
10801
|
+
init_events();
|
|
10682
10802
|
_adapter = null;
|
|
10683
10803
|
_connectionManager = null;
|
|
10684
10804
|
plugin = {
|
|
@@ -10705,11 +10825,11 @@ var init_sse_adapter = __esm({
|
|
|
10705
10825
|
_connectionManager = connectionManager;
|
|
10706
10826
|
ctx.registerService("adapter:sse", adapter);
|
|
10707
10827
|
const commandRegistry = ctx.getService("command-registry");
|
|
10708
|
-
ctx.on(
|
|
10828
|
+
ctx.on(BusEvent.SESSION_DELETED, (data) => {
|
|
10709
10829
|
const { sessionId } = data;
|
|
10710
10830
|
eventBuffer.cleanup(sessionId);
|
|
10711
10831
|
});
|
|
10712
|
-
ctx.on(
|
|
10832
|
+
ctx.on(BusEvent.SESSION_ENDED, (data) => {
|
|
10713
10833
|
const { sessionId } = data;
|
|
10714
10834
|
eventBuffer.cleanup(sessionId);
|
|
10715
10835
|
});
|
|
@@ -12968,7 +13088,6 @@ var menu_exports = {};
|
|
|
12968
13088
|
__export(menu_exports, {
|
|
12969
13089
|
buildMenuKeyboard: () => buildMenuKeyboard,
|
|
12970
13090
|
buildSkillMessages: () => buildSkillMessages,
|
|
12971
|
-
handleClear: () => handleClear,
|
|
12972
13091
|
handleHelp: () => handleHelp,
|
|
12973
13092
|
handleMenu: () => handleMenu
|
|
12974
13093
|
});
|
|
@@ -13029,31 +13148,11 @@ Each session gets its own topic \u2014 chat there to work with the agent.
|
|
|
13029
13148
|
/bypass_permissions \u2014 Toggle bypass permissions
|
|
13030
13149
|
/handoff \u2014 Continue session in terminal
|
|
13031
13150
|
/archive \u2014 Archive session topic
|
|
13032
|
-
/clear \u2014 Clear assistant history
|
|
13033
13151
|
|
|
13034
13152
|
\u{1F4AC} Need help? Just ask me in this topic!`,
|
|
13035
13153
|
{ parse_mode: "HTML" }
|
|
13036
13154
|
);
|
|
13037
13155
|
}
|
|
13038
|
-
async function handleClear(ctx, assistant) {
|
|
13039
|
-
if (!assistant) {
|
|
13040
|
-
await ctx.reply("\u26A0\uFE0F Assistant is not available.", { parse_mode: "HTML" });
|
|
13041
|
-
return;
|
|
13042
|
-
}
|
|
13043
|
-
const threadId = ctx.message?.message_thread_id;
|
|
13044
|
-
if (threadId !== assistant.topicId) {
|
|
13045
|
-
await ctx.reply("\u2139\uFE0F /clear only works in the Assistant topic.", { parse_mode: "HTML" });
|
|
13046
|
-
return;
|
|
13047
|
-
}
|
|
13048
|
-
await ctx.reply("\u{1F504} Clearing assistant history...", { parse_mode: "HTML" });
|
|
13049
|
-
try {
|
|
13050
|
-
await assistant.respawn();
|
|
13051
|
-
await ctx.reply("\u2705 Assistant history cleared.", { parse_mode: "HTML" });
|
|
13052
|
-
} catch (err) {
|
|
13053
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
13054
|
-
await ctx.reply(`\u274C Failed to clear: <code>${message}</code>`, { parse_mode: "HTML" });
|
|
13055
|
-
}
|
|
13056
|
-
}
|
|
13057
13156
|
function buildSkillMessages(commands) {
|
|
13058
13157
|
const sorted = [...commands].sort((a, b) => a.name.localeCompare(b.name));
|
|
13059
13158
|
const header2 = "\u{1F6E0} <b>Available Skills</b>\n";
|
|
@@ -14578,7 +14677,10 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
14578
14677
|
const menuRegistry = core.lifecycleManager?.serviceRegistry?.get("menu-registry");
|
|
14579
14678
|
if (!menuRegistry) return;
|
|
14580
14679
|
const item = menuRegistry.getItem(itemId);
|
|
14581
|
-
if (!item)
|
|
14680
|
+
if (!item) {
|
|
14681
|
+
log25.warn({ itemId }, "Menu item not found in registry");
|
|
14682
|
+
return;
|
|
14683
|
+
}
|
|
14582
14684
|
const topicId = ctx.callbackQuery.message?.message_thread_id;
|
|
14583
14685
|
const registry = core.lifecycleManager?.serviceRegistry?.get("command-registry");
|
|
14584
14686
|
switch (item.action.type) {
|
|
@@ -14662,7 +14764,7 @@ ${lines}`, { parse_mode: "HTML" }).catch(() => {
|
|
|
14662
14764
|
}
|
|
14663
14765
|
});
|
|
14664
14766
|
}
|
|
14665
|
-
var STATIC_COMMANDS;
|
|
14767
|
+
var log25, STATIC_COMMANDS;
|
|
14666
14768
|
var init_commands3 = __esm({
|
|
14667
14769
|
"src/plugins/telegram/commands/index.ts"() {
|
|
14668
14770
|
"use strict";
|
|
@@ -14675,6 +14777,7 @@ var init_commands3 = __esm({
|
|
|
14675
14777
|
init_tunnel4();
|
|
14676
14778
|
init_switch();
|
|
14677
14779
|
init_telegram_overrides();
|
|
14780
|
+
init_log();
|
|
14678
14781
|
init_menu();
|
|
14679
14782
|
init_menu();
|
|
14680
14783
|
init_telegram_overrides();
|
|
@@ -14686,6 +14789,7 @@ var init_commands3 = __esm({
|
|
|
14686
14789
|
init_settings();
|
|
14687
14790
|
init_doctor2();
|
|
14688
14791
|
init_resume();
|
|
14792
|
+
log25 = createChildLogger({ module: "telegram-menu-callbacks" });
|
|
14689
14793
|
STATIC_COMMANDS = [
|
|
14690
14794
|
{ command: "new", description: "Create new session" },
|
|
14691
14795
|
{ command: "newchat", description: "New chat, same agent & workspace" },
|
|
@@ -14698,7 +14802,6 @@ var init_commands3 = __esm({
|
|
|
14698
14802
|
{ command: "menu", description: "Show menu" },
|
|
14699
14803
|
{ command: "integrate", description: "Manage agent integrations" },
|
|
14700
14804
|
{ command: "handoff", description: "Continue this session in your terminal" },
|
|
14701
|
-
{ command: "clear", description: "Clear assistant history" },
|
|
14702
14805
|
{ command: "restart", description: "Restart OpenACP" },
|
|
14703
14806
|
{ command: "update", description: "Update to latest version and restart" },
|
|
14704
14807
|
{ command: "doctor", description: "Run system diagnostics" },
|
|
@@ -14721,14 +14824,14 @@ var init_commands3 = __esm({
|
|
|
14721
14824
|
// src/plugins/telegram/permissions.ts
|
|
14722
14825
|
import { InlineKeyboard as InlineKeyboard11 } from "grammy";
|
|
14723
14826
|
import { nanoid as nanoid2 } from "nanoid";
|
|
14724
|
-
var
|
|
14827
|
+
var log26, PermissionHandler;
|
|
14725
14828
|
var init_permissions = __esm({
|
|
14726
14829
|
"src/plugins/telegram/permissions.ts"() {
|
|
14727
14830
|
"use strict";
|
|
14728
14831
|
init_formatting();
|
|
14729
14832
|
init_topics2();
|
|
14730
14833
|
init_log();
|
|
14731
|
-
|
|
14834
|
+
log26 = createChildLogger({ module: "telegram-permissions" });
|
|
14732
14835
|
PermissionHandler = class {
|
|
14733
14836
|
constructor(bot, chatId, getSession, sendNotification) {
|
|
14734
14837
|
this.bot = bot;
|
|
@@ -14772,11 +14875,11 @@ ${escapeHtml4(request.description)}`,
|
|
|
14772
14875
|
});
|
|
14773
14876
|
}
|
|
14774
14877
|
setupCallbackHandler() {
|
|
14775
|
-
this.bot.on("callback_query:data", async (ctx) => {
|
|
14878
|
+
this.bot.on("callback_query:data", async (ctx, next) => {
|
|
14776
14879
|
const data = ctx.callbackQuery.data;
|
|
14777
|
-
if (!data.startsWith("p:")) return;
|
|
14880
|
+
if (!data.startsWith("p:")) return next();
|
|
14778
14881
|
const parts = data.split(":");
|
|
14779
|
-
if (parts.length < 3) return;
|
|
14882
|
+
if (parts.length < 3) return next();
|
|
14780
14883
|
const [, callbackKey, optionId] = parts;
|
|
14781
14884
|
const pending = this.pending.get(callbackKey);
|
|
14782
14885
|
if (!pending) {
|
|
@@ -14788,7 +14891,7 @@ ${escapeHtml4(request.description)}`,
|
|
|
14788
14891
|
}
|
|
14789
14892
|
const session = this.getSession(pending.sessionId);
|
|
14790
14893
|
const isAllow = pending.options.find((o) => o.id === optionId)?.isAllow ?? false;
|
|
14791
|
-
|
|
14894
|
+
log26.info({ requestId: pending.requestId, optionId, isAllow }, "Permission responded");
|
|
14792
14895
|
if (session?.permissionGate.requestId === pending.requestId) {
|
|
14793
14896
|
session.permissionGate.resolve(optionId);
|
|
14794
14897
|
}
|
|
@@ -15242,7 +15345,7 @@ var init_display_spec_builder = __esm({
|
|
|
15242
15345
|
});
|
|
15243
15346
|
|
|
15244
15347
|
// src/plugins/telegram/activity.ts
|
|
15245
|
-
var
|
|
15348
|
+
var log27, THINKING_REFRESH_MS, THINKING_MAX_MS, ThinkingIndicator, ToolCard, ActivityTracker;
|
|
15246
15349
|
var init_activity = __esm({
|
|
15247
15350
|
"src/plugins/telegram/activity.ts"() {
|
|
15248
15351
|
"use strict";
|
|
@@ -15252,7 +15355,7 @@ var init_activity = __esm({
|
|
|
15252
15355
|
init_stream_accumulator();
|
|
15253
15356
|
init_stream_accumulator();
|
|
15254
15357
|
init_display_spec_builder();
|
|
15255
|
-
|
|
15358
|
+
log27 = createChildLogger({ module: "telegram:activity" });
|
|
15256
15359
|
THINKING_REFRESH_MS = 15e3;
|
|
15257
15360
|
THINKING_MAX_MS = 3 * 60 * 1e3;
|
|
15258
15361
|
ThinkingIndicator = class {
|
|
@@ -15293,7 +15396,7 @@ var init_activity = __esm({
|
|
|
15293
15396
|
}
|
|
15294
15397
|
}
|
|
15295
15398
|
} catch (err) {
|
|
15296
|
-
|
|
15399
|
+
log27.warn({ err }, "ThinkingIndicator.show() failed");
|
|
15297
15400
|
} finally {
|
|
15298
15401
|
this.sending = false;
|
|
15299
15402
|
}
|
|
@@ -15461,7 +15564,7 @@ var init_activity = __esm({
|
|
|
15461
15564
|
this.tracer?.log("telegram", { action: "telegram:delete:overflow", sessionId: this.sessionId, msgId: staleId });
|
|
15462
15565
|
}
|
|
15463
15566
|
} catch (err) {
|
|
15464
|
-
|
|
15567
|
+
log27.warn({ err }, "[ToolCard] send/edit failed");
|
|
15465
15568
|
}
|
|
15466
15569
|
}
|
|
15467
15570
|
};
|
|
@@ -15565,7 +15668,7 @@ var init_activity = __esm({
|
|
|
15565
15668
|
const entry = this.toolStateMap.merge(id, status, rawInput, content, viewerLinks, diffStats);
|
|
15566
15669
|
if (!existed || !entry) return;
|
|
15567
15670
|
if (viewerLinks || entry.viewerLinks) {
|
|
15568
|
-
|
|
15671
|
+
log27.debug({ toolId: id, status, hasIncomingLinks: !!viewerLinks, hasEntryLinks: !!entry.viewerLinks, entryLinks: entry.viewerLinks }, "toolUpdate: viewer links trace");
|
|
15569
15672
|
}
|
|
15570
15673
|
const spec = this.specBuilder.buildToolSpec(entry, this._outputMode, this.sessionContext);
|
|
15571
15674
|
this.toolCard.updateFromSpec(spec);
|
|
@@ -15992,13 +16095,13 @@ var init_draft_manager = __esm({
|
|
|
15992
16095
|
});
|
|
15993
16096
|
|
|
15994
16097
|
// src/plugins/telegram/skill-command-manager.ts
|
|
15995
|
-
var
|
|
16098
|
+
var log28, SkillCommandManager;
|
|
15996
16099
|
var init_skill_command_manager = __esm({
|
|
15997
16100
|
"src/plugins/telegram/skill-command-manager.ts"() {
|
|
15998
16101
|
"use strict";
|
|
15999
16102
|
init_commands3();
|
|
16000
16103
|
init_log();
|
|
16001
|
-
|
|
16104
|
+
log28 = createChildLogger({ module: "skill-commands" });
|
|
16002
16105
|
SkillCommandManager = class {
|
|
16003
16106
|
// sessionId → pinned msgId
|
|
16004
16107
|
constructor(bot, chatId, sendQueue, sessionManager) {
|
|
@@ -16064,7 +16167,7 @@ var init_skill_command_manager = __esm({
|
|
|
16064
16167
|
disable_notification: true
|
|
16065
16168
|
});
|
|
16066
16169
|
} catch (err) {
|
|
16067
|
-
|
|
16170
|
+
log28.error({ err, sessionId }, "Failed to send skill commands");
|
|
16068
16171
|
}
|
|
16069
16172
|
}
|
|
16070
16173
|
async cleanup(sessionId) {
|
|
@@ -16458,10 +16561,11 @@ function patchedFetch(input2, init) {
|
|
|
16458
16561
|
}
|
|
16459
16562
|
return fetch(input2, init);
|
|
16460
16563
|
}
|
|
16461
|
-
var
|
|
16564
|
+
var log29, TelegramAdapter;
|
|
16462
16565
|
var init_adapter2 = __esm({
|
|
16463
16566
|
"src/plugins/telegram/adapter.ts"() {
|
|
16464
16567
|
"use strict";
|
|
16568
|
+
init_events();
|
|
16465
16569
|
init_log();
|
|
16466
16570
|
init_topics2();
|
|
16467
16571
|
init_commands3();
|
|
@@ -16477,7 +16581,7 @@ var init_adapter2 = __esm({
|
|
|
16477
16581
|
init_messaging_adapter();
|
|
16478
16582
|
init_renderer2();
|
|
16479
16583
|
init_output_mode_resolver();
|
|
16480
|
-
|
|
16584
|
+
log29 = createChildLogger({ module: "telegram" });
|
|
16481
16585
|
TelegramAdapter = class extends MessagingAdapter {
|
|
16482
16586
|
name = "telegram";
|
|
16483
16587
|
renderer = new TelegramRenderer();
|
|
@@ -16604,7 +16708,7 @@ var init_adapter2 = __esm({
|
|
|
16604
16708
|
);
|
|
16605
16709
|
this.bot.catch((err) => {
|
|
16606
16710
|
const rootCause = err.error instanceof Error ? err.error : err;
|
|
16607
|
-
|
|
16711
|
+
log29.error({ err: rootCause }, "Telegram bot error");
|
|
16608
16712
|
});
|
|
16609
16713
|
this.bot.api.config.use(async (prev, method, payload, signal) => {
|
|
16610
16714
|
const maxRetries = 3;
|
|
@@ -16622,7 +16726,7 @@ var init_adapter2 = __esm({
|
|
|
16622
16726
|
if (rateLimitedMethods.includes(method)) {
|
|
16623
16727
|
this.sendQueue.onRateLimited();
|
|
16624
16728
|
}
|
|
16625
|
-
|
|
16729
|
+
log29.warn(
|
|
16626
16730
|
{ method, retryAfter, attempt: attempt + 1 },
|
|
16627
16731
|
"Rate limited by Telegram, retrying"
|
|
16628
16732
|
);
|
|
@@ -16810,9 +16914,9 @@ ${p2}` : p2;
|
|
|
16810
16914
|
this.setupRoutes();
|
|
16811
16915
|
this.bot.start({
|
|
16812
16916
|
allowed_updates: ["message", "callback_query"],
|
|
16813
|
-
onStart: () =>
|
|
16917
|
+
onStart: () => log29.info({ chatId: this.telegramConfig.chatId }, "Telegram bot started")
|
|
16814
16918
|
});
|
|
16815
|
-
|
|
16919
|
+
log29.info(
|
|
16816
16920
|
{
|
|
16817
16921
|
chatId: this.telegramConfig.chatId,
|
|
16818
16922
|
notificationTopicId: this.telegramConfig.notificationTopicId,
|
|
@@ -16826,12 +16930,12 @@ ${p2}` : p2;
|
|
|
16826
16930
|
this.telegramConfig.chatId
|
|
16827
16931
|
);
|
|
16828
16932
|
if (prereqResult.ok) {
|
|
16829
|
-
|
|
16933
|
+
log29.info("Telegram adapter: prerequisites OK, initializing topic-dependent features");
|
|
16830
16934
|
await this.initTopicDependentFeatures();
|
|
16831
16935
|
} else {
|
|
16832
|
-
|
|
16936
|
+
log29.warn({ issues: prereqResult.issues }, "Telegram adapter: prerequisites NOT met, starting watcher");
|
|
16833
16937
|
for (const issue of prereqResult.issues) {
|
|
16834
|
-
|
|
16938
|
+
log29.warn({ issue }, "Telegram prerequisite not met");
|
|
16835
16939
|
}
|
|
16836
16940
|
this.startPrerequisiteWatcher(prereqResult.issues);
|
|
16837
16941
|
}
|
|
@@ -16847,7 +16951,7 @@ ${p2}` : p2;
|
|
|
16847
16951
|
} catch (err) {
|
|
16848
16952
|
if (attempt === maxRetries) throw err;
|
|
16849
16953
|
const delay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
16850
|
-
|
|
16954
|
+
log29.warn(
|
|
16851
16955
|
{ err, attempt, maxRetries, delayMs: delay, operation: label },
|
|
16852
16956
|
`${label} failed, retrying in ${delay}ms`
|
|
16853
16957
|
);
|
|
@@ -16867,12 +16971,12 @@ ${p2}` : p2;
|
|
|
16867
16971
|
}),
|
|
16868
16972
|
"setMyCommands"
|
|
16869
16973
|
).catch((err) => {
|
|
16870
|
-
|
|
16974
|
+
log29.warn({ err }, "Failed to register Telegram commands after retries (non-critical)");
|
|
16871
16975
|
});
|
|
16872
16976
|
}
|
|
16873
16977
|
async initTopicDependentFeatures() {
|
|
16874
16978
|
if (this._topicsInitialized) return;
|
|
16875
|
-
|
|
16979
|
+
log29.info(
|
|
16876
16980
|
{ notificationTopicId: this.telegramConfig.notificationTopicId, assistantTopicId: this.telegramConfig.assistantTopicId },
|
|
16877
16981
|
"initTopicDependentFeatures: starting (existing IDs in config)"
|
|
16878
16982
|
);
|
|
@@ -16897,7 +17001,7 @@ ${p2}` : p2;
|
|
|
16897
17001
|
this.assistantTopicId = topics.assistantTopicId;
|
|
16898
17002
|
this._systemTopicIds.notificationTopicId = topics.notificationTopicId;
|
|
16899
17003
|
this._systemTopicIds.assistantTopicId = topics.assistantTopicId;
|
|
16900
|
-
|
|
17004
|
+
log29.info(
|
|
16901
17005
|
{ notificationTopicId: this.notificationTopicId, assistantTopicId: this.assistantTopicId },
|
|
16902
17006
|
"initTopicDependentFeatures: topics ready"
|
|
16903
17007
|
);
|
|
@@ -16928,16 +17032,16 @@ ${p2}` : p2;
|
|
|
16928
17032
|
).then((msg) => {
|
|
16929
17033
|
if (msg) this.storeControlMsgId(sessionId, msg.message_id);
|
|
16930
17034
|
}).catch((err) => {
|
|
16931
|
-
|
|
17035
|
+
log29.warn({ err, sessionId }, "Failed to send initial messages for new session");
|
|
16932
17036
|
});
|
|
16933
17037
|
};
|
|
16934
|
-
this.core.eventBus.on(
|
|
17038
|
+
this.core.eventBus.on(BusEvent.SESSION_THREAD_READY, this._threadReadyHandler);
|
|
16935
17039
|
this._configChangedHandler = ({ sessionId }) => {
|
|
16936
17040
|
this.updateControlMessage(sessionId).catch(() => {
|
|
16937
17041
|
});
|
|
16938
17042
|
};
|
|
16939
17043
|
this.core.eventBus.on("session:configChanged", this._configChangedHandler);
|
|
16940
|
-
|
|
17044
|
+
log29.info({ assistantTopicId: this.assistantTopicId }, "initTopicDependentFeatures: sending welcome message");
|
|
16941
17045
|
try {
|
|
16942
17046
|
const config = this.core.configManager.get();
|
|
16943
17047
|
const agents = this.core.agentManager.getAvailableAgents();
|
|
@@ -16959,17 +17063,17 @@ ${p2}` : p2;
|
|
|
16959
17063
|
this.core.lifecycleManager?.serviceRegistry?.get("menu-registry")
|
|
16960
17064
|
)
|
|
16961
17065
|
});
|
|
16962
|
-
|
|
17066
|
+
log29.info("initTopicDependentFeatures: welcome message sent");
|
|
16963
17067
|
} catch (err) {
|
|
16964
|
-
|
|
17068
|
+
log29.warn({ err }, "Failed to send welcome message");
|
|
16965
17069
|
}
|
|
16966
17070
|
try {
|
|
16967
|
-
await this.core.assistantManager.
|
|
17071
|
+
await this.core.assistantManager.getOrSpawn("telegram", String(this.assistantTopicId));
|
|
16968
17072
|
} catch (err) {
|
|
16969
|
-
|
|
17073
|
+
log29.error({ err }, "Failed to spawn assistant");
|
|
16970
17074
|
}
|
|
16971
17075
|
this._topicsInitialized = true;
|
|
16972
|
-
|
|
17076
|
+
log29.info("Telegram adapter fully initialized");
|
|
16973
17077
|
}
|
|
16974
17078
|
startPrerequisiteWatcher(issues) {
|
|
16975
17079
|
const setupMessage = `\u26A0\uFE0F <b>OpenACP needs setup before it can start.</b>
|
|
@@ -16980,7 +17084,7 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
16980
17084
|
this.bot.api.sendMessage(this.telegramConfig.chatId, setupMessage, {
|
|
16981
17085
|
parse_mode: "HTML"
|
|
16982
17086
|
}).catch((err) => {
|
|
16983
|
-
|
|
17087
|
+
log29.warn({ err }, "Failed to send setup guidance to General topic");
|
|
16984
17088
|
});
|
|
16985
17089
|
const schedule = [5e3, 1e4, 3e4];
|
|
16986
17090
|
let attempt = 1;
|
|
@@ -16993,7 +17097,7 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
16993
17097
|
);
|
|
16994
17098
|
if (result.ok) {
|
|
16995
17099
|
this._prerequisiteWatcher = null;
|
|
16996
|
-
|
|
17100
|
+
log29.info("Prerequisites met \u2014 completing Telegram adapter initialization");
|
|
16997
17101
|
try {
|
|
16998
17102
|
await this.initTopicDependentFeatures();
|
|
16999
17103
|
await this.bot.api.sendMessage(
|
|
@@ -17002,11 +17106,11 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
17002
17106
|
{ parse_mode: "HTML" }
|
|
17003
17107
|
);
|
|
17004
17108
|
} catch (err) {
|
|
17005
|
-
|
|
17109
|
+
log29.error({ err }, "Failed to complete initialization after prerequisites met");
|
|
17006
17110
|
}
|
|
17007
17111
|
return;
|
|
17008
17112
|
}
|
|
17009
|
-
|
|
17113
|
+
log29.debug({ issues: result.issues }, "Prerequisites not yet met, retrying");
|
|
17010
17114
|
const delay = schedule[Math.min(attempt, schedule.length - 1)];
|
|
17011
17115
|
attempt++;
|
|
17012
17116
|
this._prerequisiteWatcher = setTimeout(retry, delay);
|
|
@@ -17023,7 +17127,7 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
17023
17127
|
}
|
|
17024
17128
|
this.sessionTrackers.clear();
|
|
17025
17129
|
if (this._threadReadyHandler) {
|
|
17026
|
-
this.core.eventBus.off(
|
|
17130
|
+
this.core.eventBus.off(BusEvent.SESSION_THREAD_READY, this._threadReadyHandler);
|
|
17027
17131
|
this._threadReadyHandler = void 0;
|
|
17028
17132
|
}
|
|
17029
17133
|
if (this._configChangedHandler) {
|
|
@@ -17032,7 +17136,7 @@ OpenACP will automatically retry until this is resolved.`;
|
|
|
17032
17136
|
}
|
|
17033
17137
|
this.sendQueue.clear();
|
|
17034
17138
|
await this.bot.stop();
|
|
17035
|
-
|
|
17139
|
+
log29.info("Telegram bot stopped");
|
|
17036
17140
|
}
|
|
17037
17141
|
// --- CommandRegistry response rendering ---
|
|
17038
17142
|
async renderCommandResponse(response, chatId, topicId) {
|
|
@@ -17117,6 +17221,13 @@ ${lines.join("\n")}`;
|
|
|
17117
17221
|
}
|
|
17118
17222
|
setupRoutes() {
|
|
17119
17223
|
this.bot.on("message:text", async (ctx) => {
|
|
17224
|
+
if (!this._topicsInitialized) {
|
|
17225
|
+
await ctx.reply(
|
|
17226
|
+
"\u23F3 OpenACP is still setting up. Check the General topic for instructions."
|
|
17227
|
+
).catch(() => {
|
|
17228
|
+
});
|
|
17229
|
+
return;
|
|
17230
|
+
}
|
|
17120
17231
|
const threadId = ctx.message.message_thread_id;
|
|
17121
17232
|
const text6 = ctx.message.text;
|
|
17122
17233
|
if (!threadId) {
|
|
@@ -17149,7 +17260,7 @@ ${lines.join("\n")}`;
|
|
|
17149
17260
|
threadId: String(threadId),
|
|
17150
17261
|
userId: String(ctx.from.id),
|
|
17151
17262
|
text: forwardText
|
|
17152
|
-
}).catch((err) =>
|
|
17263
|
+
}).catch((err) => log29.error({ err }, "handleMessage error"));
|
|
17153
17264
|
});
|
|
17154
17265
|
this.bot.on("message:photo", async (ctx) => {
|
|
17155
17266
|
const threadId = ctx.message.message_thread_id;
|
|
@@ -17238,7 +17349,7 @@ ${lines.join("\n")}`;
|
|
|
17238
17349
|
if (session.archiving) return;
|
|
17239
17350
|
const threadId = Number(session.threadId);
|
|
17240
17351
|
if (!threadId || isNaN(threadId)) {
|
|
17241
|
-
|
|
17352
|
+
log29.warn(
|
|
17242
17353
|
{ sessionId, threadId: session.threadId },
|
|
17243
17354
|
"Session has no valid threadId, skipping message"
|
|
17244
17355
|
);
|
|
@@ -17254,7 +17365,7 @@ ${lines.join("\n")}`;
|
|
|
17254
17365
|
this._sessionThreadIds.delete(sessionId);
|
|
17255
17366
|
}
|
|
17256
17367
|
}).catch((err) => {
|
|
17257
|
-
|
|
17368
|
+
log29.warn({ err, sessionId }, "Dispatch queue error");
|
|
17258
17369
|
});
|
|
17259
17370
|
this._dispatchQueues.set(sessionId, next);
|
|
17260
17371
|
await next;
|
|
@@ -17376,7 +17487,7 @@ ${lines.join("\n")}`;
|
|
|
17376
17487
|
);
|
|
17377
17488
|
usageMsgId = result?.message_id;
|
|
17378
17489
|
} catch (err) {
|
|
17379
|
-
|
|
17490
|
+
log29.warn({ err, sessionId }, "Failed to send usage message");
|
|
17380
17491
|
}
|
|
17381
17492
|
if (this.notificationTopicId && sessionId !== this.core.assistantManager?.get("telegram")?.id) {
|
|
17382
17493
|
const sess = this.core.sessionManager.getSession(sessionId);
|
|
@@ -17404,7 +17515,7 @@ Task completed.
|
|
|
17404
17515
|
if (!content.attachment) return;
|
|
17405
17516
|
const { attachment } = content;
|
|
17406
17517
|
if (attachment.size > 50 * 1024 * 1024) {
|
|
17407
|
-
|
|
17518
|
+
log29.warn(
|
|
17408
17519
|
{
|
|
17409
17520
|
sessionId,
|
|
17410
17521
|
fileName: attachment.fileName,
|
|
@@ -17448,7 +17559,7 @@ Task completed.
|
|
|
17448
17559
|
);
|
|
17449
17560
|
}
|
|
17450
17561
|
} catch (err) {
|
|
17451
|
-
|
|
17562
|
+
log29.error(
|
|
17452
17563
|
{ err, sessionId, fileName: attachment.fileName },
|
|
17453
17564
|
"Failed to send attachment"
|
|
17454
17565
|
);
|
|
@@ -17547,7 +17658,7 @@ Task completed.
|
|
|
17547
17658
|
}
|
|
17548
17659
|
async sendPermissionRequest(sessionId, request) {
|
|
17549
17660
|
this.getTracer(sessionId)?.log("telegram", { action: "permission:send", sessionId, requestId: request.id, description: request.description });
|
|
17550
|
-
|
|
17661
|
+
log29.info({ sessionId, requestId: request.id }, "Permission request sent");
|
|
17551
17662
|
const session = this.core.sessionManager.getSession(sessionId);
|
|
17552
17663
|
if (!session) return;
|
|
17553
17664
|
await this.sendQueue.enqueue(
|
|
@@ -17557,7 +17668,7 @@ Task completed.
|
|
|
17557
17668
|
async sendNotification(notification) {
|
|
17558
17669
|
this.getTracer(notification.sessionId)?.log("telegram", { action: "notification:send", sessionId: notification.sessionId, type: notification.type });
|
|
17559
17670
|
if (notification.sessionId === this.core.assistantManager?.get("telegram")?.id) return;
|
|
17560
|
-
|
|
17671
|
+
log29.info(
|
|
17561
17672
|
{ sessionId: notification.sessionId, type: notification.type },
|
|
17562
17673
|
"Notification sent"
|
|
17563
17674
|
);
|
|
@@ -17596,7 +17707,7 @@ Task completed.
|
|
|
17596
17707
|
}
|
|
17597
17708
|
async createSessionThread(sessionId, name) {
|
|
17598
17709
|
this.getTracer(sessionId)?.log("telegram", { action: "thread:create", sessionId, name });
|
|
17599
|
-
|
|
17710
|
+
log29.info({ sessionId, name }, "Session topic created");
|
|
17600
17711
|
return String(
|
|
17601
17712
|
await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
|
|
17602
17713
|
);
|
|
@@ -17607,7 +17718,7 @@ Task completed.
|
|
|
17607
17718
|
if (!session) return;
|
|
17608
17719
|
const threadId = Number(session.threadId);
|
|
17609
17720
|
if (!threadId) {
|
|
17610
|
-
|
|
17721
|
+
log29.debug({ sessionId, newName }, "Cannot rename thread \u2014 threadId not set yet");
|
|
17611
17722
|
return;
|
|
17612
17723
|
}
|
|
17613
17724
|
await renameSessionTopic(
|
|
@@ -17626,7 +17737,7 @@ Task completed.
|
|
|
17626
17737
|
try {
|
|
17627
17738
|
await this.bot.api.deleteForumTopic(this.telegramConfig.chatId, topicId);
|
|
17628
17739
|
} catch (err) {
|
|
17629
|
-
|
|
17740
|
+
log29.warn(
|
|
17630
17741
|
{ err, sessionId, topicId },
|
|
17631
17742
|
"Failed to delete forum topic (may already be deleted)"
|
|
17632
17743
|
);
|
|
@@ -17670,7 +17781,7 @@ Task completed.
|
|
|
17670
17781
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
17671
17782
|
return { buffer, filePath: file.file_path };
|
|
17672
17783
|
} catch (err) {
|
|
17673
|
-
|
|
17784
|
+
log29.error({ err }, "Failed to download file from Telegram");
|
|
17674
17785
|
return null;
|
|
17675
17786
|
}
|
|
17676
17787
|
}
|
|
@@ -17691,7 +17802,7 @@ Task completed.
|
|
|
17691
17802
|
try {
|
|
17692
17803
|
buffer = await this.fileService.convertOggToWav(buffer);
|
|
17693
17804
|
} catch (err) {
|
|
17694
|
-
|
|
17805
|
+
log29.warn({ err }, "OGG\u2192WAV conversion failed, saving original OGG");
|
|
17695
17806
|
fileName = "voice.ogg";
|
|
17696
17807
|
mimeType = "audio/ogg";
|
|
17697
17808
|
originalFilePath = void 0;
|
|
@@ -17723,7 +17834,7 @@ Task completed.
|
|
|
17723
17834
|
userId: String(userId),
|
|
17724
17835
|
text: text6,
|
|
17725
17836
|
attachments: [att]
|
|
17726
|
-
}).catch((err) =>
|
|
17837
|
+
}).catch((err) => log29.error({ err }, "handleMessage error"));
|
|
17727
17838
|
}
|
|
17728
17839
|
async cleanupSkillCommands(sessionId) {
|
|
17729
17840
|
this._pendingSkillCommands.delete(sessionId);
|
|
@@ -18820,6 +18931,47 @@ var init_typed_emitter = __esm({
|
|
|
18820
18931
|
}
|
|
18821
18932
|
});
|
|
18822
18933
|
|
|
18934
|
+
// src/core/agents/attachment-blocks.ts
|
|
18935
|
+
function buildAttachmentNote(att, capabilities) {
|
|
18936
|
+
const tooLarge = att.size > MAX_ATTACHMENT_SIZE;
|
|
18937
|
+
if (tooLarge) {
|
|
18938
|
+
const sizeMB = Math.round(att.size / 1024 / 1024);
|
|
18939
|
+
return `[Attachment skipped: "${att.fileName}" is too large (${sizeMB}MB > 10MB limit)]`;
|
|
18940
|
+
}
|
|
18941
|
+
if (att.type === "image") {
|
|
18942
|
+
if (!capabilities.image) {
|
|
18943
|
+
return null;
|
|
18944
|
+
}
|
|
18945
|
+
if (!SUPPORTED_IMAGE_MIMES.has(att.mimeType)) {
|
|
18946
|
+
return `[Attachment skipped: image format not supported (${att.mimeType})]`;
|
|
18947
|
+
}
|
|
18948
|
+
return null;
|
|
18949
|
+
}
|
|
18950
|
+
if (att.type === "audio") {
|
|
18951
|
+
if (!capabilities.audio) {
|
|
18952
|
+
return null;
|
|
18953
|
+
}
|
|
18954
|
+
return null;
|
|
18955
|
+
}
|
|
18956
|
+
return null;
|
|
18957
|
+
}
|
|
18958
|
+
var SUPPORTED_IMAGE_MIMES, MAX_ATTACHMENT_SIZE;
|
|
18959
|
+
var init_attachment_blocks = __esm({
|
|
18960
|
+
"src/core/agents/attachment-blocks.ts"() {
|
|
18961
|
+
"use strict";
|
|
18962
|
+
SUPPORTED_IMAGE_MIMES = /* @__PURE__ */ new Set([
|
|
18963
|
+
"image/jpeg",
|
|
18964
|
+
"image/png",
|
|
18965
|
+
"image/gif",
|
|
18966
|
+
"image/webp",
|
|
18967
|
+
"image/avif",
|
|
18968
|
+
"image/heic",
|
|
18969
|
+
"image/heif"
|
|
18970
|
+
]);
|
|
18971
|
+
MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024;
|
|
18972
|
+
}
|
|
18973
|
+
});
|
|
18974
|
+
|
|
18823
18975
|
// src/core/sessions/terminal-manager.ts
|
|
18824
18976
|
import { spawn as spawn7 } from "child_process";
|
|
18825
18977
|
import { randomUUID } from "crypto";
|
|
@@ -18828,6 +18980,7 @@ var init_terminal_manager = __esm({
|
|
|
18828
18980
|
"src/core/sessions/terminal-manager.ts"() {
|
|
18829
18981
|
"use strict";
|
|
18830
18982
|
init_env_filter();
|
|
18983
|
+
init_events();
|
|
18831
18984
|
TerminalManager = class {
|
|
18832
18985
|
terminals = /* @__PURE__ */ new Map();
|
|
18833
18986
|
maxOutputBytes;
|
|
@@ -18844,7 +18997,7 @@ var init_terminal_manager = __esm({
|
|
|
18844
18997
|
for (const ev of termEnvArr) {
|
|
18845
18998
|
envRecord[ev.name] = ev.value;
|
|
18846
18999
|
}
|
|
18847
|
-
const result = await middlewareChain.execute(
|
|
19000
|
+
const result = await middlewareChain.execute(Hook.TERMINAL_BEFORE_CREATE, {
|
|
18848
19001
|
sessionId,
|
|
18849
19002
|
command: termCommand,
|
|
18850
19003
|
args: termArgs,
|
|
@@ -18898,7 +19051,7 @@ var init_terminal_manager = __esm({
|
|
|
18898
19051
|
childProcess.on("exit", (code, signal) => {
|
|
18899
19052
|
state.exitStatus = { exitCode: code, signal };
|
|
18900
19053
|
if (middlewareChain) {
|
|
18901
|
-
middlewareChain.execute(
|
|
19054
|
+
middlewareChain.execute(Hook.TERMINAL_AFTER_EXIT, {
|
|
18902
19055
|
sessionId,
|
|
18903
19056
|
terminalId,
|
|
18904
19057
|
command: state.command,
|
|
@@ -19102,7 +19255,7 @@ function resolveAgentCommand(cmd) {
|
|
|
19102
19255
|
}
|
|
19103
19256
|
return { command: cmd, args: [] };
|
|
19104
19257
|
}
|
|
19105
|
-
var
|
|
19258
|
+
var log31, AgentInstance;
|
|
19106
19259
|
var init_agent_instance = __esm({
|
|
19107
19260
|
"src/core/agents/agent-instance.ts"() {
|
|
19108
19261
|
"use strict";
|
|
@@ -19112,11 +19265,13 @@ var init_agent_instance = __esm({
|
|
|
19112
19265
|
init_stderr_capture();
|
|
19113
19266
|
init_typed_emitter();
|
|
19114
19267
|
init_read_text_file();
|
|
19268
|
+
init_attachment_blocks();
|
|
19115
19269
|
init_terminal_manager();
|
|
19116
19270
|
init_mcp_manager();
|
|
19117
19271
|
init_debug_tracer();
|
|
19118
19272
|
init_log();
|
|
19119
|
-
|
|
19273
|
+
init_events();
|
|
19274
|
+
log31 = createChildLogger({ module: "agent-instance" });
|
|
19120
19275
|
AgentInstance = class _AgentInstance extends TypedEmitter {
|
|
19121
19276
|
connection;
|
|
19122
19277
|
child;
|
|
@@ -19143,10 +19298,10 @@ var init_agent_instance = __esm({
|
|
|
19143
19298
|
super();
|
|
19144
19299
|
this.agentName = agentName;
|
|
19145
19300
|
}
|
|
19146
|
-
static async spawnSubprocess(agentDef, workingDirectory) {
|
|
19301
|
+
static async spawnSubprocess(agentDef, workingDirectory, allowedPaths = []) {
|
|
19147
19302
|
const instance = new _AgentInstance(agentDef.name);
|
|
19148
19303
|
const resolved = resolveAgentCommand(agentDef.command);
|
|
19149
|
-
|
|
19304
|
+
log31.debug(
|
|
19150
19305
|
{
|
|
19151
19306
|
agentName: agentDef.name,
|
|
19152
19307
|
command: resolved.command,
|
|
@@ -19157,10 +19312,7 @@ var init_agent_instance = __esm({
|
|
|
19157
19312
|
const ignorePatterns = PathGuard.loadIgnoreFile(workingDirectory);
|
|
19158
19313
|
instance.pathGuard = new PathGuard({
|
|
19159
19314
|
cwd: workingDirectory,
|
|
19160
|
-
|
|
19161
|
-
// spawnSubprocess would need to receive a SecurityConfig param to use it.
|
|
19162
|
-
// Tracked as follow-up: pass workspace security config through spawn/resume call chain.
|
|
19163
|
-
allowedPaths: [],
|
|
19315
|
+
allowedPaths,
|
|
19164
19316
|
ignorePatterns
|
|
19165
19317
|
});
|
|
19166
19318
|
instance.child = spawn8(
|
|
@@ -19231,14 +19383,14 @@ var init_agent_instance = __esm({
|
|
|
19231
19383
|
}
|
|
19232
19384
|
});
|
|
19233
19385
|
if (initResponse.protocolVersion !== PROTOCOL_VERSION) {
|
|
19234
|
-
|
|
19386
|
+
log31.warn(
|
|
19235
19387
|
{ expected: PROTOCOL_VERSION, got: initResponse.protocolVersion },
|
|
19236
19388
|
"ACP protocol version mismatch \u2014 some features may not work correctly"
|
|
19237
19389
|
);
|
|
19238
19390
|
}
|
|
19239
19391
|
instance.promptCapabilities = initResponse.agentCapabilities?.promptCapabilities;
|
|
19240
19392
|
instance.agentCapabilities = initResponse.agentCapabilities;
|
|
19241
|
-
|
|
19393
|
+
log31.info(
|
|
19242
19394
|
{ promptCapabilities: instance.promptCapabilities ?? {} },
|
|
19243
19395
|
"Agent prompt capabilities"
|
|
19244
19396
|
);
|
|
@@ -19247,14 +19399,14 @@ var init_agent_instance = __esm({
|
|
|
19247
19399
|
setupCrashDetection() {
|
|
19248
19400
|
this.child.on("exit", (code, signal) => {
|
|
19249
19401
|
if (this._destroying) return;
|
|
19250
|
-
|
|
19402
|
+
log31.info(
|
|
19251
19403
|
{ sessionId: this.sessionId, exitCode: code, signal },
|
|
19252
19404
|
"Agent process exited"
|
|
19253
19405
|
);
|
|
19254
19406
|
if (signal === "SIGINT" || signal === "SIGTERM") return;
|
|
19255
19407
|
if (code !== 0 && code !== null || signal) {
|
|
19256
19408
|
const stderr = this.stderrCapture.getLastLines();
|
|
19257
|
-
this.emit(
|
|
19409
|
+
this.emit(SessionEv.AGENT_EVENT, {
|
|
19258
19410
|
type: "error",
|
|
19259
19411
|
message: signal ? `Agent killed by signal ${signal}
|
|
19260
19412
|
${stderr}` : `Agent crashed (exit code ${code})
|
|
@@ -19263,30 +19415,31 @@ ${stderr}`
|
|
|
19263
19415
|
}
|
|
19264
19416
|
});
|
|
19265
19417
|
this.connection.closed.then(() => {
|
|
19266
|
-
|
|
19418
|
+
log31.debug({ sessionId: this.sessionId }, "ACP connection closed");
|
|
19267
19419
|
});
|
|
19268
19420
|
}
|
|
19269
|
-
static async spawn(agentDef, workingDirectory, mcpServers) {
|
|
19270
|
-
|
|
19421
|
+
static async spawn(agentDef, workingDirectory, mcpServers, allowedPaths) {
|
|
19422
|
+
log31.debug(
|
|
19271
19423
|
{ agentName: agentDef.name, command: agentDef.command },
|
|
19272
19424
|
"Spawning agent"
|
|
19273
19425
|
);
|
|
19274
19426
|
const spawnStart = Date.now();
|
|
19275
19427
|
const instance = await _AgentInstance.spawnSubprocess(
|
|
19276
19428
|
agentDef,
|
|
19277
|
-
workingDirectory
|
|
19429
|
+
workingDirectory,
|
|
19430
|
+
allowedPaths
|
|
19278
19431
|
);
|
|
19279
19432
|
const resolvedMcp = _AgentInstance.mcpManager.resolve(mcpServers);
|
|
19280
19433
|
const response = await instance.connection.newSession({
|
|
19281
19434
|
cwd: workingDirectory,
|
|
19282
19435
|
mcpServers: resolvedMcp
|
|
19283
19436
|
});
|
|
19284
|
-
|
|
19437
|
+
log31.info(response, "newSession response");
|
|
19285
19438
|
instance.sessionId = response.sessionId;
|
|
19286
19439
|
instance.initialSessionResponse = response;
|
|
19287
19440
|
instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
|
|
19288
19441
|
instance.setupCrashDetection();
|
|
19289
|
-
|
|
19442
|
+
log31.info(
|
|
19290
19443
|
{
|
|
19291
19444
|
sessionId: response.sessionId,
|
|
19292
19445
|
durationMs: Date.now() - spawnStart,
|
|
@@ -19297,12 +19450,13 @@ ${stderr}`
|
|
|
19297
19450
|
);
|
|
19298
19451
|
return instance;
|
|
19299
19452
|
}
|
|
19300
|
-
static async resume(agentDef, workingDirectory, agentSessionId, mcpServers) {
|
|
19301
|
-
|
|
19453
|
+
static async resume(agentDef, workingDirectory, agentSessionId, mcpServers, allowedPaths) {
|
|
19454
|
+
log31.debug({ agentName: agentDef.name, agentSessionId }, "Resuming agent");
|
|
19302
19455
|
const spawnStart = Date.now();
|
|
19303
19456
|
const instance = await _AgentInstance.spawnSubprocess(
|
|
19304
19457
|
agentDef,
|
|
19305
|
-
workingDirectory
|
|
19458
|
+
workingDirectory,
|
|
19459
|
+
allowedPaths
|
|
19306
19460
|
);
|
|
19307
19461
|
const resolvedMcp = _AgentInstance.mcpManager.resolve(mcpServers);
|
|
19308
19462
|
try {
|
|
@@ -19315,7 +19469,7 @@ ${stderr}`
|
|
|
19315
19469
|
instance.sessionId = agentSessionId;
|
|
19316
19470
|
instance.initialSessionResponse = response;
|
|
19317
19471
|
instance.debugTracer = createDebugTracer(agentSessionId, workingDirectory);
|
|
19318
|
-
|
|
19472
|
+
log31.info(
|
|
19319
19473
|
{
|
|
19320
19474
|
sessionId: agentSessionId,
|
|
19321
19475
|
durationMs: Date.now() - spawnStart,
|
|
@@ -19331,7 +19485,7 @@ ${stderr}`
|
|
|
19331
19485
|
instance.sessionId = response.sessionId;
|
|
19332
19486
|
instance.initialSessionResponse = response;
|
|
19333
19487
|
instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
|
|
19334
|
-
|
|
19488
|
+
log31.info(
|
|
19335
19489
|
{
|
|
19336
19490
|
sessionId: response.sessionId,
|
|
19337
19491
|
durationMs: Date.now() - spawnStart,
|
|
@@ -19341,7 +19495,7 @@ ${stderr}`
|
|
|
19341
19495
|
);
|
|
19342
19496
|
}
|
|
19343
19497
|
} catch (err) {
|
|
19344
|
-
|
|
19498
|
+
log31.warn(
|
|
19345
19499
|
{ err, agentSessionId },
|
|
19346
19500
|
"Resume failed, falling back to new session"
|
|
19347
19501
|
);
|
|
@@ -19352,7 +19506,7 @@ ${stderr}`
|
|
|
19352
19506
|
instance.sessionId = response.sessionId;
|
|
19353
19507
|
instance.initialSessionResponse = response;
|
|
19354
19508
|
instance.debugTracer = createDebugTracer(response.sessionId, workingDirectory);
|
|
19355
|
-
|
|
19509
|
+
log31.info(
|
|
19356
19510
|
{ sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
|
|
19357
19511
|
"Agent fallback spawn complete"
|
|
19358
19512
|
);
|
|
@@ -19490,7 +19644,7 @@ ${stderr}`
|
|
|
19490
19644
|
return;
|
|
19491
19645
|
}
|
|
19492
19646
|
if (event !== null) {
|
|
19493
|
-
self.emit(
|
|
19647
|
+
self.emit(SessionEv.AGENT_EVENT, event);
|
|
19494
19648
|
}
|
|
19495
19649
|
},
|
|
19496
19650
|
// ── Permission requests ──────────────────────────────────────────────
|
|
@@ -19517,7 +19671,7 @@ ${stderr}`
|
|
|
19517
19671
|
throw new Error(`[Access denied] ${pathCheck.reason}`);
|
|
19518
19672
|
}
|
|
19519
19673
|
if (self.middlewareChain) {
|
|
19520
|
-
const result = await self.middlewareChain.execute(
|
|
19674
|
+
const result = await self.middlewareChain.execute(Hook.FS_BEFORE_READ, { sessionId: self.sessionId, path: p2.path, line: p2.line, limit: p2.limit }, async (r) => r);
|
|
19521
19675
|
if (!result) return { content: "" };
|
|
19522
19676
|
p2.path = result.path;
|
|
19523
19677
|
}
|
|
@@ -19535,7 +19689,7 @@ ${stderr}`
|
|
|
19535
19689
|
throw new Error(`[Access denied] ${pathCheck.reason}`);
|
|
19536
19690
|
}
|
|
19537
19691
|
if (self.middlewareChain) {
|
|
19538
|
-
const result = await self.middlewareChain.execute(
|
|
19692
|
+
const result = await self.middlewareChain.execute(Hook.FS_BEFORE_WRITE, { sessionId: self.sessionId, path: writePath, content: writeContent }, async (r) => r);
|
|
19539
19693
|
if (!result) return {};
|
|
19540
19694
|
writePath = result.path;
|
|
19541
19695
|
writeContent = result.content;
|
|
@@ -19632,10 +19786,16 @@ ${stderr}`
|
|
|
19632
19786
|
// ── Prompt & lifecycle ──────────────────────────────────────────────
|
|
19633
19787
|
async prompt(text6, attachments) {
|
|
19634
19788
|
const contentBlocks = [{ type: "text", text: text6 }];
|
|
19635
|
-
const
|
|
19789
|
+
const capabilities = this.promptCapabilities ?? {};
|
|
19636
19790
|
for (const att of attachments ?? []) {
|
|
19637
|
-
const
|
|
19638
|
-
if (
|
|
19791
|
+
const skipNote = buildAttachmentNote(att, capabilities);
|
|
19792
|
+
if (skipNote !== null) {
|
|
19793
|
+
contentBlocks[0].text += `
|
|
19794
|
+
|
|
19795
|
+
${skipNote}`;
|
|
19796
|
+
continue;
|
|
19797
|
+
}
|
|
19798
|
+
if (att.type === "image" && capabilities.image && SUPPORTED_IMAGE_MIMES.has(att.mimeType)) {
|
|
19639
19799
|
const attCheck = this.pathGuard.validatePath(att.filePath, "read");
|
|
19640
19800
|
if (!attCheck.allowed) {
|
|
19641
19801
|
contentBlocks[0].text += `
|
|
@@ -19645,7 +19805,7 @@ ${stderr}`
|
|
|
19645
19805
|
}
|
|
19646
19806
|
const data = await fs40.promises.readFile(att.filePath);
|
|
19647
19807
|
contentBlocks.push({ type: "image", data: data.toString("base64"), mimeType: att.mimeType });
|
|
19648
|
-
} else if (att.type === "audio" &&
|
|
19808
|
+
} else if (att.type === "audio" && capabilities.audio) {
|
|
19649
19809
|
const attCheck = this.pathGuard.validatePath(att.filePath, "read");
|
|
19650
19810
|
if (!attCheck.allowed) {
|
|
19651
19811
|
contentBlocks[0].text += `
|
|
@@ -19656,9 +19816,9 @@ ${stderr}`
|
|
|
19656
19816
|
const data = await fs40.promises.readFile(att.filePath);
|
|
19657
19817
|
contentBlocks.push({ type: "audio", data: data.toString("base64"), mimeType: att.mimeType });
|
|
19658
19818
|
} else {
|
|
19659
|
-
if (
|
|
19660
|
-
|
|
19661
|
-
{ type: att.type, capabilities
|
|
19819
|
+
if (att.type === "image" || att.type === "audio") {
|
|
19820
|
+
log31.debug(
|
|
19821
|
+
{ type: att.type, capabilities },
|
|
19662
19822
|
"Agent does not support %s content, falling back to file path",
|
|
19663
19823
|
att.type
|
|
19664
19824
|
);
|
|
@@ -19721,15 +19881,15 @@ var init_agent_manager = __esm({
|
|
|
19721
19881
|
getAgent(name) {
|
|
19722
19882
|
return this.catalog.resolve(name);
|
|
19723
19883
|
}
|
|
19724
|
-
async spawn(agentName, workingDirectory) {
|
|
19884
|
+
async spawn(agentName, workingDirectory, allowedPaths) {
|
|
19725
19885
|
const agentDef = this.getAgent(agentName);
|
|
19726
19886
|
if (!agentDef) throw new Error(`Agent "${agentName}" is not installed. Run "openacp agents install ${agentName}" to add it.`);
|
|
19727
|
-
return AgentInstance.spawn(agentDef, workingDirectory);
|
|
19887
|
+
return AgentInstance.spawn(agentDef, workingDirectory, void 0, allowedPaths);
|
|
19728
19888
|
}
|
|
19729
|
-
async resume(agentName, workingDirectory, agentSessionId) {
|
|
19889
|
+
async resume(agentName, workingDirectory, agentSessionId, allowedPaths) {
|
|
19730
19890
|
const agentDef = this.getAgent(agentName);
|
|
19731
19891
|
if (!agentDef) throw new Error(`Agent "${agentName}" is not installed. Run "openacp agents install ${agentName}" to add it.`);
|
|
19732
|
-
return AgentInstance.resume(agentDef, workingDirectory, agentSessionId);
|
|
19892
|
+
return AgentInstance.resume(agentDef, workingDirectory, agentSessionId, void 0, allowedPaths);
|
|
19733
19893
|
}
|
|
19734
19894
|
};
|
|
19735
19895
|
}
|
|
@@ -19926,6 +20086,7 @@ var init_session2 = __esm({
|
|
|
19926
20086
|
init_permission_gate();
|
|
19927
20087
|
init_log();
|
|
19928
20088
|
init_turn_context();
|
|
20089
|
+
init_events();
|
|
19929
20090
|
moduleLog = createChildLogger({ module: "session" });
|
|
19930
20091
|
TTS_PROMPT_INSTRUCTION = `
|
|
19931
20092
|
|
|
@@ -19954,7 +20115,15 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
19954
20115
|
}
|
|
19955
20116
|
agentName;
|
|
19956
20117
|
workingDirectory;
|
|
19957
|
-
|
|
20118
|
+
_agentInstance;
|
|
20119
|
+
get agentInstance() {
|
|
20120
|
+
return this._agentInstance;
|
|
20121
|
+
}
|
|
20122
|
+
set agentInstance(agent) {
|
|
20123
|
+
this._agentInstance = agent;
|
|
20124
|
+
this.wireAgentRelay();
|
|
20125
|
+
this.wireCommandsBuffer();
|
|
20126
|
+
}
|
|
19958
20127
|
agentSessionId = "";
|
|
19959
20128
|
_status = "initializing";
|
|
19960
20129
|
name;
|
|
@@ -19978,9 +20147,6 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
19978
20147
|
threadIds = /* @__PURE__ */ new Map();
|
|
19979
20148
|
/** Active turn context — sealed on prompt dequeue, cleared on turn end */
|
|
19980
20149
|
activeTurnContext = null;
|
|
19981
|
-
/** The agentInstance for which the agent→session event relay is wired (prevents duplicate relays from multiple bridges).
|
|
19982
|
-
* When the agent is swapped, the relay must be re-wired to the new instance. */
|
|
19983
|
-
agentRelaySource = null;
|
|
19984
20150
|
permissionGate = new PermissionGate();
|
|
19985
20151
|
queue;
|
|
19986
20152
|
speechService;
|
|
@@ -20004,23 +20170,37 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
20004
20170
|
this.log.error({ err }, "Prompt execution failed");
|
|
20005
20171
|
const message = err instanceof Error ? err.message : String(err);
|
|
20006
20172
|
this.fail(message);
|
|
20007
|
-
this.emit(
|
|
20173
|
+
this.emit(SessionEv.AGENT_EVENT, { type: "error", message: `Prompt execution failed: ${message}` });
|
|
20008
20174
|
}
|
|
20009
20175
|
);
|
|
20010
|
-
|
|
20176
|
+
}
|
|
20177
|
+
/** Wire the agent→session event relay on the current agentInstance.
|
|
20178
|
+
* Removes any previous relay first to avoid duplicates on agent switch.
|
|
20179
|
+
* This relay ensures session.emit("agent_event") fires for ALL sessions,
|
|
20180
|
+
* including headless API sessions that have no SessionBridge attached. */
|
|
20181
|
+
agentRelayCleanup;
|
|
20182
|
+
wireAgentRelay() {
|
|
20183
|
+
this.agentRelayCleanup?.();
|
|
20184
|
+
const instance = this._agentInstance;
|
|
20185
|
+
const handler = (event) => {
|
|
20186
|
+
this.emit(SessionEv.AGENT_EVENT, event);
|
|
20187
|
+
};
|
|
20188
|
+
instance.on(SessionEv.AGENT_EVENT, handler);
|
|
20189
|
+
this.agentRelayCleanup = () => instance.off(SessionEv.AGENT_EVENT, handler);
|
|
20011
20190
|
}
|
|
20012
20191
|
/** Wire a listener on the current agentInstance to buffer commands_update events.
|
|
20013
20192
|
* Must be called after every agentInstance replacement (constructor + switchAgent). */
|
|
20014
20193
|
commandsBufferCleanup;
|
|
20015
20194
|
wireCommandsBuffer() {
|
|
20016
20195
|
this.commandsBufferCleanup?.();
|
|
20196
|
+
const instance = this._agentInstance;
|
|
20017
20197
|
const handler = (event) => {
|
|
20018
20198
|
if (event.type === "commands_update") {
|
|
20019
20199
|
this.latestCommands = event.commands;
|
|
20020
20200
|
}
|
|
20021
20201
|
};
|
|
20022
|
-
|
|
20023
|
-
this.commandsBufferCleanup = () =>
|
|
20202
|
+
instance.on(SessionEv.AGENT_EVENT, handler);
|
|
20203
|
+
this.commandsBufferCleanup = () => instance.off(SessionEv.AGENT_EVENT, handler);
|
|
20024
20204
|
}
|
|
20025
20205
|
// --- State Machine ---
|
|
20026
20206
|
get status() {
|
|
@@ -20034,12 +20214,12 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
20034
20214
|
fail(reason) {
|
|
20035
20215
|
if (this._status === "error") return;
|
|
20036
20216
|
this.transition("error");
|
|
20037
|
-
this.emit(
|
|
20217
|
+
this.emit(SessionEv.ERROR, new Error(reason));
|
|
20038
20218
|
}
|
|
20039
20219
|
/** Transition to finished — from active only. Emits session_end for backward compat. */
|
|
20040
20220
|
finish(reason) {
|
|
20041
20221
|
this.transition("finished");
|
|
20042
|
-
this.emit(
|
|
20222
|
+
this.emit(SessionEv.SESSION_END, reason ?? "completed");
|
|
20043
20223
|
}
|
|
20044
20224
|
/** Transition to cancelled — from active only (terminal session cancel) */
|
|
20045
20225
|
markCancelled() {
|
|
@@ -20055,7 +20235,7 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
20055
20235
|
}
|
|
20056
20236
|
this._status = to;
|
|
20057
20237
|
this.log.debug({ from, to }, "Session status transition");
|
|
20058
|
-
this.emit(
|
|
20238
|
+
this.emit(SessionEv.STATUS_CHANGE, from, to);
|
|
20059
20239
|
}
|
|
20060
20240
|
/** Number of prompts waiting in queue */
|
|
20061
20241
|
get queueDepth() {
|
|
@@ -20077,8 +20257,8 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
20077
20257
|
async enqueuePrompt(text6, attachments, routing, externalTurnId) {
|
|
20078
20258
|
const turnId = externalTurnId ?? nanoid4(8);
|
|
20079
20259
|
if (this.middlewareChain) {
|
|
20080
|
-
const payload = { text: text6, attachments, sessionId: this.id };
|
|
20081
|
-
const result = await this.middlewareChain.execute(
|
|
20260
|
+
const payload = { text: text6, attachments, sessionId: this.id, sourceAdapterId: routing?.sourceAdapterId };
|
|
20261
|
+
const result = await this.middlewareChain.execute(Hook.AGENT_BEFORE_PROMPT, payload, async (p2) => p2);
|
|
20082
20262
|
if (!result) return turnId;
|
|
20083
20263
|
text6 = result.text;
|
|
20084
20264
|
attachments = result.attachments;
|
|
@@ -20093,9 +20273,9 @@ Additionally, include a [TTS]...[/TTS] block with a spoken-friendly summary of y
|
|
|
20093
20273
|
routing?.responseAdapterId,
|
|
20094
20274
|
turnId
|
|
20095
20275
|
);
|
|
20096
|
-
this.emit(
|
|
20276
|
+
this.emit(SessionEv.TURN_STARTED, this.activeTurnContext);
|
|
20097
20277
|
this.promptCount++;
|
|
20098
|
-
this.emit(
|
|
20278
|
+
this.emit(SessionEv.PROMPT_COUNT_CHANGED, this.promptCount);
|
|
20099
20279
|
if (this._status === "initializing" || this._status === "cancelled" || this._status === "error") {
|
|
20100
20280
|
this.activate();
|
|
20101
20281
|
}
|
|
@@ -20124,10 +20304,18 @@ ${text6}`;
|
|
|
20124
20304
|
}
|
|
20125
20305
|
} : null;
|
|
20126
20306
|
if (accumulatorListener) {
|
|
20127
|
-
this.on(
|
|
20307
|
+
this.on(SessionEv.AGENT_EVENT, accumulatorListener);
|
|
20308
|
+
}
|
|
20309
|
+
const mw = this.middlewareChain;
|
|
20310
|
+
const afterEventListener = mw ? (event) => {
|
|
20311
|
+
mw.execute(Hook.AGENT_AFTER_EVENT, { sessionId: this.id, event, outgoingMessage: { type: "text", text: "" } }, async (e) => e).catch(() => {
|
|
20312
|
+
});
|
|
20313
|
+
} : null;
|
|
20314
|
+
if (afterEventListener) {
|
|
20315
|
+
this.agentInstance.on(SessionEv.AGENT_EVENT, afterEventListener);
|
|
20128
20316
|
}
|
|
20129
20317
|
if (this.middlewareChain) {
|
|
20130
|
-
this.middlewareChain.execute(
|
|
20318
|
+
this.middlewareChain.execute(Hook.TURN_START, { sessionId: this.id, promptText: processed.text, promptNumber: this.promptCount }, async (p2) => p2).catch(() => {
|
|
20131
20319
|
});
|
|
20132
20320
|
}
|
|
20133
20321
|
let stopReason = "end_turn";
|
|
@@ -20148,10 +20336,13 @@ ${text6}`;
|
|
|
20148
20336
|
promptError = err;
|
|
20149
20337
|
} finally {
|
|
20150
20338
|
if (accumulatorListener) {
|
|
20151
|
-
this.off(
|
|
20339
|
+
this.off(SessionEv.AGENT_EVENT, accumulatorListener);
|
|
20340
|
+
}
|
|
20341
|
+
if (afterEventListener) {
|
|
20342
|
+
this.agentInstance.off(SessionEv.AGENT_EVENT, afterEventListener);
|
|
20152
20343
|
}
|
|
20153
20344
|
if (this.middlewareChain) {
|
|
20154
|
-
this.middlewareChain.execute(
|
|
20345
|
+
this.middlewareChain.execute(Hook.TURN_END, { sessionId: this.id, stopReason, durationMs: Date.now() - promptStart }, async (p2) => p2).catch(() => {
|
|
20155
20346
|
});
|
|
20156
20347
|
}
|
|
20157
20348
|
this.activeTurnContext = null;
|
|
@@ -20196,7 +20387,7 @@ ${text6}`;
|
|
|
20196
20387
|
const audioBuffer = await fs41.promises.readFile(audioPath);
|
|
20197
20388
|
const result = await this.speechService.transcribe(audioBuffer, audioMime);
|
|
20198
20389
|
this.log.info({ provider: "stt", duration: result.duration }, "Voice transcribed");
|
|
20199
|
-
this.emit(
|
|
20390
|
+
this.emit(SessionEv.AGENT_EVENT, {
|
|
20200
20391
|
type: "system_message",
|
|
20201
20392
|
message: `\u{1F3A4} You said: ${result.text}`
|
|
20202
20393
|
});
|
|
@@ -20205,7 +20396,7 @@ ${text6}`;
|
|
|
20205
20396
|
${result.text}` : result.text;
|
|
20206
20397
|
} catch (err) {
|
|
20207
20398
|
this.log.warn({ err }, "STT transcription failed, keeping audio attachment");
|
|
20208
|
-
this.emit(
|
|
20399
|
+
this.emit(SessionEv.AGENT_EVENT, {
|
|
20209
20400
|
type: "error",
|
|
20210
20401
|
message: `Voice transcription failed: ${err.message}`
|
|
20211
20402
|
});
|
|
@@ -20239,12 +20430,12 @@ ${result.text}` : result.text;
|
|
|
20239
20430
|
timeoutPromise
|
|
20240
20431
|
]);
|
|
20241
20432
|
const base64 = result.audioBuffer.toString("base64");
|
|
20242
|
-
this.emit(
|
|
20433
|
+
this.emit(SessionEv.AGENT_EVENT, {
|
|
20243
20434
|
type: "audio_content",
|
|
20244
20435
|
data: base64,
|
|
20245
20436
|
mimeType: result.mimeType
|
|
20246
20437
|
});
|
|
20247
|
-
this.emit(
|
|
20438
|
+
this.emit(SessionEv.AGENT_EVENT, { type: "tts_strip" });
|
|
20248
20439
|
this.log.info("TTS synthesis completed");
|
|
20249
20440
|
} finally {
|
|
20250
20441
|
clearTimeout(ttsTimer);
|
|
@@ -20259,19 +20450,19 @@ ${result.text}` : result.text;
|
|
|
20259
20450
|
const captureHandler = (event) => {
|
|
20260
20451
|
if (event.type === "text") title += event.content;
|
|
20261
20452
|
};
|
|
20262
|
-
this.pause((event) => event !==
|
|
20263
|
-
this.agentInstance.on(
|
|
20453
|
+
this.pause((event) => event !== SessionEv.AGENT_EVENT);
|
|
20454
|
+
this.agentInstance.on(SessionEv.AGENT_EVENT, captureHandler);
|
|
20264
20455
|
try {
|
|
20265
20456
|
await this.agentInstance.prompt(
|
|
20266
20457
|
"Summarize this conversation in max 5 words for a topic title. Reply ONLY with the title, nothing else."
|
|
20267
20458
|
);
|
|
20268
20459
|
this.name = title.trim().slice(0, 50) || `Session ${this.id.slice(0, 6)}`;
|
|
20269
20460
|
this.log.info({ name: this.name }, "Session auto-named");
|
|
20270
|
-
this.emit(
|
|
20461
|
+
this.emit(SessionEv.NAMED, this.name);
|
|
20271
20462
|
} catch {
|
|
20272
20463
|
this.name = `Session ${this.id.slice(0, 6)}`;
|
|
20273
20464
|
} finally {
|
|
20274
|
-
this.agentInstance.off(
|
|
20465
|
+
this.agentInstance.off(SessionEv.AGENT_EVENT, captureHandler);
|
|
20275
20466
|
this.clearBuffer();
|
|
20276
20467
|
this.resume();
|
|
20277
20468
|
}
|
|
@@ -20333,7 +20524,7 @@ ${result.text}` : result.text;
|
|
|
20333
20524
|
/** Set session name explicitly and emit 'named' event */
|
|
20334
20525
|
setName(name) {
|
|
20335
20526
|
this.name = name;
|
|
20336
|
-
this.emit(
|
|
20527
|
+
this.emit(SessionEv.NAMED, name);
|
|
20337
20528
|
}
|
|
20338
20529
|
/** Send a config option change to the agent and update local state from the response. */
|
|
20339
20530
|
async setConfigOption(configId, value) {
|
|
@@ -20349,7 +20540,7 @@ ${result.text}` : result.text;
|
|
|
20349
20540
|
}
|
|
20350
20541
|
async updateConfigOptions(options) {
|
|
20351
20542
|
if (this.middlewareChain) {
|
|
20352
|
-
const result = await this.middlewareChain.execute(
|
|
20543
|
+
const result = await this.middlewareChain.execute(Hook.CONFIG_BEFORE_CHANGE, { sessionId: this.id, configId: "options", oldValue: this.configOptions, newValue: options }, async (p2) => p2);
|
|
20353
20544
|
if (!result) return;
|
|
20354
20545
|
}
|
|
20355
20546
|
this.configOptions = options;
|
|
@@ -20369,7 +20560,7 @@ ${result.text}` : result.text;
|
|
|
20369
20560
|
/** Cancel the current prompt and clear the queue. Stays in active state. */
|
|
20370
20561
|
async abortPrompt() {
|
|
20371
20562
|
if (this.middlewareChain) {
|
|
20372
|
-
const result = await this.middlewareChain.execute(
|
|
20563
|
+
const result = await this.middlewareChain.execute(Hook.AGENT_BEFORE_CANCEL, { sessionId: this.id }, async (p2) => p2);
|
|
20373
20564
|
if (!result) return;
|
|
20374
20565
|
}
|
|
20375
20566
|
this.queue.clear();
|
|
@@ -20410,7 +20601,6 @@ ${result.text}` : result.text;
|
|
|
20410
20601
|
this.configOptions = [];
|
|
20411
20602
|
this.latestCommands = null;
|
|
20412
20603
|
this.applySpawnResponse(newAgent.initialSessionResponse, newAgent.agentCapabilities);
|
|
20413
|
-
this.wireCommandsBuffer();
|
|
20414
20604
|
this.log.info({ from: this.agentSwitchHistory.at(-1).agentName, to: agentName }, "Agent switched");
|
|
20415
20605
|
}
|
|
20416
20606
|
async destroy() {
|
|
@@ -20432,6 +20622,7 @@ var init_session_manager = __esm({
|
|
|
20432
20622
|
"src/core/sessions/session-manager.ts"() {
|
|
20433
20623
|
"use strict";
|
|
20434
20624
|
init_session2();
|
|
20625
|
+
init_events();
|
|
20435
20626
|
SessionManager = class {
|
|
20436
20627
|
sessions = /* @__PURE__ */ new Map();
|
|
20437
20628
|
store;
|
|
@@ -20536,18 +20727,18 @@ var init_session_manager = __esm({
|
|
|
20536
20727
|
}
|
|
20537
20728
|
}
|
|
20538
20729
|
if (this.middlewareChain) {
|
|
20539
|
-
this.middlewareChain.execute(
|
|
20730
|
+
this.middlewareChain.execute(Hook.SESSION_AFTER_DESTROY, { sessionId }, async (p2) => p2).catch(() => {
|
|
20540
20731
|
});
|
|
20541
20732
|
}
|
|
20542
20733
|
}
|
|
20543
20734
|
listSessions(channelId) {
|
|
20544
|
-
const all = Array.from(this.sessions.values());
|
|
20735
|
+
const all = Array.from(this.sessions.values()).filter((s) => !s.isAssistant);
|
|
20545
20736
|
if (channelId) return all.filter((s) => s.channelId === channelId);
|
|
20546
20737
|
return all;
|
|
20547
20738
|
}
|
|
20548
20739
|
listAllSessions(channelId) {
|
|
20549
20740
|
if (this.store) {
|
|
20550
|
-
let records = this.store.list();
|
|
20741
|
+
let records = this.store.list().filter((r) => !r.isAssistant);
|
|
20551
20742
|
if (channelId) records = records.filter((r) => r.channelId === channelId);
|
|
20552
20743
|
return records.map((record) => {
|
|
20553
20744
|
const live2 = this.sessions.get(record.sessionId);
|
|
@@ -20587,7 +20778,7 @@ var init_session_manager = __esm({
|
|
|
20587
20778
|
};
|
|
20588
20779
|
});
|
|
20589
20780
|
}
|
|
20590
|
-
let live = Array.from(this.sessions.values());
|
|
20781
|
+
let live = Array.from(this.sessions.values()).filter((s) => !s.isAssistant);
|
|
20591
20782
|
if (channelId) live = live.filter((s) => s.channelId === channelId);
|
|
20592
20783
|
return live.map((s) => ({
|
|
20593
20784
|
id: s.id,
|
|
@@ -20608,7 +20799,7 @@ var init_session_manager = __esm({
|
|
|
20608
20799
|
}
|
|
20609
20800
|
listRecords(filter) {
|
|
20610
20801
|
if (!this.store) return [];
|
|
20611
|
-
let records = this.store.list();
|
|
20802
|
+
let records = this.store.list().filter((r) => !r.isAssistant);
|
|
20612
20803
|
if (filter?.statuses?.length) {
|
|
20613
20804
|
records = records.filter((r) => filter.statuses.includes(r.status));
|
|
20614
20805
|
}
|
|
@@ -20617,7 +20808,7 @@ var init_session_manager = __esm({
|
|
|
20617
20808
|
async removeRecord(sessionId) {
|
|
20618
20809
|
if (!this.store) return;
|
|
20619
20810
|
await this.store.remove(sessionId);
|
|
20620
|
-
this.eventBus?.emit(
|
|
20811
|
+
this.eventBus?.emit(BusEvent.SESSION_DELETED, { sessionId });
|
|
20621
20812
|
}
|
|
20622
20813
|
/**
|
|
20623
20814
|
* Graceful shutdown: persist session state without killing agent subprocesses.
|
|
@@ -20665,7 +20856,7 @@ var init_session_manager = __esm({
|
|
|
20665
20856
|
this.sessions.clear();
|
|
20666
20857
|
if (this.middlewareChain) {
|
|
20667
20858
|
for (const sessionId of sessionIds) {
|
|
20668
|
-
this.middlewareChain.execute(
|
|
20859
|
+
this.middlewareChain.execute(Hook.SESSION_AFTER_DESTROY, { sessionId }, async (p2) => p2).catch(() => {
|
|
20669
20860
|
});
|
|
20670
20861
|
}
|
|
20671
20862
|
}
|
|
@@ -20675,14 +20866,15 @@ var init_session_manager = __esm({
|
|
|
20675
20866
|
});
|
|
20676
20867
|
|
|
20677
20868
|
// src/core/sessions/session-bridge.ts
|
|
20678
|
-
var
|
|
20869
|
+
var log32, SessionBridge;
|
|
20679
20870
|
var init_session_bridge = __esm({
|
|
20680
20871
|
"src/core/sessions/session-bridge.ts"() {
|
|
20681
20872
|
"use strict";
|
|
20682
20873
|
init_log();
|
|
20683
20874
|
init_bypass_detection();
|
|
20684
20875
|
init_turn_context();
|
|
20685
|
-
|
|
20876
|
+
init_events();
|
|
20877
|
+
log32 = createChildLogger({ module: "session-bridge" });
|
|
20686
20878
|
SessionBridge = class {
|
|
20687
20879
|
constructor(session, adapter, deps, adapterId) {
|
|
20688
20880
|
this.session = session;
|
|
@@ -20706,21 +20898,21 @@ var init_session_bridge = __esm({
|
|
|
20706
20898
|
try {
|
|
20707
20899
|
const mw = this.deps.middlewareChain;
|
|
20708
20900
|
if (mw) {
|
|
20709
|
-
const result = await mw.execute(
|
|
20901
|
+
const result = await mw.execute(Hook.MESSAGE_OUTGOING, { sessionId, message }, async (m) => m);
|
|
20710
20902
|
this.tracer?.log("core", { step: "middleware:outgoing", sessionId, hook: "message:outgoing", blocked: !result });
|
|
20711
20903
|
if (!result) return;
|
|
20712
20904
|
this.tracer?.log("core", { step: "dispatch", sessionId, message: result.message });
|
|
20713
20905
|
this.adapter.sendMessage(sessionId, result.message).catch((err) => {
|
|
20714
|
-
|
|
20906
|
+
log32.error({ err, sessionId }, "Failed to send message to adapter");
|
|
20715
20907
|
});
|
|
20716
20908
|
} else {
|
|
20717
20909
|
this.tracer?.log("core", { step: "dispatch", sessionId, message });
|
|
20718
20910
|
this.adapter.sendMessage(sessionId, message).catch((err) => {
|
|
20719
|
-
|
|
20911
|
+
log32.error({ err, sessionId }, "Failed to send message to adapter");
|
|
20720
20912
|
});
|
|
20721
20913
|
}
|
|
20722
20914
|
} catch (err) {
|
|
20723
|
-
|
|
20915
|
+
log32.error({ err, sessionId }, "Error in sendMessage middleware");
|
|
20724
20916
|
}
|
|
20725
20917
|
}
|
|
20726
20918
|
/** Determine if this bridge should forward the given event based on turn routing. */
|
|
@@ -20735,17 +20927,11 @@ var init_session_bridge = __esm({
|
|
|
20735
20927
|
connect() {
|
|
20736
20928
|
if (this.connected) return;
|
|
20737
20929
|
this.connected = true;
|
|
20738
|
-
|
|
20739
|
-
this.listen(this.session.agentInstance, "agent_event", (event) => {
|
|
20740
|
-
this.session.emit("agent_event", event);
|
|
20741
|
-
});
|
|
20742
|
-
this.session.agentRelaySource = this.session.agentInstance;
|
|
20743
|
-
}
|
|
20744
|
-
this.listen(this.session, "agent_event", (event) => {
|
|
20930
|
+
this.listen(this.session, SessionEv.AGENT_EVENT, (event) => {
|
|
20745
20931
|
if (this.shouldForward(event)) {
|
|
20746
20932
|
this.dispatchAgentEvent(event);
|
|
20747
20933
|
} else {
|
|
20748
|
-
this.deps.eventBus?.emit(
|
|
20934
|
+
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, { sessionId: this.session.id, event });
|
|
20749
20935
|
}
|
|
20750
20936
|
});
|
|
20751
20937
|
if (!this.session.agentInstance.onPermissionRequest || this.session.agentInstance.onPermissionRequest.__bridgeId === void 0) {
|
|
@@ -20755,47 +20941,51 @@ var init_session_bridge = __esm({
|
|
|
20755
20941
|
handler.__bridgeId = this.adapterId;
|
|
20756
20942
|
this.session.agentInstance.onPermissionRequest = handler;
|
|
20757
20943
|
}
|
|
20758
|
-
this.listen(this.session,
|
|
20944
|
+
this.listen(this.session, SessionEv.PERMISSION_REQUEST, async (request) => {
|
|
20759
20945
|
const current = this.session.agentInstance.onPermissionRequest;
|
|
20760
20946
|
if (current?.__bridgeId === this.adapterId) return;
|
|
20761
20947
|
if (!this.session.permissionGate.isPending) return;
|
|
20762
20948
|
try {
|
|
20763
20949
|
await this.adapter.sendPermissionRequest(this.session.id, request);
|
|
20764
20950
|
} catch (err) {
|
|
20765
|
-
|
|
20951
|
+
log32.error({ err, sessionId: this.session.id, adapterId: this.adapterId }, "Failed to send permission request to adapter");
|
|
20766
20952
|
}
|
|
20767
20953
|
});
|
|
20768
|
-
this.listen(this.session,
|
|
20954
|
+
this.listen(this.session, SessionEv.STATUS_CHANGE, (from, to) => {
|
|
20769
20955
|
this.deps.sessionManager.patchRecord(this.session.id, {
|
|
20770
20956
|
status: to,
|
|
20771
20957
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20772
20958
|
});
|
|
20773
|
-
this.
|
|
20774
|
-
|
|
20775
|
-
|
|
20776
|
-
|
|
20959
|
+
if (!this.session.isAssistant) {
|
|
20960
|
+
this.deps.eventBus?.emit(BusEvent.SESSION_UPDATED, {
|
|
20961
|
+
sessionId: this.session.id,
|
|
20962
|
+
status: to
|
|
20963
|
+
});
|
|
20964
|
+
}
|
|
20777
20965
|
if (to === "finished") {
|
|
20778
20966
|
queueMicrotask(() => this.disconnect());
|
|
20779
20967
|
}
|
|
20780
20968
|
});
|
|
20781
|
-
this.listen(this.session,
|
|
20969
|
+
this.listen(this.session, SessionEv.NAMED, async (name) => {
|
|
20782
20970
|
const record = this.deps.sessionManager.getSessionRecord(this.session.id);
|
|
20783
20971
|
const alreadyNamed = !!record?.name;
|
|
20784
20972
|
await this.deps.sessionManager.patchRecord(this.session.id, { name });
|
|
20785
|
-
this.
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20973
|
+
if (!this.session.isAssistant) {
|
|
20974
|
+
this.deps.eventBus?.emit(BusEvent.SESSION_UPDATED, {
|
|
20975
|
+
sessionId: this.session.id,
|
|
20976
|
+
name
|
|
20977
|
+
});
|
|
20978
|
+
}
|
|
20789
20979
|
if (!alreadyNamed) {
|
|
20790
20980
|
await this.adapter.renameSessionThread(this.session.id, name);
|
|
20791
20981
|
}
|
|
20792
20982
|
});
|
|
20793
|
-
this.listen(this.session,
|
|
20983
|
+
this.listen(this.session, SessionEv.PROMPT_COUNT_CHANGED, (count) => {
|
|
20794
20984
|
this.deps.sessionManager.patchRecord(this.session.id, { currentPromptCount: count });
|
|
20795
20985
|
});
|
|
20796
|
-
this.listen(this.session,
|
|
20986
|
+
this.listen(this.session, SessionEv.TURN_STARTED, (ctx) => {
|
|
20797
20987
|
if (ctx.sourceAdapterId !== "sse" && ctx.sourceAdapterId !== "api") {
|
|
20798
|
-
this.deps.eventBus?.emit(
|
|
20988
|
+
this.deps.eventBus?.emit(BusEvent.MESSAGE_PROCESSING, {
|
|
20799
20989
|
sessionId: this.session.id,
|
|
20800
20990
|
turnId: ctx.turnId,
|
|
20801
20991
|
sourceAdapterId: ctx.sourceAdapterId,
|
|
@@ -20804,10 +20994,10 @@ var init_session_bridge = __esm({
|
|
|
20804
20994
|
}
|
|
20805
20995
|
});
|
|
20806
20996
|
if (this.session.latestCommands !== null) {
|
|
20807
|
-
this.session.emit(
|
|
20997
|
+
this.session.emit(SessionEv.AGENT_EVENT, { type: "commands_update", commands: this.session.latestCommands });
|
|
20808
20998
|
}
|
|
20809
20999
|
if (this.session.configOptions.length > 0) {
|
|
20810
|
-
this.session.emit(
|
|
21000
|
+
this.session.emit(SessionEv.AGENT_EVENT, { type: "config_option_update", options: this.session.configOptions });
|
|
20811
21001
|
}
|
|
20812
21002
|
}
|
|
20813
21003
|
disconnect() {
|
|
@@ -20827,29 +21017,23 @@ var init_session_bridge = __esm({
|
|
|
20827
21017
|
const mw = this.deps.middlewareChain;
|
|
20828
21018
|
if (mw) {
|
|
20829
21019
|
try {
|
|
20830
|
-
const result = await mw.execute(
|
|
21020
|
+
const result = await mw.execute(Hook.AGENT_BEFORE_EVENT, { sessionId: this.session.id, event }, async (e) => e);
|
|
20831
21021
|
this.tracer?.log("core", { step: "middleware:before", sessionId: this.session.id, hook: "agent:beforeEvent", blocked: !result });
|
|
20832
21022
|
if (!result) return;
|
|
20833
21023
|
const transformedEvent = result.event;
|
|
20834
|
-
|
|
20835
|
-
mw.execute("agent:afterEvent", {
|
|
20836
|
-
sessionId: this.session.id,
|
|
20837
|
-
event: transformedEvent,
|
|
20838
|
-
outgoingMessage: outgoing ?? { type: "text", text: "" }
|
|
20839
|
-
}, async (e) => e).catch(() => {
|
|
20840
|
-
});
|
|
21024
|
+
this.handleAgentEvent(transformedEvent);
|
|
20841
21025
|
} catch {
|
|
20842
21026
|
try {
|
|
20843
21027
|
this.handleAgentEvent(event);
|
|
20844
21028
|
} catch (err) {
|
|
20845
|
-
|
|
21029
|
+
log32.error({ err, sessionId: this.session.id }, "Error handling agent event (middleware fallback)");
|
|
20846
21030
|
}
|
|
20847
21031
|
}
|
|
20848
21032
|
} else {
|
|
20849
21033
|
try {
|
|
20850
21034
|
this.handleAgentEvent(event);
|
|
20851
21035
|
} catch (err) {
|
|
20852
|
-
|
|
21036
|
+
log32.error({ err, sessionId: this.session.id }, "Error handling agent event");
|
|
20853
21037
|
}
|
|
20854
21038
|
}
|
|
20855
21039
|
}
|
|
@@ -20913,7 +21097,7 @@ var init_session_bridge = __esm({
|
|
|
20913
21097
|
text: "",
|
|
20914
21098
|
attachment: att
|
|
20915
21099
|
});
|
|
20916
|
-
}).catch((err) =>
|
|
21100
|
+
}).catch((err) => log32.error({ err }, "Failed to save agent image"));
|
|
20917
21101
|
}
|
|
20918
21102
|
break;
|
|
20919
21103
|
}
|
|
@@ -20930,12 +21114,12 @@ var init_session_bridge = __esm({
|
|
|
20930
21114
|
text: "",
|
|
20931
21115
|
attachment: att
|
|
20932
21116
|
});
|
|
20933
|
-
}).catch((err) =>
|
|
21117
|
+
}).catch((err) => log32.error({ err }, "Failed to save agent audio"));
|
|
20934
21118
|
}
|
|
20935
21119
|
break;
|
|
20936
21120
|
}
|
|
20937
21121
|
case "commands_update":
|
|
20938
|
-
|
|
21122
|
+
log32.debug({ commands: event.commands }, "Commands available");
|
|
20939
21123
|
this.adapter.sendSkillCommands?.(this.session.id, event.commands);
|
|
20940
21124
|
break;
|
|
20941
21125
|
case "system_message":
|
|
@@ -20970,7 +21154,7 @@ var init_session_bridge = __esm({
|
|
|
20970
21154
|
this.adapter.stripTTSBlock?.(this.session.id);
|
|
20971
21155
|
break;
|
|
20972
21156
|
}
|
|
20973
|
-
this.deps.eventBus?.emit(
|
|
21157
|
+
this.deps.eventBus?.emit(BusEvent.AGENT_EVENT, {
|
|
20974
21158
|
sessionId: this.session.id,
|
|
20975
21159
|
event
|
|
20976
21160
|
});
|
|
@@ -20989,7 +21173,7 @@ var init_session_bridge = __esm({
|
|
|
20989
21173
|
let permReq = request;
|
|
20990
21174
|
if (mw) {
|
|
20991
21175
|
const payload = { sessionId: this.session.id, request, autoResolve: void 0 };
|
|
20992
|
-
const result = await mw.execute(
|
|
21176
|
+
const result = await mw.execute(Hook.PERMISSION_BEFORE_REQUEST, payload, async (r) => r);
|
|
20993
21177
|
if (!result) return "";
|
|
20994
21178
|
permReq = result.request;
|
|
20995
21179
|
if (result.autoResolve) {
|
|
@@ -20997,21 +21181,21 @@ var init_session_bridge = __esm({
|
|
|
20997
21181
|
return result.autoResolve;
|
|
20998
21182
|
}
|
|
20999
21183
|
}
|
|
21000
|
-
this.deps.eventBus?.emit(
|
|
21184
|
+
this.deps.eventBus?.emit(BusEvent.PERMISSION_REQUEST, {
|
|
21001
21185
|
sessionId: this.session.id,
|
|
21002
21186
|
permission: permReq
|
|
21003
21187
|
});
|
|
21004
21188
|
const autoDecision = this.checkAutoApprove(permReq);
|
|
21005
21189
|
if (autoDecision) {
|
|
21006
|
-
this.session.emit(
|
|
21190
|
+
this.session.emit(SessionEv.PERMISSION_REQUEST, permReq);
|
|
21007
21191
|
this.emitAfterResolve(mw, permReq.id, autoDecision, "system", startTime);
|
|
21008
21192
|
return autoDecision;
|
|
21009
21193
|
}
|
|
21010
21194
|
const promise = this.session.permissionGate.setPending(permReq);
|
|
21011
|
-
this.session.emit(
|
|
21195
|
+
this.session.emit(SessionEv.PERMISSION_REQUEST, permReq);
|
|
21012
21196
|
await this.adapter.sendPermissionRequest(this.session.id, permReq);
|
|
21013
21197
|
const optionId = await promise;
|
|
21014
|
-
this.deps.eventBus?.emit(
|
|
21198
|
+
this.deps.eventBus?.emit(BusEvent.PERMISSION_RESOLVED, {
|
|
21015
21199
|
sessionId: this.session.id,
|
|
21016
21200
|
requestId: permReq.id,
|
|
21017
21201
|
decision: optionId,
|
|
@@ -21031,7 +21215,7 @@ var init_session_bridge = __esm({
|
|
|
21031
21215
|
if (isAgentBypass || isClientBypass) {
|
|
21032
21216
|
const allowOption = request.options.find((o) => o.isAllow);
|
|
21033
21217
|
if (allowOption) {
|
|
21034
|
-
|
|
21218
|
+
log32.info(
|
|
21035
21219
|
{ sessionId: this.session.id, requestId: request.id, optionId: allowOption.id, agentBypass: !!isAgentBypass, clientBypass: !!isClientBypass },
|
|
21036
21220
|
"Bypass mode: auto-approving permission"
|
|
21037
21221
|
);
|
|
@@ -21043,7 +21227,7 @@ var init_session_bridge = __esm({
|
|
|
21043
21227
|
/** Emit permission:afterResolve middleware hook (fire-and-forget) */
|
|
21044
21228
|
emitAfterResolve(mw, requestId, decision, userId, startTime) {
|
|
21045
21229
|
if (mw) {
|
|
21046
|
-
mw.execute(
|
|
21230
|
+
mw.execute(Hook.PERMISSION_AFTER_RESOLVE, {
|
|
21047
21231
|
sessionId: this.session.id,
|
|
21048
21232
|
requestId,
|
|
21049
21233
|
decision,
|
|
@@ -21204,13 +21388,13 @@ function computeLineDiff(oldStr, newStr) {
|
|
|
21204
21388
|
removed: Math.max(0, oldLines.length - prefixLen - suffixLen)
|
|
21205
21389
|
};
|
|
21206
21390
|
}
|
|
21207
|
-
var
|
|
21391
|
+
var log33, BINARY_VIEWER_EXTENSIONS, MessageTransformer;
|
|
21208
21392
|
var init_message_transformer = __esm({
|
|
21209
21393
|
"src/core/message-transformer.ts"() {
|
|
21210
21394
|
"use strict";
|
|
21211
21395
|
init_extract_file_info();
|
|
21212
21396
|
init_log();
|
|
21213
|
-
|
|
21397
|
+
log33 = createChildLogger({ module: "message-transformer" });
|
|
21214
21398
|
BINARY_VIEWER_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
21215
21399
|
".wav",
|
|
21216
21400
|
".ogg",
|
|
@@ -21413,14 +21597,14 @@ var init_message_transformer = __esm({
|
|
|
21413
21597
|
}
|
|
21414
21598
|
}
|
|
21415
21599
|
if (!this.tunnelService || !sessionContext) {
|
|
21416
|
-
|
|
21600
|
+
log33.debug(
|
|
21417
21601
|
{ hasTunnel: !!this.tunnelService, hasCtx: !!sessionContext, kind },
|
|
21418
21602
|
"enrichWithViewerLinks: skipping (no tunnel or session context)"
|
|
21419
21603
|
);
|
|
21420
21604
|
return;
|
|
21421
21605
|
}
|
|
21422
21606
|
const name = "name" in event ? event.name || "" : "";
|
|
21423
|
-
|
|
21607
|
+
log33.debug(
|
|
21424
21608
|
{ name, kind, status: event.status, hasContent: !!event.content, hasRawInput: !!event.rawInput },
|
|
21425
21609
|
"enrichWithViewerLinks: inspecting event"
|
|
21426
21610
|
);
|
|
@@ -21432,7 +21616,7 @@ var init_message_transformer = __esm({
|
|
|
21432
21616
|
event.meta
|
|
21433
21617
|
);
|
|
21434
21618
|
if (!fileInfo) {
|
|
21435
|
-
|
|
21619
|
+
log33.debug(
|
|
21436
21620
|
{ name, kind, hasContent: !!event.content, hasRawInput: !!event.rawInput, hasMeta: !!event.meta },
|
|
21437
21621
|
"enrichWithViewerLinks: extractFileInfo returned null"
|
|
21438
21622
|
);
|
|
@@ -21440,15 +21624,15 @@ var init_message_transformer = __esm({
|
|
|
21440
21624
|
}
|
|
21441
21625
|
const fileExt = path45.extname(fileInfo.filePath).toLowerCase();
|
|
21442
21626
|
if (BINARY_VIEWER_EXTENSIONS.has(fileExt)) {
|
|
21443
|
-
|
|
21627
|
+
log33.debug({ kind, filePath: fileInfo.filePath }, "enrichWithViewerLinks: skipping binary file");
|
|
21444
21628
|
return;
|
|
21445
21629
|
}
|
|
21446
21630
|
const publicUrl = this.tunnelService.getPublicUrl();
|
|
21447
21631
|
if (publicUrl.startsWith("http://localhost") || publicUrl.startsWith("http://127.0.0.1")) {
|
|
21448
|
-
|
|
21632
|
+
log33.debug({ kind, filePath: fileInfo.filePath }, "enrichWithViewerLinks: skipping (no public tunnel URL)");
|
|
21449
21633
|
return;
|
|
21450
21634
|
}
|
|
21451
|
-
|
|
21635
|
+
log33.info(
|
|
21452
21636
|
{
|
|
21453
21637
|
name,
|
|
21454
21638
|
kind,
|
|
@@ -21494,12 +21678,12 @@ var init_message_transformer = __esm({
|
|
|
21494
21678
|
// src/core/sessions/session-store.ts
|
|
21495
21679
|
import fs42 from "fs";
|
|
21496
21680
|
import path46 from "path";
|
|
21497
|
-
var
|
|
21681
|
+
var log34, DEBOUNCE_MS3, JsonFileSessionStore;
|
|
21498
21682
|
var init_session_store = __esm({
|
|
21499
21683
|
"src/core/sessions/session-store.ts"() {
|
|
21500
21684
|
"use strict";
|
|
21501
21685
|
init_log();
|
|
21502
|
-
|
|
21686
|
+
log34 = createChildLogger({ module: "session-store" });
|
|
21503
21687
|
DEBOUNCE_MS3 = 2e3;
|
|
21504
21688
|
JsonFileSessionStore = class {
|
|
21505
21689
|
records = /* @__PURE__ */ new Map();
|
|
@@ -21551,6 +21735,14 @@ var init_session_store = __esm({
|
|
|
21551
21735
|
}
|
|
21552
21736
|
return void 0;
|
|
21553
21737
|
}
|
|
21738
|
+
findAssistant(channelId) {
|
|
21739
|
+
for (const record of this.records.values()) {
|
|
21740
|
+
if (record.isAssistant === true && record.channelId === channelId) {
|
|
21741
|
+
return record;
|
|
21742
|
+
}
|
|
21743
|
+
}
|
|
21744
|
+
return void 0;
|
|
21745
|
+
}
|
|
21554
21746
|
list(channelId) {
|
|
21555
21747
|
const all = [...this.records.values()];
|
|
21556
21748
|
if (channelId) return all.filter((r) => r.channelId === channelId);
|
|
@@ -21593,7 +21785,7 @@ var init_session_store = __esm({
|
|
|
21593
21785
|
fs42.readFileSync(this.filePath, "utf-8")
|
|
21594
21786
|
);
|
|
21595
21787
|
if (raw.version !== 1) {
|
|
21596
|
-
|
|
21788
|
+
log34.warn(
|
|
21597
21789
|
{ version: raw.version },
|
|
21598
21790
|
"Unknown session store version, skipping load"
|
|
21599
21791
|
);
|
|
@@ -21602,9 +21794,9 @@ var init_session_store = __esm({
|
|
|
21602
21794
|
for (const [id, record] of Object.entries(raw.sessions)) {
|
|
21603
21795
|
this.records.set(id, this.migrateRecord(record));
|
|
21604
21796
|
}
|
|
21605
|
-
|
|
21797
|
+
log34.debug({ count: this.records.size }, "Loaded session records");
|
|
21606
21798
|
} catch (err) {
|
|
21607
|
-
|
|
21799
|
+
log34.error({ err }, "Failed to load session store, backing up corrupt file");
|
|
21608
21800
|
try {
|
|
21609
21801
|
fs42.renameSync(this.filePath, `${this.filePath}.bak`);
|
|
21610
21802
|
} catch {
|
|
@@ -21630,6 +21822,8 @@ var init_session_store = __esm({
|
|
|
21630
21822
|
for (const [id, record] of this.records) {
|
|
21631
21823
|
if (record.status === "active" || record.status === "initializing")
|
|
21632
21824
|
continue;
|
|
21825
|
+
if (record.isAssistant === true)
|
|
21826
|
+
continue;
|
|
21633
21827
|
const raw = record.lastActiveAt;
|
|
21634
21828
|
if (!raw) continue;
|
|
21635
21829
|
const lastActive = new Date(raw).getTime();
|
|
@@ -21640,7 +21834,7 @@ var init_session_store = __esm({
|
|
|
21640
21834
|
}
|
|
21641
21835
|
}
|
|
21642
21836
|
if (removed > 0) {
|
|
21643
|
-
|
|
21837
|
+
log34.info({ removed }, "Cleaned up expired session records");
|
|
21644
21838
|
this.scheduleDiskWrite();
|
|
21645
21839
|
}
|
|
21646
21840
|
}
|
|
@@ -21655,13 +21849,14 @@ var init_session_store = __esm({
|
|
|
21655
21849
|
});
|
|
21656
21850
|
|
|
21657
21851
|
// src/core/sessions/session-factory.ts
|
|
21658
|
-
var
|
|
21852
|
+
var log35, SessionFactory;
|
|
21659
21853
|
var init_session_factory = __esm({
|
|
21660
21854
|
"src/core/sessions/session-factory.ts"() {
|
|
21661
21855
|
"use strict";
|
|
21662
21856
|
init_session2();
|
|
21663
21857
|
init_log();
|
|
21664
|
-
|
|
21858
|
+
init_events();
|
|
21859
|
+
log35 = createChildLogger({ module: "session-factory" });
|
|
21665
21860
|
SessionFactory = class {
|
|
21666
21861
|
constructor(agentManager, sessionManager, speechServiceAccessor, eventBus, instanceRoot) {
|
|
21667
21862
|
this.agentManager = agentManager;
|
|
@@ -21703,7 +21898,7 @@ var init_session_factory = __esm({
|
|
|
21703
21898
|
threadId: ""
|
|
21704
21899
|
// threadId is assigned after session creation
|
|
21705
21900
|
};
|
|
21706
|
-
const result = await this.middlewareChain.execute(
|
|
21901
|
+
const result = await this.middlewareChain.execute(Hook.SESSION_BEFORE_CREATE, payload, async (p2) => p2);
|
|
21707
21902
|
if (!result) throw new Error("Session creation blocked by middleware");
|
|
21708
21903
|
createParams = {
|
|
21709
21904
|
...params,
|
|
@@ -21712,6 +21907,7 @@ var init_session_factory = __esm({
|
|
|
21712
21907
|
channelId: result.channelId
|
|
21713
21908
|
};
|
|
21714
21909
|
}
|
|
21910
|
+
const configAllowedPaths = this.configManager?.get().workspace?.security?.allowedPaths ?? [];
|
|
21715
21911
|
let agentInstance;
|
|
21716
21912
|
try {
|
|
21717
21913
|
if (createParams.resumeAgentSessionId) {
|
|
@@ -21719,22 +21915,25 @@ var init_session_factory = __esm({
|
|
|
21719
21915
|
agentInstance = await this.agentManager.resume(
|
|
21720
21916
|
createParams.agentName,
|
|
21721
21917
|
createParams.workingDirectory,
|
|
21722
|
-
createParams.resumeAgentSessionId
|
|
21918
|
+
createParams.resumeAgentSessionId,
|
|
21919
|
+
configAllowedPaths
|
|
21723
21920
|
);
|
|
21724
21921
|
} catch (resumeErr) {
|
|
21725
|
-
|
|
21922
|
+
log35.warn(
|
|
21726
21923
|
{ agentName: createParams.agentName, resumeErr },
|
|
21727
21924
|
"Agent session resume failed, falling back to fresh spawn"
|
|
21728
21925
|
);
|
|
21729
21926
|
agentInstance = await this.agentManager.spawn(
|
|
21730
21927
|
createParams.agentName,
|
|
21731
|
-
createParams.workingDirectory
|
|
21928
|
+
createParams.workingDirectory,
|
|
21929
|
+
configAllowedPaths
|
|
21732
21930
|
);
|
|
21733
21931
|
}
|
|
21734
21932
|
} else {
|
|
21735
21933
|
agentInstance = await this.agentManager.spawn(
|
|
21736
21934
|
createParams.agentName,
|
|
21737
|
-
createParams.workingDirectory
|
|
21935
|
+
createParams.workingDirectory,
|
|
21936
|
+
configAllowedPaths
|
|
21738
21937
|
);
|
|
21739
21938
|
}
|
|
21740
21939
|
} catch (err) {
|
|
@@ -21766,7 +21965,7 @@ var init_session_factory = __esm({
|
|
|
21766
21965
|
message: guidanceLines.join("\n")
|
|
21767
21966
|
};
|
|
21768
21967
|
const failedSessionId = createParams.existingSessionId ?? `failed-${Date.now()}`;
|
|
21769
|
-
this.eventBus.emit(
|
|
21968
|
+
this.eventBus.emit(BusEvent.AGENT_EVENT, {
|
|
21770
21969
|
sessionId: failedSessionId,
|
|
21771
21970
|
event: guidance
|
|
21772
21971
|
});
|
|
@@ -21792,11 +21991,13 @@ var init_session_factory = __esm({
|
|
|
21792
21991
|
}
|
|
21793
21992
|
session.applySpawnResponse(agentInstance.initialSessionResponse, agentInstance.agentCapabilities);
|
|
21794
21993
|
this.sessionManager.registerSession(session);
|
|
21795
|
-
|
|
21796
|
-
|
|
21797
|
-
|
|
21798
|
-
|
|
21799
|
-
|
|
21994
|
+
if (!session.isAssistant) {
|
|
21995
|
+
this.eventBus.emit(BusEvent.SESSION_CREATED, {
|
|
21996
|
+
sessionId: session.id,
|
|
21997
|
+
agent: session.agentName,
|
|
21998
|
+
status: session.status
|
|
21999
|
+
});
|
|
22000
|
+
}
|
|
21800
22001
|
return session;
|
|
21801
22002
|
}
|
|
21802
22003
|
/**
|
|
@@ -21814,6 +22015,7 @@ var init_session_factory = __esm({
|
|
|
21814
22015
|
if (!this.sessionStore || !this.createFullSession) return null;
|
|
21815
22016
|
const record = this.sessionStore.get(sessionId);
|
|
21816
22017
|
if (!record) return null;
|
|
22018
|
+
if (record.isAssistant) return null;
|
|
21817
22019
|
if (record.status === "error" || record.status === "cancelled") return null;
|
|
21818
22020
|
const existing = this.resumeLocks.get(sessionId);
|
|
21819
22021
|
if (existing) return existing;
|
|
@@ -21855,10 +22057,10 @@ var init_session_factory = __esm({
|
|
|
21855
22057
|
session.setAgentCapabilities(record.acpState.agentCapabilities);
|
|
21856
22058
|
}
|
|
21857
22059
|
}
|
|
21858
|
-
|
|
22060
|
+
log35.info({ sessionId }, "Lazy resume by ID successful");
|
|
21859
22061
|
return session;
|
|
21860
22062
|
} catch (err) {
|
|
21861
|
-
|
|
22063
|
+
log35.error({ err, sessionId }, "Lazy resume by ID failed");
|
|
21862
22064
|
return null;
|
|
21863
22065
|
} finally {
|
|
21864
22066
|
this.resumeLocks.delete(sessionId);
|
|
@@ -21878,18 +22080,19 @@ var init_session_factory = __esm({
|
|
|
21878
22080
|
(p2) => String(p2.topicId) === threadId || String(p2.threadId ?? "") === threadId
|
|
21879
22081
|
);
|
|
21880
22082
|
if (!record) {
|
|
21881
|
-
|
|
22083
|
+
log35.debug({ threadId, channelId }, "No session record found for thread");
|
|
21882
22084
|
return null;
|
|
21883
22085
|
}
|
|
22086
|
+
if (record.isAssistant) return null;
|
|
21884
22087
|
if (record.status === "error" || record.status === "cancelled") {
|
|
21885
|
-
|
|
22088
|
+
log35.warn(
|
|
21886
22089
|
{ threadId, sessionId: record.sessionId, status: record.status },
|
|
21887
22090
|
"Session record found but skipped (status: %s) \u2014 use /new to start a fresh session",
|
|
21888
22091
|
record.status
|
|
21889
22092
|
);
|
|
21890
22093
|
return null;
|
|
21891
22094
|
}
|
|
21892
|
-
|
|
22095
|
+
log35.info({ threadId, sessionId: record.sessionId, status: record.status }, "Lazy resume: found record, attempting resume");
|
|
21893
22096
|
const resumePromise = (async () => {
|
|
21894
22097
|
try {
|
|
21895
22098
|
const session = await this.createFullSession({
|
|
@@ -21930,7 +22133,7 @@ var init_session_factory = __esm({
|
|
|
21930
22133
|
}
|
|
21931
22134
|
const resumeFalledBack = record.agentSessionId && session.agentSessionId !== record.agentSessionId;
|
|
21932
22135
|
if (resumeFalledBack) {
|
|
21933
|
-
|
|
22136
|
+
log35.info({ sessionId: session.id }, "Resume fell back to fresh spawn \u2014 injecting conversation history");
|
|
21934
22137
|
const contextManager = this.getContextManager?.();
|
|
21935
22138
|
if (contextManager) {
|
|
21936
22139
|
try {
|
|
@@ -21947,10 +22150,10 @@ var init_session_factory = __esm({
|
|
|
21947
22150
|
}
|
|
21948
22151
|
}
|
|
21949
22152
|
}
|
|
21950
|
-
|
|
22153
|
+
log35.info({ sessionId: session.id, threadId }, "Lazy resume successful");
|
|
21951
22154
|
return session;
|
|
21952
22155
|
} catch (err) {
|
|
21953
|
-
|
|
22156
|
+
log35.error({ err, record }, "Lazy resume failed");
|
|
21954
22157
|
const adapter = this.adapters?.get(channelId);
|
|
21955
22158
|
if (adapter) {
|
|
21956
22159
|
try {
|
|
@@ -21975,7 +22178,7 @@ var init_session_factory = __esm({
|
|
|
21975
22178
|
}
|
|
21976
22179
|
const config = this.configManager.get();
|
|
21977
22180
|
const resolvedAgent = agentName || config.defaultAgent;
|
|
21978
|
-
|
|
22181
|
+
log35.info({ channelId, agentName: resolvedAgent }, "New session request");
|
|
21979
22182
|
const agentDef = this.agentCatalog.resolve(resolvedAgent);
|
|
21980
22183
|
const resolvedWorkspace = this.configManager.resolveWorkspace(
|
|
21981
22184
|
workspacePath || agentDef?.workingDirectory
|
|
@@ -22024,7 +22227,7 @@ var init_session_factory = __esm({
|
|
|
22024
22227
|
params.contextOptions
|
|
22025
22228
|
);
|
|
22026
22229
|
} catch (err) {
|
|
22027
|
-
|
|
22230
|
+
log35.warn({ err }, "Context building failed, proceeding without context");
|
|
22028
22231
|
}
|
|
22029
22232
|
}
|
|
22030
22233
|
const session = await this.createFullSession({
|
|
@@ -22040,9 +22243,9 @@ var init_session_factory = __esm({
|
|
|
22040
22243
|
return { session, contextResult };
|
|
22041
22244
|
}
|
|
22042
22245
|
wireSideEffects(session, deps) {
|
|
22043
|
-
session.on(
|
|
22246
|
+
session.on(SessionEv.AGENT_EVENT, (event) => {
|
|
22044
22247
|
if (event.type !== "usage") return;
|
|
22045
|
-
deps.eventBus.emit(
|
|
22248
|
+
deps.eventBus.emit(BusEvent.USAGE_RECORDED, {
|
|
22046
22249
|
sessionId: session.id,
|
|
22047
22250
|
agentName: session.agentName,
|
|
22048
22251
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -22051,7 +22254,7 @@ var init_session_factory = __esm({
|
|
|
22051
22254
|
cost: event.cost
|
|
22052
22255
|
});
|
|
22053
22256
|
});
|
|
22054
|
-
session.on(
|
|
22257
|
+
session.on(SessionEv.STATUS_CHANGE, (_from, to) => {
|
|
22055
22258
|
if ((to === "finished" || to === "cancelled") && deps.tunnelService) {
|
|
22056
22259
|
deps.tunnelService.stopBySession(session.id).then((stopped) => {
|
|
22057
22260
|
for (const entry of stopped) {
|
|
@@ -22073,13 +22276,14 @@ var init_session_factory = __esm({
|
|
|
22073
22276
|
});
|
|
22074
22277
|
|
|
22075
22278
|
// src/core/agent-switch-handler.ts
|
|
22076
|
-
var
|
|
22279
|
+
var log36, AgentSwitchHandler;
|
|
22077
22280
|
var init_agent_switch_handler = __esm({
|
|
22078
22281
|
"src/core/agent-switch-handler.ts"() {
|
|
22079
22282
|
"use strict";
|
|
22080
22283
|
init_agent_registry();
|
|
22081
22284
|
init_log();
|
|
22082
|
-
|
|
22285
|
+
init_events();
|
|
22286
|
+
log36 = createChildLogger({ module: "agent-switch" });
|
|
22083
22287
|
AgentSwitchHandler = class {
|
|
22084
22288
|
constructor(deps) {
|
|
22085
22289
|
this.deps = deps;
|
|
@@ -22104,7 +22308,7 @@ var init_agent_switch_handler = __esm({
|
|
|
22104
22308
|
if (!agentDef) throw new Error(`Agent "${toAgent}" is not installed`);
|
|
22105
22309
|
const fromAgent = session.agentName;
|
|
22106
22310
|
const middlewareChain = this.deps.getMiddlewareChain();
|
|
22107
|
-
const result = await middlewareChain?.execute(
|
|
22311
|
+
const result = await middlewareChain?.execute(Hook.AGENT_BEFORE_SWITCH, {
|
|
22108
22312
|
sessionId,
|
|
22109
22313
|
fromAgent,
|
|
22110
22314
|
toAgent
|
|
@@ -22118,9 +22322,9 @@ var init_agent_switch_handler = __esm({
|
|
|
22118
22322
|
type: "system_message",
|
|
22119
22323
|
message: `Switching from ${fromAgent} to ${toAgent}...`
|
|
22120
22324
|
};
|
|
22121
|
-
session.emit(
|
|
22122
|
-
eventBus.emit(
|
|
22123
|
-
eventBus.emit(
|
|
22325
|
+
session.emit(SessionEv.AGENT_EVENT, startEvent);
|
|
22326
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: startEvent });
|
|
22327
|
+
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
22124
22328
|
sessionId,
|
|
22125
22329
|
fromAgent,
|
|
22126
22330
|
toAgent,
|
|
@@ -22144,19 +22348,20 @@ var init_agent_switch_handler = __esm({
|
|
|
22144
22348
|
}
|
|
22145
22349
|
const fromAgentSessionId = session.agentSessionId;
|
|
22146
22350
|
const fileService = this.deps.getService("file-service");
|
|
22351
|
+
const configAllowedPaths = configManager.get().workspace?.security?.allowedPaths ?? [];
|
|
22147
22352
|
try {
|
|
22148
22353
|
await session.switchAgent(toAgent, async () => {
|
|
22149
22354
|
if (canResume) {
|
|
22150
22355
|
try {
|
|
22151
|
-
const instance2 = await agentManager.resume(toAgent, session.workingDirectory, lastEntry.agentSessionId);
|
|
22356
|
+
const instance2 = await agentManager.resume(toAgent, session.workingDirectory, lastEntry.agentSessionId, configAllowedPaths);
|
|
22152
22357
|
if (fileService) instance2.addAllowedPath(fileService.baseDir);
|
|
22153
22358
|
resumed = true;
|
|
22154
22359
|
return instance2;
|
|
22155
22360
|
} catch {
|
|
22156
|
-
|
|
22361
|
+
log36.warn({ sessionId, toAgent }, "Resume failed, falling back to new agent with context injection");
|
|
22157
22362
|
}
|
|
22158
22363
|
}
|
|
22159
|
-
const instance = await agentManager.spawn(toAgent, session.workingDirectory);
|
|
22364
|
+
const instance = await agentManager.spawn(toAgent, session.workingDirectory, configAllowedPaths);
|
|
22160
22365
|
if (fileService) instance.addAllowedPath(fileService.baseDir);
|
|
22161
22366
|
try {
|
|
22162
22367
|
const contextService = this.deps.getService("context");
|
|
@@ -22180,9 +22385,9 @@ var init_agent_switch_handler = __esm({
|
|
|
22180
22385
|
type: "system_message",
|
|
22181
22386
|
message: resumed ? `Switched to ${toAgent} (resumed previous session).` : `Switched to ${toAgent} (new session).`
|
|
22182
22387
|
};
|
|
22183
|
-
session.emit(
|
|
22184
|
-
eventBus.emit(
|
|
22185
|
-
eventBus.emit(
|
|
22388
|
+
session.emit(SessionEv.AGENT_EVENT, successEvent);
|
|
22389
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: successEvent });
|
|
22390
|
+
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
22186
22391
|
sessionId,
|
|
22187
22392
|
fromAgent,
|
|
22188
22393
|
toAgent,
|
|
@@ -22195,9 +22400,9 @@ var init_agent_switch_handler = __esm({
|
|
|
22195
22400
|
type: "system_message",
|
|
22196
22401
|
message: `Failed to switch to ${toAgent}: ${errorMessage}`
|
|
22197
22402
|
};
|
|
22198
|
-
session.emit(
|
|
22199
|
-
eventBus.emit(
|
|
22200
|
-
eventBus.emit(
|
|
22403
|
+
session.emit(SessionEv.AGENT_EVENT, failedEvent);
|
|
22404
|
+
eventBus.emit(BusEvent.AGENT_EVENT, { sessionId, event: failedEvent });
|
|
22405
|
+
eventBus.emit(BusEvent.SESSION_AGENT_SWITCH, {
|
|
22201
22406
|
sessionId,
|
|
22202
22407
|
fromAgent,
|
|
22203
22408
|
toAgent,
|
|
@@ -22222,10 +22427,10 @@ var init_agent_switch_handler = __esm({
|
|
|
22222
22427
|
createBridge(session, adapter, adapterId).connect();
|
|
22223
22428
|
}
|
|
22224
22429
|
}
|
|
22225
|
-
|
|
22430
|
+
log36.warn({ sessionId, fromAgent, toAgent, err }, "Agent switch failed, rolled back to previous agent");
|
|
22226
22431
|
} catch (rollbackErr) {
|
|
22227
22432
|
session.fail(`Switch failed and rollback failed: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`);
|
|
22228
|
-
|
|
22433
|
+
log36.error({ sessionId, fromAgent, toAgent, err, rollbackErr }, "Agent switch failed and rollback also failed");
|
|
22229
22434
|
}
|
|
22230
22435
|
throw err;
|
|
22231
22436
|
}
|
|
@@ -22235,7 +22440,7 @@ var init_agent_switch_handler = __esm({
|
|
|
22235
22440
|
if (adapter) {
|
|
22236
22441
|
createBridge(session, adapter, adapterId).connect();
|
|
22237
22442
|
} else {
|
|
22238
|
-
|
|
22443
|
+
log36.warn({ sessionId, adapterId }, "Adapter not available during switch reconnect, skipping bridge");
|
|
22239
22444
|
}
|
|
22240
22445
|
}
|
|
22241
22446
|
}
|
|
@@ -22246,7 +22451,7 @@ var init_agent_switch_handler = __esm({
|
|
|
22246
22451
|
currentPromptCount: 0,
|
|
22247
22452
|
agentSwitchHistory: session.agentSwitchHistory
|
|
22248
22453
|
});
|
|
22249
|
-
middlewareChain?.execute(
|
|
22454
|
+
middlewareChain?.execute(Hook.AGENT_AFTER_SWITCH, {
|
|
22250
22455
|
sessionId,
|
|
22251
22456
|
fromAgent,
|
|
22252
22457
|
toAgent,
|
|
@@ -22268,12 +22473,12 @@ import * as fs43 from "fs";
|
|
|
22268
22473
|
import * as path47 from "path";
|
|
22269
22474
|
import * as os20 from "os";
|
|
22270
22475
|
import { z as z10 } from "zod";
|
|
22271
|
-
var
|
|
22476
|
+
var log37, InstalledAgentSchema, AgentStoreSchema, AgentStore;
|
|
22272
22477
|
var init_agent_store = __esm({
|
|
22273
22478
|
"src/core/agents/agent-store.ts"() {
|
|
22274
22479
|
"use strict";
|
|
22275
22480
|
init_log();
|
|
22276
|
-
|
|
22481
|
+
log37 = createChildLogger({ module: "agent-store" });
|
|
22277
22482
|
InstalledAgentSchema = z10.object({
|
|
22278
22483
|
registryId: z10.string().nullable(),
|
|
22279
22484
|
name: z10.string(),
|
|
@@ -22307,11 +22512,11 @@ var init_agent_store = __esm({
|
|
|
22307
22512
|
if (result.success) {
|
|
22308
22513
|
this.data = result.data;
|
|
22309
22514
|
} else {
|
|
22310
|
-
|
|
22515
|
+
log37.warn({ errors: result.error.issues }, "Invalid agents.json, starting fresh");
|
|
22311
22516
|
this.data = { version: 1, installed: {} };
|
|
22312
22517
|
}
|
|
22313
22518
|
} catch (err) {
|
|
22314
|
-
|
|
22519
|
+
log37.warn({ err }, "Failed to read agents.json, starting fresh");
|
|
22315
22520
|
this.data = { version: 1, installed: {} };
|
|
22316
22521
|
}
|
|
22317
22522
|
}
|
|
@@ -22353,7 +22558,7 @@ __export(agent_catalog_exports, {
|
|
|
22353
22558
|
import * as fs44 from "fs";
|
|
22354
22559
|
import * as path48 from "path";
|
|
22355
22560
|
import * as os21 from "os";
|
|
22356
|
-
var
|
|
22561
|
+
var log38, REGISTRY_URL2, DEFAULT_TTL_HOURS, AgentCatalog;
|
|
22357
22562
|
var init_agent_catalog = __esm({
|
|
22358
22563
|
"src/core/agents/agent-catalog.ts"() {
|
|
22359
22564
|
"use strict";
|
|
@@ -22361,7 +22566,7 @@ var init_agent_catalog = __esm({
|
|
|
22361
22566
|
init_agent_installer();
|
|
22362
22567
|
init_agent_dependencies();
|
|
22363
22568
|
init_log();
|
|
22364
|
-
|
|
22569
|
+
log38 = createChildLogger({ module: "agent-catalog" });
|
|
22365
22570
|
REGISTRY_URL2 = "https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json";
|
|
22366
22571
|
DEFAULT_TTL_HOURS = 24;
|
|
22367
22572
|
AgentCatalog = class {
|
|
@@ -22382,7 +22587,7 @@ var init_agent_catalog = __esm({
|
|
|
22382
22587
|
// --- Registry ---
|
|
22383
22588
|
async fetchRegistry() {
|
|
22384
22589
|
try {
|
|
22385
|
-
|
|
22590
|
+
log38.info("Fetching agent registry from CDN...");
|
|
22386
22591
|
const response = await fetch(REGISTRY_URL2);
|
|
22387
22592
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
22388
22593
|
const data = await response.json();
|
|
@@ -22394,9 +22599,9 @@ var init_agent_catalog = __esm({
|
|
|
22394
22599
|
};
|
|
22395
22600
|
fs44.mkdirSync(path48.dirname(this.cachePath), { recursive: true });
|
|
22396
22601
|
fs44.writeFileSync(this.cachePath, JSON.stringify(cache, null, 2), { mode: 384 });
|
|
22397
|
-
|
|
22602
|
+
log38.info({ count: this.registryAgents.length }, "Registry updated");
|
|
22398
22603
|
} catch (err) {
|
|
22399
|
-
|
|
22604
|
+
log38.warn({ err }, "Failed to fetch registry, using cached data");
|
|
22400
22605
|
}
|
|
22401
22606
|
}
|
|
22402
22607
|
async refreshRegistryIfStale() {
|
|
@@ -22557,7 +22762,7 @@ var init_agent_catalog = __esm({
|
|
|
22557
22762
|
}
|
|
22558
22763
|
}
|
|
22559
22764
|
if (changed) {
|
|
22560
|
-
|
|
22765
|
+
log38.info("Enriched installed agents with registry data");
|
|
22561
22766
|
}
|
|
22562
22767
|
}
|
|
22563
22768
|
isCacheStale() {
|
|
@@ -22577,11 +22782,11 @@ var init_agent_catalog = __esm({
|
|
|
22577
22782
|
const raw = JSON.parse(fs44.readFileSync(this.cachePath, "utf-8"));
|
|
22578
22783
|
if (raw.data?.agents) {
|
|
22579
22784
|
this.registryAgents = raw.data.agents;
|
|
22580
|
-
|
|
22785
|
+
log38.debug({ count: this.registryAgents.length }, "Loaded registry from cache");
|
|
22581
22786
|
return;
|
|
22582
22787
|
}
|
|
22583
22788
|
} catch {
|
|
22584
|
-
|
|
22789
|
+
log38.warn("Failed to load registry cache");
|
|
22585
22790
|
}
|
|
22586
22791
|
}
|
|
22587
22792
|
try {
|
|
@@ -22594,13 +22799,13 @@ var init_agent_catalog = __esm({
|
|
|
22594
22799
|
if (fs44.existsSync(candidate)) {
|
|
22595
22800
|
const raw = JSON.parse(fs44.readFileSync(candidate, "utf-8"));
|
|
22596
22801
|
this.registryAgents = raw.agents ?? [];
|
|
22597
|
-
|
|
22802
|
+
log38.debug({ count: this.registryAgents.length }, "Loaded registry from bundled snapshot");
|
|
22598
22803
|
return;
|
|
22599
22804
|
}
|
|
22600
22805
|
}
|
|
22601
|
-
|
|
22806
|
+
log38.warn("No registry data available (no cache, no snapshot)");
|
|
22602
22807
|
} catch {
|
|
22603
|
-
|
|
22808
|
+
log38.warn("Failed to load bundled registry snapshot");
|
|
22604
22809
|
}
|
|
22605
22810
|
}
|
|
22606
22811
|
};
|
|
@@ -22986,7 +23191,7 @@ function createPluginContext(opts) {
|
|
|
22986
23191
|
}
|
|
22987
23192
|
};
|
|
22988
23193
|
const baseLog = opts.log ?? noopLog;
|
|
22989
|
-
const
|
|
23194
|
+
const log47 = typeof baseLog.child === "function" ? baseLog.child({ plugin: pluginName }) : baseLog;
|
|
22990
23195
|
const storageImpl = new PluginStorageImpl(storagePath);
|
|
22991
23196
|
const storage = {
|
|
22992
23197
|
async get(key) {
|
|
@@ -23013,7 +23218,7 @@ function createPluginContext(opts) {
|
|
|
23013
23218
|
const ctx = {
|
|
23014
23219
|
pluginName,
|
|
23015
23220
|
pluginConfig,
|
|
23016
|
-
log:
|
|
23221
|
+
log: log47,
|
|
23017
23222
|
storage,
|
|
23018
23223
|
on(event, handler) {
|
|
23019
23224
|
requirePermission(permissions, "events:read", "on()");
|
|
@@ -23048,7 +23253,7 @@ function createPluginContext(opts) {
|
|
|
23048
23253
|
const registry = serviceRegistry.get("command-registry");
|
|
23049
23254
|
if (registry && typeof registry.register === "function") {
|
|
23050
23255
|
registry.register(def, pluginName);
|
|
23051
|
-
|
|
23256
|
+
log47.debug(`Command '/${def.name}' registered`);
|
|
23052
23257
|
}
|
|
23053
23258
|
},
|
|
23054
23259
|
async sendMessage(_sessionId, _content) {
|
|
@@ -23091,7 +23296,7 @@ function createPluginContext(opts) {
|
|
|
23091
23296
|
const registry = serviceRegistry.get("field-registry");
|
|
23092
23297
|
if (registry && typeof registry.register === "function") {
|
|
23093
23298
|
registry.register(pluginName, fields);
|
|
23094
|
-
|
|
23299
|
+
log47.debug(`Registered ${fields.length} editable field(s) for ${pluginName}`);
|
|
23095
23300
|
}
|
|
23096
23301
|
},
|
|
23097
23302
|
get sessions() {
|
|
@@ -23197,6 +23402,7 @@ var init_lifecycle_manager = __esm({
|
|
|
23197
23402
|
init_middleware_chain();
|
|
23198
23403
|
init_error_tracker();
|
|
23199
23404
|
init_plugin_context();
|
|
23405
|
+
init_events();
|
|
23200
23406
|
SETUP_TIMEOUT_MS = 3e4;
|
|
23201
23407
|
TEARDOWN_TIMEOUT_MS = 1e4;
|
|
23202
23408
|
LifecycleManager = class {
|
|
@@ -23303,7 +23509,7 @@ var init_lifecycle_manager = __esm({
|
|
|
23303
23509
|
}
|
|
23304
23510
|
const registryEntry = this.pluginRegistry?.get(plugin2.name);
|
|
23305
23511
|
if (registryEntry && registryEntry.enabled === false) {
|
|
23306
|
-
this.eventBus?.emit(
|
|
23512
|
+
this.eventBus?.emit(BusEvent.PLUGIN_DISABLED, { name: plugin2.name });
|
|
23307
23513
|
continue;
|
|
23308
23514
|
}
|
|
23309
23515
|
if (registryEntry && plugin2.migrate && registryEntry.version !== plugin2.version && this.settingsManager) {
|
|
@@ -23346,7 +23552,7 @@ var init_lifecycle_manager = __esm({
|
|
|
23346
23552
|
if (!validation.valid) {
|
|
23347
23553
|
this._failed.add(plugin2.name);
|
|
23348
23554
|
this.getPluginLogger(plugin2.name).error(`Settings validation failed: ${validation.errors?.join("; ")}`);
|
|
23349
|
-
this.eventBus?.emit(
|
|
23555
|
+
this.eventBus?.emit(BusEvent.PLUGIN_FAILED, { name: plugin2.name, error: `Settings validation failed: ${validation.errors?.join("; ")}` });
|
|
23350
23556
|
continue;
|
|
23351
23557
|
}
|
|
23352
23558
|
}
|
|
@@ -23369,13 +23575,13 @@ var init_lifecycle_manager = __esm({
|
|
|
23369
23575
|
await withTimeout(plugin2.setup(ctx), SETUP_TIMEOUT_MS, `${plugin2.name}.setup()`);
|
|
23370
23576
|
this.contexts.set(plugin2.name, ctx);
|
|
23371
23577
|
this._loaded.add(plugin2.name);
|
|
23372
|
-
this.eventBus?.emit(
|
|
23578
|
+
this.eventBus?.emit(BusEvent.PLUGIN_LOADED, { name: plugin2.name, version: plugin2.version });
|
|
23373
23579
|
} catch (err) {
|
|
23374
23580
|
this._failed.add(plugin2.name);
|
|
23375
23581
|
ctx.cleanup();
|
|
23376
23582
|
console.error(`[lifecycle] Plugin ${plugin2.name} setup() FAILED:`, err);
|
|
23377
23583
|
this.getPluginLogger(plugin2.name).error(`setup() failed: ${err}`);
|
|
23378
|
-
this.eventBus?.emit(
|
|
23584
|
+
this.eventBus?.emit(BusEvent.PLUGIN_FAILED, { name: plugin2.name, error: String(err) });
|
|
23379
23585
|
}
|
|
23380
23586
|
}
|
|
23381
23587
|
}
|
|
@@ -23396,7 +23602,7 @@ var init_lifecycle_manager = __esm({
|
|
|
23396
23602
|
this._loaded.delete(name);
|
|
23397
23603
|
this._failed.delete(name);
|
|
23398
23604
|
this.loadOrder = this.loadOrder.filter((p2) => p2.name !== name);
|
|
23399
|
-
this.eventBus?.emit(
|
|
23605
|
+
this.eventBus?.emit(BusEvent.PLUGIN_UNLOADED, { name });
|
|
23400
23606
|
}
|
|
23401
23607
|
async shutdown() {
|
|
23402
23608
|
const reversed = [...this.loadOrder].reverse();
|
|
@@ -23413,7 +23619,7 @@ var init_lifecycle_manager = __esm({
|
|
|
23413
23619
|
ctx.cleanup();
|
|
23414
23620
|
this.contexts.delete(plugin2.name);
|
|
23415
23621
|
}
|
|
23416
|
-
this.eventBus?.emit(
|
|
23622
|
+
this.eventBus?.emit(BusEvent.PLUGIN_UNLOADED, { name: plugin2.name });
|
|
23417
23623
|
}
|
|
23418
23624
|
this._loaded.clear();
|
|
23419
23625
|
this.loadOrder = [];
|
|
@@ -23423,12 +23629,12 @@ var init_lifecycle_manager = __esm({
|
|
|
23423
23629
|
});
|
|
23424
23630
|
|
|
23425
23631
|
// src/core/menu-registry.ts
|
|
23426
|
-
var
|
|
23632
|
+
var log39, MenuRegistry;
|
|
23427
23633
|
var init_menu_registry = __esm({
|
|
23428
23634
|
"src/core/menu-registry.ts"() {
|
|
23429
23635
|
"use strict";
|
|
23430
23636
|
init_log();
|
|
23431
|
-
|
|
23637
|
+
log39 = createChildLogger({ module: "menu-registry" });
|
|
23432
23638
|
MenuRegistry = class {
|
|
23433
23639
|
items = /* @__PURE__ */ new Map();
|
|
23434
23640
|
register(item) {
|
|
@@ -23447,7 +23653,7 @@ var init_menu_registry = __esm({
|
|
|
23447
23653
|
try {
|
|
23448
23654
|
return item.visible();
|
|
23449
23655
|
} catch (err) {
|
|
23450
|
-
|
|
23656
|
+
log39.warn({ err, id: item.id }, "MenuItem visible() threw, hiding item");
|
|
23451
23657
|
return false;
|
|
23452
23658
|
}
|
|
23453
23659
|
}).sort((a, b) => a.priority - b.priority);
|
|
@@ -23520,13 +23726,13 @@ Talk to users like a helpful assistant, not a CLI manual.`;
|
|
|
23520
23726
|
});
|
|
23521
23727
|
|
|
23522
23728
|
// src/core/assistant/assistant-registry.ts
|
|
23523
|
-
var
|
|
23729
|
+
var log40, AssistantRegistry;
|
|
23524
23730
|
var init_assistant_registry = __esm({
|
|
23525
23731
|
"src/core/assistant/assistant-registry.ts"() {
|
|
23526
23732
|
"use strict";
|
|
23527
23733
|
init_log();
|
|
23528
23734
|
init_prompt_constants();
|
|
23529
|
-
|
|
23735
|
+
log40 = createChildLogger({ module: "assistant-registry" });
|
|
23530
23736
|
AssistantRegistry = class {
|
|
23531
23737
|
sections = /* @__PURE__ */ new Map();
|
|
23532
23738
|
_instanceRoot = "";
|
|
@@ -23536,7 +23742,7 @@ var init_assistant_registry = __esm({
|
|
|
23536
23742
|
}
|
|
23537
23743
|
register(section) {
|
|
23538
23744
|
if (this.sections.has(section.id)) {
|
|
23539
|
-
|
|
23745
|
+
log40.warn({ id: section.id }, "Assistant section overwritten");
|
|
23540
23746
|
}
|
|
23541
23747
|
this.sections.set(section.id, section);
|
|
23542
23748
|
}
|
|
@@ -23561,7 +23767,7 @@ ${context}`);
|
|
|
23561
23767
|
parts.push("```bash\n" + cmds + "\n```");
|
|
23562
23768
|
}
|
|
23563
23769
|
} catch (err) {
|
|
23564
|
-
|
|
23770
|
+
log40.warn({ err, sectionId: section.id }, "Assistant section buildContext() failed, skipping");
|
|
23565
23771
|
}
|
|
23566
23772
|
}
|
|
23567
23773
|
parts.push(buildAssistantGuidelines(this._instanceRoot));
|
|
@@ -23572,33 +23778,37 @@ ${context}`);
|
|
|
23572
23778
|
});
|
|
23573
23779
|
|
|
23574
23780
|
// src/core/assistant/assistant-manager.ts
|
|
23575
|
-
var
|
|
23781
|
+
var log41, AssistantManager;
|
|
23576
23782
|
var init_assistant_manager = __esm({
|
|
23577
23783
|
"src/core/assistant/assistant-manager.ts"() {
|
|
23578
23784
|
"use strict";
|
|
23579
23785
|
init_log();
|
|
23580
|
-
|
|
23786
|
+
log41 = createChildLogger({ module: "assistant-manager" });
|
|
23581
23787
|
AssistantManager = class {
|
|
23582
23788
|
constructor(core, registry) {
|
|
23583
23789
|
this.core = core;
|
|
23584
23790
|
this.registry = registry;
|
|
23585
23791
|
}
|
|
23586
23792
|
sessions = /* @__PURE__ */ new Map();
|
|
23587
|
-
respawning = /* @__PURE__ */ new Set();
|
|
23588
23793
|
pendingSystemPrompts = /* @__PURE__ */ new Map();
|
|
23589
|
-
async
|
|
23794
|
+
async getOrSpawn(channelId, threadId) {
|
|
23795
|
+
const existing = this.core.sessionStore?.findAssistant(channelId);
|
|
23590
23796
|
const session = await this.core.createSession({
|
|
23591
23797
|
channelId,
|
|
23592
23798
|
agentName: this.core.configManager.get().defaultAgent,
|
|
23593
23799
|
workingDirectory: this.core.configManager.resolveWorkspace(),
|
|
23594
23800
|
initialName: "Assistant",
|
|
23595
23801
|
isAssistant: true,
|
|
23596
|
-
threadId
|
|
23802
|
+
threadId,
|
|
23803
|
+
existingSessionId: existing?.sessionId
|
|
23597
23804
|
});
|
|
23598
23805
|
this.sessions.set(channelId, session);
|
|
23599
23806
|
const systemPrompt = this.registry.buildSystemPrompt(channelId);
|
|
23600
23807
|
this.pendingSystemPrompts.set(channelId, systemPrompt);
|
|
23601
|
-
|
|
23808
|
+
log41.info(
|
|
23809
|
+
{ sessionId: session.id, channelId, reused: !!existing },
|
|
23810
|
+
existing ? "Assistant session reused (system prompt deferred)" : "Assistant spawned (system prompt deferred)"
|
|
23811
|
+
);
|
|
23602
23812
|
return session;
|
|
23603
23813
|
}
|
|
23604
23814
|
get(channelId) {
|
|
@@ -23619,19 +23829,6 @@ var init_assistant_manager = __esm({
|
|
|
23619
23829
|
}
|
|
23620
23830
|
return false;
|
|
23621
23831
|
}
|
|
23622
|
-
async respawn(channelId, threadId) {
|
|
23623
|
-
if (this.respawning.has(channelId)) {
|
|
23624
|
-
return this.sessions.get(channelId);
|
|
23625
|
-
}
|
|
23626
|
-
this.respawning.add(channelId);
|
|
23627
|
-
try {
|
|
23628
|
-
const old = this.sessions.get(channelId);
|
|
23629
|
-
if (old) await old.destroy();
|
|
23630
|
-
return await this.spawn(channelId, threadId);
|
|
23631
|
-
} finally {
|
|
23632
|
-
this.respawning.delete(channelId);
|
|
23633
|
-
}
|
|
23634
|
-
}
|
|
23635
23832
|
};
|
|
23636
23833
|
}
|
|
23637
23834
|
});
|
|
@@ -23844,7 +24041,7 @@ var init_core_items = __esm({
|
|
|
23844
24041
|
import path51 from "path";
|
|
23845
24042
|
import os23 from "os";
|
|
23846
24043
|
import { nanoid as nanoid5 } from "nanoid";
|
|
23847
|
-
var
|
|
24044
|
+
var log42, OpenACPCore;
|
|
23848
24045
|
var init_core = __esm({
|
|
23849
24046
|
"src/core/core.ts"() {
|
|
23850
24047
|
"use strict";
|
|
@@ -23868,7 +24065,8 @@ var init_core = __esm({
|
|
|
23868
24065
|
init_middleware_chain();
|
|
23869
24066
|
init_error_tracker();
|
|
23870
24067
|
init_log();
|
|
23871
|
-
|
|
24068
|
+
init_events();
|
|
24069
|
+
log42 = createChildLogger({ module: "core" });
|
|
23872
24070
|
OpenACPCore = class {
|
|
23873
24071
|
configManager;
|
|
23874
24072
|
agentCatalog;
|
|
@@ -23983,7 +24181,7 @@ var init_core = __esm({
|
|
|
23983
24181
|
if (configPath === "logging.level" && typeof value === "string") {
|
|
23984
24182
|
const { setLogLevel: setLogLevel2 } = await Promise.resolve().then(() => (init_log(), log_exports));
|
|
23985
24183
|
setLogLevel2(value);
|
|
23986
|
-
|
|
24184
|
+
log42.info({ level: value }, "Log level changed at runtime");
|
|
23987
24185
|
}
|
|
23988
24186
|
if (configPath.startsWith("speech.")) {
|
|
23989
24187
|
const speechSvc = this.lifecycleManager.serviceRegistry.get("speech");
|
|
@@ -24007,7 +24205,7 @@ var init_core = __esm({
|
|
|
24007
24205
|
}
|
|
24008
24206
|
};
|
|
24009
24207
|
speechSvc.refreshProviders(newSpeechConfig);
|
|
24010
|
-
|
|
24208
|
+
log42.info("Speech service config updated at runtime (from plugin settings)");
|
|
24011
24209
|
}
|
|
24012
24210
|
}
|
|
24013
24211
|
}
|
|
@@ -24037,14 +24235,14 @@ var init_core = __esm({
|
|
|
24037
24235
|
}
|
|
24038
24236
|
async start() {
|
|
24039
24237
|
this.agentCatalog.refreshRegistryIfStale().catch((err) => {
|
|
24040
|
-
|
|
24238
|
+
log42.warn({ err }, "Background registry refresh failed");
|
|
24041
24239
|
});
|
|
24042
24240
|
const failures = [];
|
|
24043
24241
|
for (const [name, adapter] of this.adapters.entries()) {
|
|
24044
24242
|
try {
|
|
24045
24243
|
await adapter.start();
|
|
24046
24244
|
} catch (err) {
|
|
24047
|
-
|
|
24245
|
+
log42.error({ err, adapter: name }, `Adapter "${name}" failed to start`);
|
|
24048
24246
|
failures.push({ name, error: err });
|
|
24049
24247
|
}
|
|
24050
24248
|
}
|
|
@@ -24092,7 +24290,7 @@ var init_core = __esm({
|
|
|
24092
24290
|
}
|
|
24093
24291
|
// --- Message Routing ---
|
|
24094
24292
|
async handleMessage(message) {
|
|
24095
|
-
|
|
24293
|
+
log42.debug(
|
|
24096
24294
|
{
|
|
24097
24295
|
channelId: message.channelId,
|
|
24098
24296
|
threadId: message.threadId,
|
|
@@ -24102,7 +24300,7 @@ var init_core = __esm({
|
|
|
24102
24300
|
);
|
|
24103
24301
|
if (this.lifecycleManager?.middlewareChain) {
|
|
24104
24302
|
const result = await this.lifecycleManager.middlewareChain.execute(
|
|
24105
|
-
|
|
24303
|
+
Hook.MESSAGE_INCOMING,
|
|
24106
24304
|
message,
|
|
24107
24305
|
async (msg) => msg
|
|
24108
24306
|
);
|
|
@@ -24111,7 +24309,7 @@ var init_core = __esm({
|
|
|
24111
24309
|
}
|
|
24112
24310
|
const access2 = await this.securityGuard.checkAccess(message);
|
|
24113
24311
|
if (!access2.allowed) {
|
|
24114
|
-
|
|
24312
|
+
log42.warn({ userId: message.userId, reason: access2.reason }, "Access denied");
|
|
24115
24313
|
if (access2.reason.includes("Session limit")) {
|
|
24116
24314
|
const adapter = this.adapters.get(message.channelId);
|
|
24117
24315
|
if (adapter) {
|
|
@@ -24125,7 +24323,7 @@ var init_core = __esm({
|
|
|
24125
24323
|
}
|
|
24126
24324
|
let session = await this.sessionFactory.getOrResume(message.channelId, message.threadId);
|
|
24127
24325
|
if (!session) {
|
|
24128
|
-
|
|
24326
|
+
log42.warn(
|
|
24129
24327
|
{ channelId: message.channelId, threadId: message.threadId },
|
|
24130
24328
|
"No session found for thread (in-memory miss + lazy resume returned null)"
|
|
24131
24329
|
);
|
|
@@ -24154,9 +24352,10 @@ ${text6}`;
|
|
|
24154
24352
|
}
|
|
24155
24353
|
}
|
|
24156
24354
|
const sourceAdapterId = message.routing?.sourceAdapterId ?? message.channelId;
|
|
24355
|
+
const routing = sourceAdapterId !== message.routing?.sourceAdapterId ? { ...message.routing, sourceAdapterId } : message.routing;
|
|
24157
24356
|
if (sourceAdapterId && sourceAdapterId !== "sse" && sourceAdapterId !== "api") {
|
|
24158
24357
|
const turnId = nanoid5(8);
|
|
24159
|
-
this.eventBus.emit(
|
|
24358
|
+
this.eventBus.emit(BusEvent.MESSAGE_QUEUED, {
|
|
24160
24359
|
sessionId: session.id,
|
|
24161
24360
|
turnId,
|
|
24162
24361
|
text: text6,
|
|
@@ -24165,9 +24364,9 @@ ${text6}`;
|
|
|
24165
24364
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24166
24365
|
queueDepth: session.queueDepth
|
|
24167
24366
|
});
|
|
24168
|
-
await session.enqueuePrompt(text6, message.attachments,
|
|
24367
|
+
await session.enqueuePrompt(text6, message.attachments, routing, turnId);
|
|
24169
24368
|
} else {
|
|
24170
|
-
await session.enqueuePrompt(text6, message.attachments,
|
|
24369
|
+
await session.enqueuePrompt(text6, message.attachments, routing);
|
|
24171
24370
|
}
|
|
24172
24371
|
}
|
|
24173
24372
|
// --- Unified Session Creation Pipeline ---
|
|
@@ -24211,6 +24410,7 @@ ${text6}`;
|
|
|
24211
24410
|
createdAt: session.createdAt.toISOString(),
|
|
24212
24411
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24213
24412
|
name: session.name,
|
|
24413
|
+
isAssistant: params.isAssistant,
|
|
24214
24414
|
platform: platform2,
|
|
24215
24415
|
platforms,
|
|
24216
24416
|
firstAgent: session.firstAgent,
|
|
@@ -24223,10 +24423,10 @@ ${text6}`;
|
|
|
24223
24423
|
const bridge = this.createBridge(session, adapter, session.channelId);
|
|
24224
24424
|
bridge.connect();
|
|
24225
24425
|
adapter.flushPendingSkillCommands?.(session.id).catch((err) => {
|
|
24226
|
-
|
|
24426
|
+
log42.warn({ err, sessionId: session.id }, "Failed to flush pending skill commands");
|
|
24227
24427
|
});
|
|
24228
24428
|
if (params.createThread && session.threadId) {
|
|
24229
|
-
this.eventBus.emit(
|
|
24429
|
+
this.eventBus.emit(BusEvent.SESSION_THREAD_READY, {
|
|
24230
24430
|
sessionId: session.id,
|
|
24231
24431
|
channelId: params.channelId,
|
|
24232
24432
|
threadId: session.threadId
|
|
@@ -24237,26 +24437,56 @@ ${text6}`;
|
|
|
24237
24437
|
session.agentInstance.onPermissionRequest = async (permRequest) => {
|
|
24238
24438
|
const allowOption = permRequest.options.find((o) => o.isAllow);
|
|
24239
24439
|
if (!allowOption) {
|
|
24240
|
-
|
|
24440
|
+
log42.warn(
|
|
24241
24441
|
{ sessionId: session.id, permissionId: permRequest.id, description: permRequest.description },
|
|
24242
24442
|
"Headless session has no allow option for permission request \u2014 skipping auto-approve, will time out"
|
|
24243
24443
|
);
|
|
24244
24444
|
return new Promise(() => {
|
|
24245
24445
|
});
|
|
24246
24446
|
}
|
|
24247
|
-
|
|
24447
|
+
log42.warn(
|
|
24248
24448
|
{ sessionId: session.id, permissionId: permRequest.id, option: allowOption.id },
|
|
24249
24449
|
`Auto-approving permission "${permRequest.description}" for headless session \u2014 no adapter connected`
|
|
24250
24450
|
);
|
|
24251
24451
|
return allowOption.id;
|
|
24252
24452
|
};
|
|
24453
|
+
session.on(SessionEv.NAMED, async (name) => {
|
|
24454
|
+
await this.sessionManager.patchRecord(session.id, { name });
|
|
24455
|
+
this.eventBus.emit(BusEvent.SESSION_UPDATED, { sessionId: session.id, name });
|
|
24456
|
+
});
|
|
24457
|
+
const mw = () => this.lifecycleManager?.middlewareChain;
|
|
24458
|
+
session.on(SessionEv.AGENT_EVENT, async (event) => {
|
|
24459
|
+
let processedEvent = event;
|
|
24460
|
+
const chain = mw();
|
|
24461
|
+
if (chain) {
|
|
24462
|
+
const result = await chain.execute(Hook.AGENT_BEFORE_EVENT, { sessionId: session.id, event }, async (e) => e);
|
|
24463
|
+
if (!result) return;
|
|
24464
|
+
processedEvent = result.event;
|
|
24465
|
+
}
|
|
24466
|
+
if (processedEvent.type === "session_end") {
|
|
24467
|
+
session.finish(processedEvent.reason);
|
|
24468
|
+
} else if (processedEvent.type === "error") {
|
|
24469
|
+
session.fail(processedEvent.message);
|
|
24470
|
+
}
|
|
24471
|
+
this.eventBus.emit(BusEvent.AGENT_EVENT, { sessionId: session.id, event: processedEvent });
|
|
24472
|
+
});
|
|
24473
|
+
session.on(SessionEv.STATUS_CHANGE, (_from, to) => {
|
|
24474
|
+
this.sessionManager.patchRecord(session.id, {
|
|
24475
|
+
status: to,
|
|
24476
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24477
|
+
});
|
|
24478
|
+
this.eventBus.emit(BusEvent.SESSION_UPDATED, { sessionId: session.id, status: to });
|
|
24479
|
+
});
|
|
24480
|
+
session.on(SessionEv.PROMPT_COUNT_CHANGED, (count) => {
|
|
24481
|
+
this.sessionManager.patchRecord(session.id, { currentPromptCount: count });
|
|
24482
|
+
});
|
|
24253
24483
|
}
|
|
24254
24484
|
this.sessionFactory.wireSideEffects(session, {
|
|
24255
24485
|
eventBus: this.eventBus,
|
|
24256
24486
|
notificationManager: this.notificationManager,
|
|
24257
24487
|
tunnelService: this._tunnelService
|
|
24258
24488
|
});
|
|
24259
|
-
|
|
24489
|
+
log42.info(
|
|
24260
24490
|
{ sessionId: session.id, agentName: params.agentName },
|
|
24261
24491
|
"Session created via pipeline"
|
|
24262
24492
|
);
|
|
@@ -24706,18 +24936,6 @@ Prompts: ${session.promptCount}` };
|
|
|
24706
24936
|
return { type: "list", title: "\u{1F4CB} Sessions", items };
|
|
24707
24937
|
}
|
|
24708
24938
|
});
|
|
24709
|
-
registry.register({
|
|
24710
|
-
name: "clear",
|
|
24711
|
-
description: "Clear session history",
|
|
24712
|
-
category: "system",
|
|
24713
|
-
handler: async (args2) => {
|
|
24714
|
-
if (!core.assistantManager) return { type: "error", message: "Assistant not available" };
|
|
24715
|
-
const assistant = core.assistantManager.get(args2.channelId);
|
|
24716
|
-
if (!assistant) return { type: "error", message: "No assistant session for this channel." };
|
|
24717
|
-
await core.assistantManager.respawn(args2.channelId, assistant.threadId);
|
|
24718
|
-
return { type: "text", text: "\u2705 Assistant history cleared." };
|
|
24719
|
-
}
|
|
24720
|
-
});
|
|
24721
24939
|
registry.register({
|
|
24722
24940
|
name: "newchat",
|
|
24723
24941
|
description: "New chat, same agent & workspace",
|
|
@@ -25244,10 +25462,10 @@ function registerCategoryCommand(registry, core, category, commandName) {
|
|
|
25244
25462
|
}
|
|
25245
25463
|
try {
|
|
25246
25464
|
await session.setConfigOption(configOption.id, { type: "select", value: raw });
|
|
25247
|
-
core.eventBus.emit(
|
|
25465
|
+
core.eventBus.emit(BusEvent.SESSION_CONFIG_CHANGED, { sessionId: session.id });
|
|
25248
25466
|
return { type: "text", text: labels.successMsg(match.name, configOption.name) };
|
|
25249
25467
|
} catch (err) {
|
|
25250
|
-
|
|
25468
|
+
log43.error({ err, commandName, configId: configOption.id }, "setConfigOption failed");
|
|
25251
25469
|
const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && typeof err.message === "string" ? err.message : String(err);
|
|
25252
25470
|
return { type: "error", message: `Could not change ${commandName}: ${msg}` };
|
|
25253
25471
|
}
|
|
@@ -25306,13 +25524,13 @@ function registerDangerousCommand(registry, core) {
|
|
|
25306
25524
|
try {
|
|
25307
25525
|
const targetValue = wantOn ? bypassValue : nonBypassDefault;
|
|
25308
25526
|
await session.setConfigOption(modeConfig.id, { type: "select", value: targetValue });
|
|
25309
|
-
core.eventBus.emit(
|
|
25527
|
+
core.eventBus.emit(BusEvent.SESSION_CONFIG_CHANGED, { sessionId: session.id });
|
|
25310
25528
|
return {
|
|
25311
25529
|
type: "text",
|
|
25312
25530
|
text: wantOn ? "\u2620\uFE0F **Bypass Permissions enabled** \u2014 all permission requests will be auto-approved. The agent can run any action without asking." : "\u{1F510} **Bypass Permissions disabled** \u2014 you will be asked to approve risky actions."
|
|
25313
25531
|
};
|
|
25314
25532
|
} catch (err) {
|
|
25315
|
-
|
|
25533
|
+
log43.error({ err }, "setConfigOption failed (bypass toggle)");
|
|
25316
25534
|
const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && typeof err.message === "string" ? err.message : String(err);
|
|
25317
25535
|
return { type: "error", message: `Could not toggle bypass: ${msg}` };
|
|
25318
25536
|
}
|
|
@@ -25321,7 +25539,7 @@ function registerDangerousCommand(registry, core) {
|
|
|
25321
25539
|
await core.sessionManager.patchRecord(session.id, {
|
|
25322
25540
|
clientOverrides: { ...session.clientOverrides }
|
|
25323
25541
|
});
|
|
25324
|
-
core.eventBus.emit(
|
|
25542
|
+
core.eventBus.emit(BusEvent.SESSION_CONFIG_CHANGED, { sessionId: session.id });
|
|
25325
25543
|
return {
|
|
25326
25544
|
type: "text",
|
|
25327
25545
|
text: wantOn ? "\u2620\uFE0F **Bypass Permissions enabled** (client-side) \u2014 all permission requests will be auto-approved.\n\n_Note: This agent doesn't natively support bypass mode, so OpenACP will auto-approve on your behalf._" : "\u{1F510} **Bypass Permissions disabled** \u2014 you will be asked to approve risky actions."
|
|
@@ -25336,14 +25554,15 @@ function registerConfigCommands(registry, _core) {
|
|
|
25336
25554
|
registerCategoryCommand(registry, core, "thought_level", "thought");
|
|
25337
25555
|
registerDangerousCommand(registry, core);
|
|
25338
25556
|
}
|
|
25339
|
-
var
|
|
25557
|
+
var log43, CATEGORY_LABELS;
|
|
25340
25558
|
var init_config6 = __esm({
|
|
25341
25559
|
"src/core/commands/config.ts"() {
|
|
25342
25560
|
"use strict";
|
|
25343
25561
|
init_log();
|
|
25562
|
+
init_events();
|
|
25344
25563
|
init_bypass_detection();
|
|
25345
25564
|
init_bypass_detection();
|
|
25346
|
-
|
|
25565
|
+
log43 = createChildLogger({ module: "commands/config" });
|
|
25347
25566
|
CATEGORY_LABELS = {
|
|
25348
25567
|
mode: {
|
|
25349
25568
|
menuTitle: (cur) => `Choose session mode (current: ${cur})`,
|
|
@@ -25755,7 +25974,7 @@ function installAutoStart(logDir2) {
|
|
|
25755
25974
|
fs46.mkdirSync(dir, { recursive: true });
|
|
25756
25975
|
fs46.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
25757
25976
|
execFileSync8("launchctl", ["load", LAUNCHD_PLIST_PATH], { stdio: "pipe" });
|
|
25758
|
-
|
|
25977
|
+
log44.info("LaunchAgent installed");
|
|
25759
25978
|
return { success: true };
|
|
25760
25979
|
}
|
|
25761
25980
|
if (process.platform === "linux") {
|
|
@@ -25765,13 +25984,13 @@ function installAutoStart(logDir2) {
|
|
|
25765
25984
|
fs46.writeFileSync(SYSTEMD_SERVICE_PATH, unit);
|
|
25766
25985
|
execFileSync8("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
|
|
25767
25986
|
execFileSync8("systemctl", ["--user", "enable", "openacp"], { stdio: "pipe" });
|
|
25768
|
-
|
|
25987
|
+
log44.info("systemd user service installed");
|
|
25769
25988
|
return { success: true };
|
|
25770
25989
|
}
|
|
25771
25990
|
return { success: false, error: "Unsupported platform" };
|
|
25772
25991
|
} catch (e) {
|
|
25773
25992
|
const msg = e.message;
|
|
25774
|
-
|
|
25993
|
+
log44.error({ err: msg }, "Failed to install auto-start");
|
|
25775
25994
|
return { success: false, error: msg };
|
|
25776
25995
|
}
|
|
25777
25996
|
}
|
|
@@ -25787,7 +26006,7 @@ function uninstallAutoStart() {
|
|
|
25787
26006
|
} catch {
|
|
25788
26007
|
}
|
|
25789
26008
|
fs46.unlinkSync(LAUNCHD_PLIST_PATH);
|
|
25790
|
-
|
|
26009
|
+
log44.info("LaunchAgent removed");
|
|
25791
26010
|
}
|
|
25792
26011
|
return { success: true };
|
|
25793
26012
|
}
|
|
@@ -25799,14 +26018,14 @@ function uninstallAutoStart() {
|
|
|
25799
26018
|
}
|
|
25800
26019
|
fs46.unlinkSync(SYSTEMD_SERVICE_PATH);
|
|
25801
26020
|
execFileSync8("systemctl", ["--user", "daemon-reload"], { stdio: "pipe" });
|
|
25802
|
-
|
|
26021
|
+
log44.info("systemd user service removed");
|
|
25803
26022
|
}
|
|
25804
26023
|
return { success: true };
|
|
25805
26024
|
}
|
|
25806
26025
|
return { success: false, error: "Unsupported platform" };
|
|
25807
26026
|
} catch (e) {
|
|
25808
26027
|
const msg = e.message;
|
|
25809
|
-
|
|
26028
|
+
log44.error({ err: msg }, "Failed to uninstall auto-start");
|
|
25810
26029
|
return { success: false, error: msg };
|
|
25811
26030
|
}
|
|
25812
26031
|
}
|
|
@@ -25819,12 +26038,12 @@ function isAutoStartInstalled() {
|
|
|
25819
26038
|
}
|
|
25820
26039
|
return false;
|
|
25821
26040
|
}
|
|
25822
|
-
var
|
|
26041
|
+
var log44, LAUNCHD_LABEL, LAUNCHD_PLIST_PATH, SYSTEMD_SERVICE_PATH;
|
|
25823
26042
|
var init_autostart = __esm({
|
|
25824
26043
|
"src/cli/autostart.ts"() {
|
|
25825
26044
|
"use strict";
|
|
25826
26045
|
init_log();
|
|
25827
|
-
|
|
26046
|
+
log44 = createChildLogger({ module: "autostart" });
|
|
25828
26047
|
LAUNCHD_LABEL = "com.openacp.daemon";
|
|
25829
26048
|
LAUNCHD_PLIST_PATH = path52.join(os24.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
25830
26049
|
SYSTEMD_SERVICE_PATH = path52.join(os24.homedir(), ".config", "systemd", "user", "openacp.service");
|
|
@@ -25927,7 +26146,7 @@ async function setupIntegrations() {
|
|
|
25927
26146
|
if (integration) {
|
|
25928
26147
|
for (const item of integration.items) {
|
|
25929
26148
|
const result = await item.install();
|
|
25930
|
-
for (const
|
|
26149
|
+
for (const log47 of result.logs) console.log(` ${log47}`);
|
|
25931
26150
|
}
|
|
25932
26151
|
}
|
|
25933
26152
|
console.log("Claude CLI integration installed.\n");
|
|
@@ -26620,7 +26839,7 @@ async function runSetup(configManager, opts) {
|
|
|
26620
26839
|
const config = {
|
|
26621
26840
|
instanceName,
|
|
26622
26841
|
defaultAgent,
|
|
26623
|
-
workspace: { ...workspace, security: { allowedPaths: [], envWhitelist: [] } },
|
|
26842
|
+
workspace: { ...workspace, allowExternalWorkspaces: true, security: { allowedPaths: [], envWhitelist: [] } },
|
|
26624
26843
|
logging: {
|
|
26625
26844
|
level: "info",
|
|
26626
26845
|
logDir: path56.join(instanceRoot, "logs"),
|
|
@@ -26869,14 +27088,14 @@ async function runPostUpgradeChecks(config) {
|
|
|
26869
27088
|
const { ensureCloudflared: ensureCloudflared2 } = await Promise.resolve().then(() => (init_install_cloudflared(), install_cloudflared_exports));
|
|
26870
27089
|
await ensureCloudflared2();
|
|
26871
27090
|
} catch (err) {
|
|
26872
|
-
|
|
27091
|
+
log46.warn(
|
|
26873
27092
|
{ err: err.message },
|
|
26874
27093
|
"Could not install cloudflared. Tunnel may not work."
|
|
26875
27094
|
);
|
|
26876
27095
|
}
|
|
26877
27096
|
} else {
|
|
26878
27097
|
if (!commandExists(tunnelProvider)) {
|
|
26879
|
-
|
|
27098
|
+
log46.warn(
|
|
26880
27099
|
`Tunnel provider "${tunnelProvider}" is not installed. Install it or switch to cloudflare (free, auto-installed).`
|
|
26881
27100
|
);
|
|
26882
27101
|
}
|
|
@@ -26890,7 +27109,7 @@ async function runPostUpgradeChecks(config) {
|
|
|
26890
27109
|
if (integration) {
|
|
26891
27110
|
const allInstalled = integration.items.every((item) => item.isInstalled());
|
|
26892
27111
|
if (!allInstalled) {
|
|
26893
|
-
|
|
27112
|
+
log46.info(
|
|
26894
27113
|
'Claude CLI integration not installed. Run "openacp integrate claude" for session transfer + tunnel skill.'
|
|
26895
27114
|
);
|
|
26896
27115
|
}
|
|
@@ -26900,7 +27119,7 @@ async function runPostUpgradeChecks(config) {
|
|
|
26900
27119
|
const { ensureJq: ensureJq2 } = await Promise.resolve().then(() => (init_install_jq(), install_jq_exports));
|
|
26901
27120
|
await ensureJq2();
|
|
26902
27121
|
} catch (err) {
|
|
26903
|
-
|
|
27122
|
+
log46.warn(
|
|
26904
27123
|
{ err: err.message },
|
|
26905
27124
|
"Could not install jq. Handoff hooks may not work."
|
|
26906
27125
|
);
|
|
@@ -26910,7 +27129,7 @@ async function runPostUpgradeChecks(config) {
|
|
|
26910
27129
|
} catch {
|
|
26911
27130
|
}
|
|
26912
27131
|
if (!commandExists("unzip")) {
|
|
26913
|
-
|
|
27132
|
+
log46.warn(
|
|
26914
27133
|
"unzip is not installed. Some agent installations (binary distribution) may fail. Install: brew install unzip (macOS) or apt install unzip (Linux)"
|
|
26915
27134
|
);
|
|
26916
27135
|
}
|
|
@@ -26923,20 +27142,20 @@ async function runPostUpgradeChecks(config) {
|
|
|
26923
27142
|
(a) => a.distribution === "uvx"
|
|
26924
27143
|
);
|
|
26925
27144
|
if (hasUvxAgent && !commandExists("uvx")) {
|
|
26926
|
-
|
|
27145
|
+
log46.warn(
|
|
26927
27146
|
"uvx is not installed but you have Python-based agents. Install: pip install uv"
|
|
26928
27147
|
);
|
|
26929
27148
|
}
|
|
26930
27149
|
} catch {
|
|
26931
27150
|
}
|
|
26932
27151
|
}
|
|
26933
|
-
var
|
|
27152
|
+
var log46;
|
|
26934
27153
|
var init_post_upgrade = __esm({
|
|
26935
27154
|
"src/cli/post-upgrade.ts"() {
|
|
26936
27155
|
"use strict";
|
|
26937
27156
|
init_log();
|
|
26938
27157
|
init_agent_dependencies();
|
|
26939
|
-
|
|
27158
|
+
log46 = createChildLogger({ module: "post-upgrade" });
|
|
26940
27159
|
}
|
|
26941
27160
|
});
|
|
26942
27161
|
|
|
@@ -27069,7 +27288,7 @@ async function startServer(opts) {
|
|
|
27069
27288
|
serviceRegistry.register("field-registry", fieldRegistry, "core");
|
|
27070
27289
|
registerSystemCommands(commandRegistry, core);
|
|
27071
27290
|
try {
|
|
27072
|
-
core.eventBus.emit(
|
|
27291
|
+
core.eventBus.emit(BusEvent.KERNEL_BOOTED);
|
|
27073
27292
|
core.lifecycleManager.settingsManager = settingsManager;
|
|
27074
27293
|
core.lifecycleManager.pluginRegistry = pluginRegistry;
|
|
27075
27294
|
await core.lifecycleManager.boot(corePlugins);
|
|
@@ -27182,8 +27401,8 @@ async function startServer(opts) {
|
|
|
27182
27401
|
if (tunnelSvc) {
|
|
27183
27402
|
core.tunnelService = tunnelSvc;
|
|
27184
27403
|
}
|
|
27185
|
-
core.eventBus.emit(
|
|
27186
|
-
core.eventBus.emit(
|
|
27404
|
+
core.eventBus.emit(BusEvent.SYSTEM_COMMANDS_READY, { commands: commandRegistry.getAll() });
|
|
27405
|
+
core.eventBus.emit(BusEvent.SYSTEM_READY);
|
|
27187
27406
|
} catch (err) {
|
|
27188
27407
|
if (spinner4) {
|
|
27189
27408
|
spinner4.fail("Plugin boot failed");
|
|
@@ -27419,6 +27638,7 @@ var init_main = __esm({
|
|
|
27419
27638
|
init_commands4();
|
|
27420
27639
|
init_instance_registry();
|
|
27421
27640
|
init_plugin_field_registry();
|
|
27641
|
+
init_events();
|
|
27422
27642
|
RESTART_EXIT_CODE = 75;
|
|
27423
27643
|
shuttingDown = false;
|
|
27424
27644
|
isDirectExecution = process.argv[1]?.endsWith("main.js");
|
|
@@ -29165,6 +29385,15 @@ async function uninstallPlugin(name, purge, instanceRoot, json = false) {
|
|
|
29165
29385
|
init_api_client();
|
|
29166
29386
|
init_helpers();
|
|
29167
29387
|
init_output();
|
|
29388
|
+
function extractApiError(data, fallback = "API request failed") {
|
|
29389
|
+
const err = data.error;
|
|
29390
|
+
if (!err) return fallback;
|
|
29391
|
+
if (typeof err === "string") return err;
|
|
29392
|
+
if (typeof err === "object" && err !== null && "message" in err) {
|
|
29393
|
+
return String(err.message);
|
|
29394
|
+
}
|
|
29395
|
+
return fallback;
|
|
29396
|
+
}
|
|
29168
29397
|
function printApiHelp() {
|
|
29169
29398
|
console.log(`
|
|
29170
29399
|
\x1B[1mopenacp api\x1B[0m \u2014 Interact with the running OpenACP daemon
|
|
@@ -29458,8 +29687,8 @@ Shows the version of the currently running daemon process.
|
|
|
29458
29687
|
});
|
|
29459
29688
|
const data = await res.json();
|
|
29460
29689
|
if (!res.ok) {
|
|
29461
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29462
|
-
console.error(`Error: ${data
|
|
29690
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29691
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29463
29692
|
process.exit(1);
|
|
29464
29693
|
}
|
|
29465
29694
|
if (json) jsonSuccess(data);
|
|
@@ -29482,8 +29711,8 @@ Shows the version of the currently running daemon process.
|
|
|
29482
29711
|
});
|
|
29483
29712
|
const data = await res.json();
|
|
29484
29713
|
if (!res.ok) {
|
|
29485
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29486
|
-
console.error(`Error: ${data
|
|
29714
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29715
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29487
29716
|
process.exit(1);
|
|
29488
29717
|
}
|
|
29489
29718
|
if (json) jsonSuccess({ cancelled: true, sessionId });
|
|
@@ -29547,8 +29776,8 @@ Shows the version of the currently running daemon process.
|
|
|
29547
29776
|
process.exit(1);
|
|
29548
29777
|
}
|
|
29549
29778
|
if (!res.ok) {
|
|
29550
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29551
|
-
console.error(`Error: ${data
|
|
29779
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29780
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29552
29781
|
process.exit(1);
|
|
29553
29782
|
}
|
|
29554
29783
|
if (json) jsonSuccess(data);
|
|
@@ -29594,8 +29823,8 @@ Shows the version of the currently running daemon process.
|
|
|
29594
29823
|
});
|
|
29595
29824
|
const data = await res.json();
|
|
29596
29825
|
if (!res.ok) {
|
|
29597
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29598
|
-
console.error(`Error: ${data
|
|
29826
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29827
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29599
29828
|
process.exit(1);
|
|
29600
29829
|
}
|
|
29601
29830
|
if (json) jsonSuccess(data);
|
|
@@ -29610,8 +29839,8 @@ Shows the version of the currently running daemon process.
|
|
|
29610
29839
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
29611
29840
|
const data = await res.json();
|
|
29612
29841
|
if (!res.ok) {
|
|
29613
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29614
|
-
console.error(`Error: ${data
|
|
29842
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29843
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29615
29844
|
process.exit(1);
|
|
29616
29845
|
}
|
|
29617
29846
|
if (json) jsonSuccess(data);
|
|
@@ -29648,8 +29877,8 @@ Shows the version of the currently running daemon process.
|
|
|
29648
29877
|
});
|
|
29649
29878
|
const data = await res.json();
|
|
29650
29879
|
if (!res.ok) {
|
|
29651
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29652
|
-
console.error(`Error: ${data
|
|
29880
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29881
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29653
29882
|
process.exit(1);
|
|
29654
29883
|
}
|
|
29655
29884
|
if (json) jsonSuccess(data);
|
|
@@ -29659,8 +29888,8 @@ Shows the version of the currently running daemon process.
|
|
|
29659
29888
|
const res = await call("/api/health");
|
|
29660
29889
|
const data = await res.json();
|
|
29661
29890
|
if (!res.ok) {
|
|
29662
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29663
|
-
console.error(`Error: ${data
|
|
29891
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29892
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29664
29893
|
process.exit(1);
|
|
29665
29894
|
}
|
|
29666
29895
|
if (json) jsonSuccess(data);
|
|
@@ -29685,8 +29914,8 @@ Shows the version of the currently running daemon process.
|
|
|
29685
29914
|
const res = await call("/api/restart", { method: "POST" });
|
|
29686
29915
|
const data = await res.json();
|
|
29687
29916
|
if (!res.ok) {
|
|
29688
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29689
|
-
console.error(`Error: ${data
|
|
29917
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29918
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29690
29919
|
process.exit(1);
|
|
29691
29920
|
}
|
|
29692
29921
|
if (json) jsonSuccess({ restarted: true });
|
|
@@ -29698,8 +29927,8 @@ Shows the version of the currently running daemon process.
|
|
|
29698
29927
|
const res = await call("/api/config");
|
|
29699
29928
|
const data = await res.json();
|
|
29700
29929
|
if (!res.ok) {
|
|
29701
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29702
|
-
console.error(`Error: ${data
|
|
29930
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29931
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29703
29932
|
process.exit(1);
|
|
29704
29933
|
}
|
|
29705
29934
|
if (json) jsonSuccess(data);
|
|
@@ -29724,8 +29953,8 @@ Shows the version of the currently running daemon process.
|
|
|
29724
29953
|
});
|
|
29725
29954
|
const data = await res.json();
|
|
29726
29955
|
if (!res.ok) {
|
|
29727
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29728
|
-
console.error(`Error: ${data
|
|
29956
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29957
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29729
29958
|
process.exit(1);
|
|
29730
29959
|
}
|
|
29731
29960
|
if (json) jsonSuccess(data);
|
|
@@ -29757,8 +29986,8 @@ Shows the version of the currently running daemon process.
|
|
|
29757
29986
|
const res = await call("/api/tunnel");
|
|
29758
29987
|
const data = await res.json();
|
|
29759
29988
|
if (!res.ok) {
|
|
29760
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29761
|
-
console.error(`Error: ${data
|
|
29989
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
29990
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29762
29991
|
process.exit(1);
|
|
29763
29992
|
}
|
|
29764
29993
|
if (json) jsonSuccess(data);
|
|
@@ -29782,8 +30011,8 @@ Shows the version of the currently running daemon process.
|
|
|
29782
30011
|
});
|
|
29783
30012
|
const data = await res.json();
|
|
29784
30013
|
if (!res.ok) {
|
|
29785
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29786
|
-
console.error(`Error: ${data
|
|
30014
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30015
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29787
30016
|
process.exit(1);
|
|
29788
30017
|
}
|
|
29789
30018
|
if (json) jsonSuccess({ sent: true });
|
|
@@ -29792,8 +30021,8 @@ Shows the version of the currently running daemon process.
|
|
|
29792
30021
|
const res = await call("/api/version");
|
|
29793
30022
|
const data = await res.json();
|
|
29794
30023
|
if (!res.ok) {
|
|
29795
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29796
|
-
console.error(`Error: ${data
|
|
30024
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30025
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29797
30026
|
process.exit(1);
|
|
29798
30027
|
}
|
|
29799
30028
|
if (json) jsonSuccess(data);
|
|
@@ -29810,8 +30039,8 @@ Shows the version of the currently running daemon process.
|
|
|
29810
30039
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config`);
|
|
29811
30040
|
const data = await res.json();
|
|
29812
30041
|
if (!res.ok) {
|
|
29813
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29814
|
-
console.error(`Error: ${data
|
|
30042
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30043
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29815
30044
|
process.exit(1);
|
|
29816
30045
|
}
|
|
29817
30046
|
if (json) jsonSuccess(data);
|
|
@@ -29859,8 +30088,8 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
29859
30088
|
});
|
|
29860
30089
|
const data = await res.json();
|
|
29861
30090
|
if (!res.ok) {
|
|
29862
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29863
|
-
console.error(`Error: ${data
|
|
30091
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30092
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29864
30093
|
process.exit(1);
|
|
29865
30094
|
}
|
|
29866
30095
|
if (json) jsonSuccess(data);
|
|
@@ -29874,8 +30103,8 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
29874
30103
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
29875
30104
|
const data = await res.json();
|
|
29876
30105
|
if (!res.ok) {
|
|
29877
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29878
|
-
console.error(`Error: ${data
|
|
30106
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30107
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29879
30108
|
process.exit(1);
|
|
29880
30109
|
}
|
|
29881
30110
|
if (json) jsonSuccess(data);
|
|
@@ -29903,8 +30132,8 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
29903
30132
|
});
|
|
29904
30133
|
const data = await res.json();
|
|
29905
30134
|
if (!res.ok) {
|
|
29906
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29907
|
-
console.error(`Error: ${data
|
|
30135
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30136
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29908
30137
|
process.exit(1);
|
|
29909
30138
|
}
|
|
29910
30139
|
if (json) jsonSuccess(data);
|
|
@@ -29914,8 +30143,8 @@ Client overrides: ${JSON.stringify(clientOverrides)}`);
|
|
|
29914
30143
|
const res = await call(`/api/sessions/${encodeURIComponent(sessionId)}/config/overrides`);
|
|
29915
30144
|
const data = await res.json();
|
|
29916
30145
|
if (!res.ok) {
|
|
29917
|
-
if (json) jsonError(ErrorCodes.API_ERROR,
|
|
29918
|
-
console.error(`Error: ${data
|
|
30146
|
+
if (json) jsonError(ErrorCodes.API_ERROR, extractApiError(data));
|
|
30147
|
+
console.error(`Error: ${extractApiError(data)}`);
|
|
29919
30148
|
process.exit(1);
|
|
29920
30149
|
}
|
|
29921
30150
|
if (json) jsonSuccess(data);
|
|
@@ -30591,7 +30820,7 @@ agent-native handoff command such as /openacp:handoff.
|
|
|
30591
30820
|
if (uninstall) {
|
|
30592
30821
|
console.log(`Removing ${agent}/${item.id}...`);
|
|
30593
30822
|
const result = await item.uninstall();
|
|
30594
|
-
for (const
|
|
30823
|
+
for (const log47 of result.logs) console.log(` ${log47}`);
|
|
30595
30824
|
if (result.success) {
|
|
30596
30825
|
console.log(` ${item.name} removed.`);
|
|
30597
30826
|
} else {
|
|
@@ -30601,7 +30830,7 @@ agent-native handoff command such as /openacp:handoff.
|
|
|
30601
30830
|
} else {
|
|
30602
30831
|
console.log(`Installing ${agent}/${item.id}...`);
|
|
30603
30832
|
const result = await item.install();
|
|
30604
|
-
for (const
|
|
30833
|
+
for (const log47 of result.logs) console.log(` ${log47}`);
|
|
30605
30834
|
if (result.success) {
|
|
30606
30835
|
console.log(` ${item.name} installed.`);
|
|
30607
30836
|
} else {
|