@pinet/slack-bridge 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -1
- package/dist/activity-log.d.ts +10 -3
- package/dist/agent-event-runtime.d.ts +0 -2
- package/dist/agent-event-runtime.js +0 -1
- package/dist/agent-prompt-guidance.d.ts +1 -6
- package/dist/agent-prompt-guidance.js +1 -6
- package/dist/broker/adapters/slack.d.ts +4 -1
- package/dist/broker/adapters/slack.js +16 -9
- package/dist/broker/client.d.ts +21 -4
- package/dist/broker/client.js +65 -25
- package/dist/broker/hibernation-activation-authority.d.ts +22 -0
- package/dist/broker/hibernation-activation-authority.js +51 -0
- package/dist/broker/hibernation-activation.d.ts +75 -0
- package/dist/broker/hibernation-activation.js +95 -0
- package/dist/broker/hibernation-command-router.d.ts +54 -0
- package/dist/broker/hibernation-command-router.js +124 -0
- package/dist/broker/hibernation-runtime-adapters.d.ts +79 -0
- package/dist/broker/hibernation-runtime-adapters.js +473 -0
- package/dist/broker/hibernation-runtime-helpers.d.ts +146 -0
- package/dist/broker/hibernation-runtime-helpers.js +243 -0
- package/dist/broker/index.d.ts +16 -1
- package/dist/broker/index.js +68 -10
- package/dist/broker/lock-conflict.d.ts +109 -0
- package/dist/broker/lock-conflict.js +409 -0
- package/dist/broker/socket-server.d.ts +25 -0
- package/dist/broker/socket-server.js +234 -4
- package/dist/broker-delivery.d.ts +1 -0
- package/dist/broker-delivery.js +10 -1
- package/dist/broker-runtime.d.ts +14 -2
- package/dist/broker-runtime.js +114 -3
- package/dist/canvases.d.ts +12 -2
- package/dist/canvases.js +1 -3
- package/dist/compaction-gate.d.ts +7 -0
- package/dist/compaction-gate.js +35 -0
- package/dist/deploy-manifest.d.ts +8 -2
- package/dist/deploy-manifest.js +9 -7
- package/dist/follower-runtime.d.ts +5 -2
- package/dist/follower-runtime.js +39 -5
- package/dist/git-metadata.d.ts +5 -9
- package/dist/git-metadata.js +23 -42
- package/dist/guardrails.js +5 -0
- package/dist/helpers.d.ts +77 -27
- package/dist/helpers.js +150 -39
- package/dist/hibernation-config.d.ts +13 -0
- package/dist/hibernation-config.js +14 -0
- package/dist/home-tab.d.ts +13 -2
- package/dist/imessage-tools.d.ts +4 -1
- package/dist/inbox-drain-runtime.d.ts +1 -0
- package/dist/inbox-drain-runtime.js +5 -1
- package/dist/index.js +340 -108
- package/dist/pinet-commands.d.ts +14 -1
- package/dist/pinet-commands.js +93 -22
- package/dist/pinet-mesh-ops.d.ts +6 -4
- package/dist/pinet-mesh-ops.js +8 -1
- package/dist/pinet-runtime-composition.d.ts +2 -1
- package/dist/pinet-runtime-composition.js +14 -3
- package/dist/pinet-session-formatting.d.ts +26 -2
- package/dist/pinet-session-formatting.js +2 -0
- package/dist/pinet-tools.d.ts +14 -0
- package/dist/pinet-tools.js +355 -50
- package/dist/prompts/broker/default.md +3 -3
- package/dist/prompts/broker/tmux.md +3 -3
- package/dist/runtime-agent-context.d.ts +3 -3
- package/dist/runtime-agent-context.js +12 -6
- package/dist/runtime-mode.js +4 -0
- package/dist/session-ui-runtime.js +3 -1
- package/dist/single-player-runtime.d.ts +1 -1
- package/dist/single-player-runtime.js +21 -5
- package/dist/slack-access.d.ts +10 -2
- package/dist/slack-access.js +64 -22
- package/dist/slack-block-kit.d.ts +44 -2
- package/dist/slack-block-kit.js +5 -5
- package/dist/slack-file-access.d.ts +12 -1
- package/dist/slack-file-access.js +4 -4
- package/dist/slack-message-context.d.ts +9 -2
- package/dist/slack-modals.d.ts +4 -1
- package/dist/slack-modals.js +5 -5
- package/dist/slack-pinet-runtime-adapter.d.ts +1 -0
- package/dist/slack-pinet-runtime-adapter.js +10 -0
- package/dist/slack-presence.d.ts +5 -4
- package/dist/slack-request-runtime.d.ts +3 -2
- package/dist/slack-scope-diagnostics.d.ts +27 -2
- package/dist/slack-socket-dedup.d.ts +8 -5
- package/dist/slack-tools.d.ts +3 -1
- package/dist/slack-tools.js +26 -16
- package/dist/slack-upload.d.ts +17 -1
- package/dist/subtree-broker-runtime.d.ts +83 -2
- package/dist/subtree-broker-runtime.js +774 -109
- package/dist/tool-output-limits.d.ts +11 -0
- package/dist/tool-output-limits.js +20 -0
- package/dist/tool-registration-runtime.d.ts +3 -0
- package/dist/tool-registration-runtime.js +27 -0
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
|
-
import {
|
|
4
|
-
import { loadSettings as loadSettingsFromFile, buildAllowlist, reloadPinetRuntimeSafely, buildPinetOwnerToken, resolveAgentIdentity, resolveBrokerStableId, resolveAgentStableId, resolveAllowAllWorkspaceUsers, trackBrokerInboundThread, } from "./helpers.js";
|
|
3
|
+
import { probeGitBranch, probeGitContext } from "./git-metadata.js";
|
|
4
|
+
import { loadSettings as loadSettingsFromFile, buildAllowlist, resolvePinetMeshAuth, reloadPinetRuntimeInPlaceSafely, reloadPinetRuntimeSafely, buildPinetOwnerToken, resolveAgentIdentity, resolveBrokerStableId, resolveAgentStableId, resolveAllowAllWorkspaceUsers, trackBrokerInboundThread, isAbortError, } from "./helpers.js";
|
|
5
5
|
import { buildSecurityPrompt } from "./guardrails.js";
|
|
6
6
|
import { TtlCache, TtlSet } from "./ttl-cache.js";
|
|
7
7
|
import { resolveReactionCommands } from "./reaction-triggers.js";
|
|
8
|
-
import {
|
|
8
|
+
import { inspectBrokerLock, probeBrokerSocket, replaceBrokerOwner, } from "./broker/index.js";
|
|
9
|
+
import { readMeshSecret } from "./broker/auth.js";
|
|
10
|
+
import { collectAgentLifecycleStatuses, } from "@pinet/broker-core";
|
|
11
|
+
import { resolveHibernationSettings } from "./hibernation-config.js";
|
|
9
12
|
import { createCommandRegistrationRuntime } from "./command-registration-runtime.js";
|
|
10
13
|
import { createToolRegistrationRuntime } from "./tool-registration-runtime.js";
|
|
11
14
|
import { createSlackRuntimeAccess } from "./slack-runtime-access.js";
|
|
12
15
|
import { createThreadConfirmationPolicy } from "./thread-confirmations.js";
|
|
13
16
|
import { persistDeliveredInboundMessage } from "./broker-inbound-persistence.js";
|
|
17
|
+
import { createCompactionGate } from "./compaction-gate.js";
|
|
14
18
|
import { createIMessageAdapter, detectIMessageMvpEnvironment, formatIMessageMvpReadiness, } from "@pinet/imessage-bridge";
|
|
15
19
|
import { SLACK_SOCKET_DELIVERY_DEDUP_MAX_SIZE, SLACK_SOCKET_DELIVERY_DEDUP_TTL_MS, } from "./slack-access.js";
|
|
16
20
|
import { createFollowerDeliveryState, markFollowerInboxIdsDelivered, queueFollowerInboxIds, } from "./follower-delivery.js";
|
|
17
|
-
import { createFollowerRuntime } from "./follower-runtime.js";
|
|
21
|
+
import { createFollowerRuntime, resolveBrokerSocketPath, } from "./follower-runtime.js";
|
|
18
22
|
import { createSinglePlayerRuntime, } from "./single-player-runtime.js";
|
|
19
23
|
import { createBrokerRuntime } from "./broker-runtime.js";
|
|
20
24
|
import { createSlackPinetRuntimeAdapterFactory } from "./slack-pinet-runtime-adapter.js";
|
|
@@ -42,7 +46,8 @@ import { formatSlackAgentsDashboard, formatSlackAgentsUsage, isSlackAgentCommand
|
|
|
42
46
|
import { createPinetRegistrationGate } from "./pinet-registration-gate.js";
|
|
43
47
|
import { createBrokerRuntimeAccess } from "./broker-runtime-access.js";
|
|
44
48
|
import { createInboxDrainRuntime } from "./inbox-drain-runtime.js";
|
|
45
|
-
import { createSubtreeBrokerRuntime } from "./subtree-broker-runtime.js";
|
|
49
|
+
import { createSubtreeBrokerRuntime, getExtensionEntryPath, SUBTREE_INHERITED_ENV_KEYS, } from "./subtree-broker-runtime.js";
|
|
50
|
+
import { routeHibernationCommand } from "./broker/hibernation-command-router.js";
|
|
46
51
|
import { createAgentCompletionRuntime } from "./agent-completion-runtime.js";
|
|
47
52
|
import { sendBrokerMessage } from "./broker/message-send.js";
|
|
48
53
|
import { SlackThreadStatusManager } from "./slack-thread-status.js";
|
|
@@ -144,13 +149,20 @@ export default function (pi) {
|
|
|
144
149
|
},
|
|
145
150
|
});
|
|
146
151
|
const { updateBadge, setExtStatus, maybeDrainInboxIfIdle } = sessionUiRuntime;
|
|
152
|
+
const compactionGate = createCompactionGate(() => {
|
|
153
|
+
maybeDrainInboxIfIdle();
|
|
154
|
+
const ctx = sessionUiRuntime.getExtensionContext();
|
|
155
|
+
if (ctx)
|
|
156
|
+
subtreeBrokerRuntime.drainInbox(ctx);
|
|
157
|
+
});
|
|
158
|
+
const isIdleAndNotCompacting = () => !compactionGate.isActive() && (sessionUiRuntime.getExtensionContext()?.isIdle?.() ?? true);
|
|
147
159
|
let reportAgentStatus = async () => { };
|
|
148
160
|
let deliverTrackedSlackFollowUpMessage = () => false;
|
|
149
161
|
const inboxDrainRuntime = createInboxDrainRuntime({
|
|
150
162
|
sendUserMessage: (body) => {
|
|
151
163
|
pi.sendUserMessage(body);
|
|
152
164
|
},
|
|
153
|
-
isIdle:
|
|
165
|
+
isIdle: isIdleAndNotCompacting,
|
|
154
166
|
takeInboxMessages: (maxMessages) => inbox.splice(0, maxMessages ?? inbox.length),
|
|
155
167
|
restoreInboxMessages: (messages) => {
|
|
156
168
|
inbox.unshift(...messages);
|
|
@@ -166,12 +178,31 @@ export default function (pi) {
|
|
|
166
178
|
markBrokerInboxIdsDelivered: (inboxIds) => {
|
|
167
179
|
brokerRuntime.markDelivered(inboxIds);
|
|
168
180
|
},
|
|
181
|
+
markSubtreeInboxIdsDelivered: (inboxIds) => {
|
|
182
|
+
subtreeBrokerRuntime.markDelivered(inboxIds);
|
|
183
|
+
},
|
|
169
184
|
getFollowerDeliveryState: () => followerDeliveryState,
|
|
170
185
|
});
|
|
171
186
|
const { deliverFollowUpMessage, flushDeliveredFollowerAcks, drainInbox } = inboxDrainRuntime;
|
|
172
187
|
drainInboxPort = drainInbox;
|
|
188
|
+
function deliverSteeringMessage(text, ctx) {
|
|
189
|
+
try {
|
|
190
|
+
return compactionGate.tryDeliver(() => {
|
|
191
|
+
if (ctx.isIdle?.() ?? true) {
|
|
192
|
+
pi.sendUserMessage(text);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
pi.sendUserMessage(text, { deliverAs: "steer" });
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
console.error(`[slack-bridge] Pinet steering delivery failed: ${msg(error)}`);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
173
204
|
// ─── Helpers ─────────────────────────────────────────
|
|
174
|
-
|
|
205
|
+
let gitContext = null;
|
|
175
206
|
const runtimeAgentContext = createRuntimeAgentContext({
|
|
176
207
|
cwd: process.cwd(),
|
|
177
208
|
getSettings: () => settings,
|
|
@@ -230,7 +261,10 @@ export default function (pi) {
|
|
|
230
261
|
getExtensionContext: sessionUiRuntime.getExtensionContext,
|
|
231
262
|
persistState,
|
|
232
263
|
updateBadge,
|
|
233
|
-
getGitContext: () =>
|
|
264
|
+
getGitContext: async (signal) => {
|
|
265
|
+
gitContext ??= await probeGitContext(process.cwd(), undefined, signal);
|
|
266
|
+
return gitContext;
|
|
267
|
+
},
|
|
234
268
|
});
|
|
235
269
|
const { isUserAllowed, maybeWarnSlackUserAccess, maybeWarnSlackGuardrailPosture, applyLocalAgentIdentity, refreshSettings, snapshotReloadableRuntime, restoreReloadableRuntime, getAgentMetadata, getMeshRoleFromMetadata, buildSkinMetadata, applyRegistrationIdentity, } = runtimeAgentContext;
|
|
236
270
|
async function refreshSlackScopeDiagnostics(ctx) {
|
|
@@ -371,7 +405,6 @@ export default function (pi) {
|
|
|
371
405
|
beginThreadStatus: (channel, threadTs, status) => slackThreadStatuses.begin(channel, threadTs, status),
|
|
372
406
|
updateThreadStatus: (channel, threadTs, status) => slackThreadStatuses.update(channel, threadTs, status),
|
|
373
407
|
clearThreadStatus: (channel, threadTs) => slackThreadStatuses.clear(channel, threadTs),
|
|
374
|
-
beforeAgentStart: agentPromptGuidance.beforeAgentStart,
|
|
375
408
|
onCompletionAgentEnd: agentCompletionRuntime.onAgentEnd,
|
|
376
409
|
setDeliverTrackedSlackFollowUpMessage: (deliver) => {
|
|
377
410
|
deliverTrackedSlackFollowUpMessage = deliver;
|
|
@@ -380,7 +413,7 @@ export default function (pi) {
|
|
|
380
413
|
const pinetMaintenanceDelivery = createPinetMaintenanceDelivery({
|
|
381
414
|
getActiveBrokerDb,
|
|
382
415
|
getActiveBrokerSelfId,
|
|
383
|
-
isIdle:
|
|
416
|
+
isIdle: isIdleAndNotCompacting,
|
|
384
417
|
sendUserMessage: (body) => {
|
|
385
418
|
pi.sendUserMessage(body);
|
|
386
419
|
},
|
|
@@ -420,8 +453,15 @@ export default function (pi) {
|
|
|
420
453
|
pushInboxMessages: (messages) => {
|
|
421
454
|
inbox.push(...messages);
|
|
422
455
|
},
|
|
456
|
+
discardQueuedInboxMessages: () => {
|
|
457
|
+
for (let index = inbox.length - 1; index >= 0; index -= 1) {
|
|
458
|
+
if (inbox[index]?.brokerInboxOrigin === "subtree")
|
|
459
|
+
inbox.splice(index, 1);
|
|
460
|
+
}
|
|
461
|
+
},
|
|
423
462
|
updateBadge,
|
|
424
463
|
maybeDrainInboxIfIdle,
|
|
464
|
+
deliverSteeringMessage,
|
|
425
465
|
requestRemoteControl,
|
|
426
466
|
runRemoteControl,
|
|
427
467
|
formatError: msg,
|
|
@@ -499,6 +539,9 @@ export default function (pi) {
|
|
|
499
539
|
let currentRuntimeMode = "off";
|
|
500
540
|
let brokerRole = null;
|
|
501
541
|
let brokerClient = null;
|
|
542
|
+
let pinetLifecycleTail = Promise.resolve();
|
|
543
|
+
let pinetReloadPromise = null;
|
|
544
|
+
let pendingStartup = null;
|
|
502
545
|
let followerRuntimeDiagnostic = null;
|
|
503
546
|
const followerDeliveryState = createFollowerDeliveryState();
|
|
504
547
|
let desiredAgentStatus = "idle";
|
|
@@ -531,6 +574,7 @@ export default function (pi) {
|
|
|
531
574
|
getAppToken: () => appToken,
|
|
532
575
|
getAllowedUsers: () => allowedUsers,
|
|
533
576
|
shouldAllowAllWorkspaceUsers: () => resolveAllowAllWorkspaceUsers(settings, process.env.SLACK_ALLOW_ALL_WORKSPACE_USERS),
|
|
577
|
+
setExtStatus,
|
|
534
578
|
onAppHomeOpened: handleBrokerAppHomeOpened,
|
|
535
579
|
onSlashCommand: handleBrokerSlackSlashCommand,
|
|
536
580
|
});
|
|
@@ -615,6 +659,7 @@ export default function (pi) {
|
|
|
615
659
|
},
|
|
616
660
|
updateBadge,
|
|
617
661
|
maybeDrainInboxIfIdle,
|
|
662
|
+
deliverSteeringMessage,
|
|
618
663
|
requestRemoteControl,
|
|
619
664
|
deferControlAck: deferBrokerControlAck,
|
|
620
665
|
runRemoteControl,
|
|
@@ -644,6 +689,14 @@ export default function (pi) {
|
|
|
644
689
|
buildControlPlaneDashboardSnapshot: (input) => buildBrokerControlPlaneDashboardSnapshot(input),
|
|
645
690
|
buildCurrentDashboardSnapshot: async (openedAt) => buildCurrentBrokerControlPlaneDashboardSnapshot(openedAt),
|
|
646
691
|
createAdapterBindings: [slackPinetAdapterFactory],
|
|
692
|
+
onAdminShutdownRequested: async (ctx) => {
|
|
693
|
+
// `/pinet start replace` from another local session: stop being the
|
|
694
|
+
// broker but keep this session alive (issue #951).
|
|
695
|
+
ctx.ui.notify("Pinet broker shutdown requested by another local session (/pinet start replace). Stopping the broker runtime in this session.", "warning");
|
|
696
|
+
await runPinetLifecycle(() => stopPinetRuntime(ctx, { releaseIdentity: true }));
|
|
697
|
+
slackRequestRuntime.reset();
|
|
698
|
+
singlePlayerRuntime.resetShutdownState();
|
|
699
|
+
},
|
|
647
700
|
onMaintenanceResult: (ctx, { result, previousSignature, signature }) => {
|
|
648
701
|
if (signature && signature !== previousSignature) {
|
|
649
702
|
ctx.ui.notify(`Pinet broker: ${result.anomalies.join("; ")}`, "warning");
|
|
@@ -734,6 +787,25 @@ export default function (pi) {
|
|
|
734
787
|
},
|
|
735
788
|
});
|
|
736
789
|
const { sendPinetAgentMessage, sendPinetBroadcastMessage, scheduleBrokerWakeup, scheduleFollowerWakeup, listBrokerAgents, listFollowerAgents, searchPinetSessions, } = pinetMeshOps;
|
|
790
|
+
async function runHibernationCommand(command, target, reason) {
|
|
791
|
+
// Thin wrapper: DB-topology resolution + executor composition live in the
|
|
792
|
+
// extracted, independently-tested production router, so the live extension and
|
|
793
|
+
// the production-route E2E drive the exact same integration code. `brokerRole`,
|
|
794
|
+
// the runtime-activation authority (via the router's internal
|
|
795
|
+
// `hibernationRuntimeActive()` gate), the real subtree control accessor, and the
|
|
796
|
+
// central-DB fallback are all threaded through unchanged.
|
|
797
|
+
return routeHibernationCommand({
|
|
798
|
+
command,
|
|
799
|
+
target,
|
|
800
|
+
...(reason !== undefined ? { reason } : {}),
|
|
801
|
+
brokerRole,
|
|
802
|
+
hib: resolveHibernationSettings(settings),
|
|
803
|
+
getRuntimeControl: () => subtreeBrokerRuntime.getHibernationRuntimeControl(),
|
|
804
|
+
getFallbackDb: () => getActiveBrokerDb(),
|
|
805
|
+
extensionEntryPath: getExtensionEntryPath(),
|
|
806
|
+
inheritedEnvKeys: SUBTREE_INHERITED_ENV_KEYS,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
737
809
|
async function listPinetLanes(options) {
|
|
738
810
|
if (brokerRole === "broker") {
|
|
739
811
|
const db = getActiveBrokerDb();
|
|
@@ -880,104 +952,185 @@ export default function (pi) {
|
|
|
880
952
|
}
|
|
881
953
|
throw new Error("Pinet is in an unexpected state.");
|
|
882
954
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
955
|
+
function runPinetLifecycle(operation) {
|
|
956
|
+
const run = pinetLifecycleTail.then(operation, operation);
|
|
957
|
+
pinetLifecycleTail = run.then(() => undefined, () => undefined);
|
|
958
|
+
return run;
|
|
959
|
+
}
|
|
960
|
+
async function cancelPendingStartup() {
|
|
961
|
+
const startup = pendingStartup;
|
|
962
|
+
if (!startup)
|
|
888
963
|
return;
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
964
|
+
startup.controller.abort();
|
|
965
|
+
await startup.promise;
|
|
966
|
+
}
|
|
967
|
+
function runRuntimeModeTransition(ctx, mode, signal) {
|
|
968
|
+
return runPinetLifecycle(async () => {
|
|
969
|
+
signal?.throwIfAborted();
|
|
970
|
+
if (currentRuntimeMode === mode) {
|
|
971
|
+
if (mode === "off") {
|
|
972
|
+
setExtStatus(ctx, "off");
|
|
973
|
+
}
|
|
974
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (currentRuntimeMode !== "off") {
|
|
978
|
+
if (pinetReloadPromise) {
|
|
979
|
+
await pinetReloadPromise.catch(() => undefined);
|
|
980
|
+
}
|
|
981
|
+
await stopPinetRuntime(ctx, { releaseIdentity: true });
|
|
982
|
+
signal?.throwIfAborted();
|
|
983
|
+
}
|
|
894
984
|
slackRequestRuntime.reset();
|
|
895
985
|
singlePlayerRuntime.resetShutdownState();
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
986
|
+
if (mode === "off") {
|
|
987
|
+
currentRuntimeMode = "off";
|
|
988
|
+
setExtStatus(ctx, "off");
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
if (mode === "single") {
|
|
992
|
+
currentRuntimeMode = "single";
|
|
993
|
+
setExtStatus(ctx, "reconnecting");
|
|
994
|
+
await singlePlayerRuntime.connect(ctx, signal);
|
|
995
|
+
signal?.throwIfAborted();
|
|
996
|
+
botUserId = singlePlayerRuntime.getBotUserId() ?? botUserId;
|
|
997
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
998
|
+
signal?.throwIfAborted();
|
|
999
|
+
void ensureSlackScopeDiagnostics(ctx);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (mode === "broker") {
|
|
1003
|
+
await connectAsBroker(ctx, {}, signal);
|
|
1004
|
+
signal?.throwIfAborted();
|
|
1005
|
+
void ensureSlackScopeDiagnostics(ctx);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
await connectAsFollower(ctx, signal);
|
|
1009
|
+
signal?.throwIfAborted();
|
|
907
1010
|
void ensureSlackScopeDiagnostics(ctx);
|
|
908
|
-
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
async function transitionToRuntimeMode(ctx, mode) {
|
|
1014
|
+
await cancelPendingStartup();
|
|
1015
|
+
await runRuntimeModeTransition(ctx, mode);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Resolve the local mesh secret value for client-side broker RPCs
|
|
1019
|
+
* (graceful takeover). Returns null when no secret is configured or the
|
|
1020
|
+
* secret file is unreadable — callers degrade to fenced termination.
|
|
1021
|
+
*/
|
|
1022
|
+
function resolveLocalMeshSecretValue() {
|
|
1023
|
+
const meshAuth = resolvePinetMeshAuth(settings);
|
|
1024
|
+
if (meshAuth.meshSecret) {
|
|
1025
|
+
return meshAuth.meshSecret;
|
|
909
1026
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1027
|
+
try {
|
|
1028
|
+
return meshAuth.meshSecretPath ? readMeshSecret(meshAuth.meshSecretPath) : readMeshSecret();
|
|
1029
|
+
}
|
|
1030
|
+
catch {
|
|
1031
|
+
return null;
|
|
914
1032
|
}
|
|
915
|
-
await connectAsFollower(ctx);
|
|
916
|
-
void ensureSlackScopeDiagnostics(ctx);
|
|
917
1033
|
}
|
|
918
1034
|
async function stopPinetRuntime(ctx, options) {
|
|
919
1035
|
flushPersist();
|
|
920
1036
|
await subtreeBrokerRuntime.stop({ releaseIdentity: options.releaseIdentity });
|
|
921
1037
|
await brokerRuntime.disconnect({ releaseIdentity: options.releaseIdentity });
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
await followerRuntime.disconnect(ctx, { releaseIdentity: false }).catch(() => {
|
|
930
|
-
/* best effort */
|
|
931
|
-
});
|
|
932
|
-
brokerClient = null;
|
|
933
|
-
desiredAgentStatus = "idle";
|
|
934
|
-
brokerRole = null;
|
|
935
|
-
pinetEnabled = false;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
1038
|
+
await followerRuntime
|
|
1039
|
+
.disconnect(ctx, { releaseIdentity: options.releaseIdentity })
|
|
1040
|
+
.catch(() => {
|
|
1041
|
+
/* best effort */
|
|
1042
|
+
});
|
|
1043
|
+
brokerClient = null;
|
|
1044
|
+
followerRuntimeDiagnostic = null;
|
|
938
1045
|
await singlePlayerRuntime.disconnect();
|
|
939
1046
|
brokerRole = null;
|
|
940
1047
|
pinetEnabled = false;
|
|
941
1048
|
desiredAgentStatus = "idle";
|
|
942
1049
|
currentRuntimeMode = "off";
|
|
943
1050
|
setExtStatus(ctx, "off");
|
|
1051
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
944
1052
|
}
|
|
945
1053
|
async function reloadPinetRuntime(ctx) {
|
|
946
|
-
await
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
},
|
|
955
|
-
validateRefreshedState: () => {
|
|
1054
|
+
await cancelPendingStartup();
|
|
1055
|
+
if (pinetReloadPromise) {
|
|
1056
|
+
await pinetReloadPromise;
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const reloadWork = runPinetLifecycle(async () => {
|
|
1060
|
+
let reloadBrokerInPlace = false;
|
|
1061
|
+
const validateRefreshedState = () => {
|
|
956
1062
|
if (!botToken || !appToken) {
|
|
957
1063
|
throw new Error("Slack tokens are not configured after reload.");
|
|
958
1064
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
await stopPinetRuntime(ctx, { releaseIdentity: false });
|
|
962
|
-
// Reload intentionally keeps the extension alive in-process, so restore a
|
|
963
|
-
// fresh top-level Slack request tracker after aborting the previous
|
|
964
|
-
// generation. This preserves shutdown abort semantics without leaving
|
|
965
|
-
// top-level Slack tools permanently stuck in "shutdown in progress".
|
|
966
|
-
slackRequestRuntime.reset();
|
|
967
|
-
singlePlayerRuntime.resetShutdownState();
|
|
968
|
-
setExtStatus(ctx, "reconnecting");
|
|
969
|
-
},
|
|
970
|
-
startRuntime: async (role) => {
|
|
971
|
-
if (role === "broker") {
|
|
972
|
-
await connectAsBroker(ctx);
|
|
973
|
-
return;
|
|
1065
|
+
if (brokerRole === "broker") {
|
|
1066
|
+
reloadBrokerInPlace = brokerRuntime.canReloadInPlace();
|
|
974
1067
|
}
|
|
975
|
-
|
|
976
|
-
|
|
1068
|
+
};
|
|
1069
|
+
if (brokerRole === "broker") {
|
|
1070
|
+
await reloadPinetRuntimeInPlaceSafely({
|
|
1071
|
+
snapshotState: () => snapshotReloadableRuntime(),
|
|
1072
|
+
restoreState: (snapshot) => {
|
|
1073
|
+
restoreReloadableRuntime(snapshot);
|
|
1074
|
+
},
|
|
1075
|
+
refreshState: () => {
|
|
1076
|
+
refreshSettings();
|
|
1077
|
+
},
|
|
1078
|
+
validateRefreshedState,
|
|
1079
|
+
reloadRuntime: async () => {
|
|
1080
|
+
if (reloadBrokerInPlace) {
|
|
1081
|
+
const result = await brokerRuntime.reloadAdapters(ctx);
|
|
1082
|
+
botUserId = result.botUserId;
|
|
1083
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
await stopPinetRuntime(ctx, { releaseIdentity: false });
|
|
1087
|
+
slackRequestRuntime.reset();
|
|
1088
|
+
singlePlayerRuntime.resetShutdownState();
|
|
1089
|
+
setExtStatus(ctx, "reconnecting");
|
|
1090
|
+
await connectAsBroker(ctx, { refreshSettings: false });
|
|
1091
|
+
},
|
|
1092
|
+
});
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
await reloadPinetRuntimeSafely({
|
|
1096
|
+
getCurrentRole: () => brokerRole,
|
|
1097
|
+
snapshotState: () => snapshotReloadableRuntime(),
|
|
1098
|
+
restoreState: (snapshot) => {
|
|
1099
|
+
restoreReloadableRuntime(snapshot);
|
|
1100
|
+
},
|
|
1101
|
+
refreshState: () => {
|
|
1102
|
+
refreshSettings();
|
|
1103
|
+
},
|
|
1104
|
+
validateRefreshedState,
|
|
1105
|
+
stopRuntime: async () => {
|
|
1106
|
+
await stopPinetRuntime(ctx, { releaseIdentity: false });
|
|
1107
|
+
// Reload intentionally keeps the extension alive in-process, so restore a
|
|
1108
|
+
// fresh top-level Slack request tracker after aborting the previous
|
|
1109
|
+
// generation. This preserves shutdown abort semantics without leaving
|
|
1110
|
+
// top-level Slack tools permanently stuck in "shutdown in progress".
|
|
1111
|
+
slackRequestRuntime.reset();
|
|
1112
|
+
singlePlayerRuntime.resetShutdownState();
|
|
1113
|
+
setExtStatus(ctx, "reconnecting");
|
|
1114
|
+
},
|
|
1115
|
+
startRuntime: async (role) => {
|
|
1116
|
+
if (role === "broker") {
|
|
1117
|
+
await connectAsBroker(ctx);
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
await connectAsFollower(ctx);
|
|
1121
|
+
},
|
|
1122
|
+
});
|
|
1123
|
+
}).finally(() => {
|
|
1124
|
+
if (pinetReloadPromise === reloadWork) {
|
|
1125
|
+
pinetReloadPromise = null;
|
|
1126
|
+
}
|
|
977
1127
|
});
|
|
1128
|
+
pinetReloadPromise = reloadWork;
|
|
1129
|
+
await reloadWork;
|
|
978
1130
|
}
|
|
979
1131
|
// ─── Tools ──────────────────────────────────────────
|
|
980
1132
|
const toolRegistrationRuntime = createToolRegistrationRuntime({
|
|
1133
|
+
buildPromptGuidelines: agentPromptGuidance.buildPromptGuidelines,
|
|
981
1134
|
slackTools: {
|
|
982
1135
|
getBotToken: () => {
|
|
983
1136
|
if (!botToken) {
|
|
@@ -994,6 +1147,9 @@ export default function (pi) {
|
|
|
994
1147
|
getAgentOwnerToken: () => agentOwnerToken,
|
|
995
1148
|
getLastDmChannel: () => lastDmChannel,
|
|
996
1149
|
updateBadge,
|
|
1150
|
+
markSubtreeInboxIdsDelivered: (inboxIds) => {
|
|
1151
|
+
subtreeBrokerRuntime.markDelivered(inboxIds);
|
|
1152
|
+
},
|
|
997
1153
|
resolveUser,
|
|
998
1154
|
threadContext: singlePlayerRuntime.getThreadContextPort(),
|
|
999
1155
|
resolveChannel,
|
|
@@ -1094,6 +1250,21 @@ export default function (pi) {
|
|
|
1094
1250
|
ralphSnoozeStatus: () => currentRuntimeMode === "broker" ? brokerRuntime.getRalphSnoozeStatus() : null,
|
|
1095
1251
|
snoozeRalphLoop: (input) => brokerRuntime.snoozeRalphLoop(input),
|
|
1096
1252
|
clearRalphSnooze: () => brokerRuntime.clearRalphSnooze(),
|
|
1253
|
+
runHibernateCommand: ({ target, reason }) => runHibernationCommand("hibernate", target, reason),
|
|
1254
|
+
runWakeCommand: ({ target, reason }) => runHibernationCommand("wake", target, reason),
|
|
1255
|
+
getAgentLifecycleProjection: (agentIds) => {
|
|
1256
|
+
if (brokerRole !== "broker")
|
|
1257
|
+
return [];
|
|
1258
|
+
const db = getActiveBrokerDb();
|
|
1259
|
+
if (!db)
|
|
1260
|
+
return [];
|
|
1261
|
+
const hib = resolveHibernationSettings(settings);
|
|
1262
|
+
return collectAgentLifecycleStatuses(db, {
|
|
1263
|
+
...(agentIds ? { agentIds } : {}),
|
|
1264
|
+
maxConcurrentWakes: hib.maxConcurrentWakes,
|
|
1265
|
+
maxConcurrentWakesPerRepo: hib.maxConcurrentWakesPerRepo,
|
|
1266
|
+
});
|
|
1267
|
+
},
|
|
1097
1268
|
},
|
|
1098
1269
|
iMessageTools: {
|
|
1099
1270
|
pinetEnabled: () => pinetEnabled,
|
|
@@ -1123,11 +1294,16 @@ export default function (pi) {
|
|
|
1123
1294
|
});
|
|
1124
1295
|
toolRegistrationRuntime.register(pi);
|
|
1125
1296
|
// ─── Commands ───────────────────────────────────────
|
|
1126
|
-
async function connectAsBroker(ctx) {
|
|
1127
|
-
|
|
1297
|
+
async function connectAsBroker(ctx, options = {}, signal) {
|
|
1298
|
+
signal?.throwIfAborted();
|
|
1299
|
+
setExtStatus(ctx, "reconnecting");
|
|
1300
|
+
if (options.refreshSettings !== false) {
|
|
1301
|
+
refreshSettings();
|
|
1302
|
+
}
|
|
1128
1303
|
maybeWarnSlackUserAccess(ctx);
|
|
1129
1304
|
maybeWarnSlackGuardrailPosture(ctx);
|
|
1130
|
-
const { botUserId: brokerBotUserId, recoveredBrokerMessages, recoveredTargetedBacklogCount, releasedBrokerClaims, } = await brokerRuntime.connect(ctx);
|
|
1305
|
+
const { botUserId: brokerBotUserId, recoveredBrokerMessages, recoveredTargetedBacklogCount, releasedBrokerClaims, } = await brokerRuntime.connect(ctx, signal);
|
|
1306
|
+
signal?.throwIfAborted();
|
|
1131
1307
|
const broker = brokerRuntime.getBroker();
|
|
1132
1308
|
if (!broker) {
|
|
1133
1309
|
throw new Error("Broker runtime failed to initialize.");
|
|
@@ -1149,8 +1325,18 @@ export default function (pi) {
|
|
|
1149
1325
|
else {
|
|
1150
1326
|
try {
|
|
1151
1327
|
const imessageAdapter = createIMessageAdapter();
|
|
1152
|
-
|
|
1153
|
-
|
|
1328
|
+
const abortConnect = () => {
|
|
1329
|
+
void imessageAdapter.disconnect().catch(() => undefined);
|
|
1330
|
+
};
|
|
1331
|
+
signal?.addEventListener("abort", abortConnect, { once: true });
|
|
1332
|
+
try {
|
|
1333
|
+
await imessageAdapter.connect();
|
|
1334
|
+
signal?.throwIfAborted();
|
|
1335
|
+
broker.addAdapter(imessageAdapter);
|
|
1336
|
+
}
|
|
1337
|
+
finally {
|
|
1338
|
+
signal?.removeEventListener("abort", abortConnect);
|
|
1339
|
+
}
|
|
1154
1340
|
if (environment.blockers.length > 0) {
|
|
1155
1341
|
ctx.ui.notify(`iMessage send-first mode enabled — ${readinessSummary}`, "warning");
|
|
1156
1342
|
brokerRuntime.logActivity({
|
|
@@ -1174,11 +1360,13 @@ export default function (pi) {
|
|
|
1174
1360
|
}
|
|
1175
1361
|
}
|
|
1176
1362
|
}
|
|
1363
|
+
signal?.throwIfAborted();
|
|
1177
1364
|
broker.server.setOutboundMessageAdapters?.(broker.adapters);
|
|
1178
1365
|
brokerRole = "broker";
|
|
1179
1366
|
pinetEnabled = true;
|
|
1180
1367
|
desiredAgentStatus = "idle";
|
|
1181
1368
|
currentRuntimeMode = "broker";
|
|
1369
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1182
1370
|
if (recoveredBrokerMessages > 0 || releasedBrokerClaims > 0) {
|
|
1183
1371
|
const recoveredTargetedDetail = recoveredTargetedBacklogCount > 0
|
|
1184
1372
|
? ` including ${recoveredTargetedBacklogCount} recovered targeted backlog item${recoveredTargetedBacklogCount === 1 ? "" : "s"}`
|
|
@@ -1186,7 +1374,6 @@ export default function (pi) {
|
|
|
1186
1374
|
ctx.ui.notify(`Pinet broker recovered ${recoveredBrokerMessages} pending message${recoveredBrokerMessages === 1 ? "" : "s"}${recoveredTargetedDetail} and released ${releasedBrokerClaims} broker-owned thread claim${releasedBrokerClaims === 1 ? "" : "s"}`, "info");
|
|
1187
1375
|
}
|
|
1188
1376
|
brokerRuntime.startObservability(ctx);
|
|
1189
|
-
setExtStatus(ctx, "ok");
|
|
1190
1377
|
brokerRuntime.logActivity({
|
|
1191
1378
|
kind: "broker_started",
|
|
1192
1379
|
level: "actions",
|
|
@@ -1234,6 +1421,11 @@ export default function (pi) {
|
|
|
1234
1421
|
},
|
|
1235
1422
|
getAgentMetadata,
|
|
1236
1423
|
applyRegistrationIdentity,
|
|
1424
|
+
onRegistrationIdentityApplied: async () => {
|
|
1425
|
+
if (currentRuntimeMode === "follower") {
|
|
1426
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1237
1429
|
persistState,
|
|
1238
1430
|
updateBadge,
|
|
1239
1431
|
maybeDrainInboxIfIdle,
|
|
@@ -1241,6 +1433,7 @@ export default function (pi) {
|
|
|
1241
1433
|
deferControlAck: deferFollowerControlAck,
|
|
1242
1434
|
runRemoteControl,
|
|
1243
1435
|
deliverFollowUpMessage,
|
|
1436
|
+
deliverSteeringMessage,
|
|
1244
1437
|
setExtStatus,
|
|
1245
1438
|
getRuntimeDiagnostic: () => followerRuntimeDiagnostic,
|
|
1246
1439
|
setRuntimeDiagnostic: (diagnostic) => {
|
|
@@ -1293,7 +1486,15 @@ export default function (pi) {
|
|
|
1293
1486
|
lastBrokerControlPlaneHomeTabRefreshAt: () => brokerRuntime.getLastHomeTabRefreshAt(),
|
|
1294
1487
|
lastBrokerControlPlaneHomeTabError: () => brokerRuntime.getLastHomeTabError(),
|
|
1295
1488
|
subtreeBrokerStatus: () => subtreeBrokerRuntime.getStatus(),
|
|
1489
|
+
inspectGlobalBroker: async () => {
|
|
1490
|
+
const lock = inspectBrokerLock();
|
|
1491
|
+
if (lock.state !== "alive") {
|
|
1492
|
+
return { lock, probe: null };
|
|
1493
|
+
}
|
|
1494
|
+
return { lock, probe: await probeBrokerSocket() };
|
|
1495
|
+
},
|
|
1296
1496
|
getPinetRegistrationBlockReason: pinetRegistrationGate.getBlockReason,
|
|
1497
|
+
replaceGlobalBroker: async () => replaceBrokerOwner({ meshSecret: resolveLocalMeshSecretValue() }),
|
|
1297
1498
|
connectAsBroker: (ctx) => transitionToRuntimeMode(ctx, "broker"),
|
|
1298
1499
|
connectAsFollower: (ctx) => transitionToRuntimeMode(ctx, "follower"),
|
|
1299
1500
|
reloadPinetRuntime,
|
|
@@ -1303,21 +1504,27 @@ export default function (pi) {
|
|
|
1303
1504
|
spawnSubtreeWorker: (ctx, input) => subtreeBrokerRuntime.spawnWorker(ctx, input),
|
|
1304
1505
|
sendPinetAgentMessage,
|
|
1305
1506
|
signalAgentFree,
|
|
1306
|
-
applyLocalAgentIdentity,
|
|
1507
|
+
applyLocalAgentIdentity: async (name, emoji, personality) => {
|
|
1508
|
+
applyLocalAgentIdentity(name, emoji, personality);
|
|
1509
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1510
|
+
},
|
|
1307
1511
|
setExtStatus,
|
|
1308
1512
|
setExtCtx: sessionUiRuntime.setExtCtx,
|
|
1309
1513
|
},
|
|
1310
1514
|
});
|
|
1311
1515
|
commandRegistrationRuntime.register(pi);
|
|
1312
|
-
async function connectAsFollower(ctx) {
|
|
1516
|
+
async function connectAsFollower(ctx, signal) {
|
|
1517
|
+
signal?.throwIfAborted();
|
|
1313
1518
|
pinetRegistrationGate.assertCanRegister();
|
|
1314
|
-
const clientRef = await followerRuntime.connect(ctx);
|
|
1519
|
+
const clientRef = await followerRuntime.connect(ctx, signal);
|
|
1520
|
+
signal?.throwIfAborted();
|
|
1315
1521
|
brokerClient = clientRef;
|
|
1316
1522
|
followerRuntimeDiagnostic = null;
|
|
1317
1523
|
brokerRole = "follower";
|
|
1318
1524
|
pinetEnabled = true;
|
|
1319
1525
|
desiredAgentStatus = "idle";
|
|
1320
1526
|
currentRuntimeMode = "follower";
|
|
1527
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1321
1528
|
setExtStatus(ctx, "ok");
|
|
1322
1529
|
}
|
|
1323
1530
|
async function disconnectFollower(ctx, options = {}) {
|
|
@@ -1327,6 +1534,7 @@ export default function (pi) {
|
|
|
1327
1534
|
brokerRole = null;
|
|
1328
1535
|
pinetEnabled = false;
|
|
1329
1536
|
currentRuntimeMode = "off";
|
|
1537
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1330
1538
|
if (!options.preserveErrorState) {
|
|
1331
1539
|
followerRuntimeDiagnostic = null;
|
|
1332
1540
|
setExtStatus(ctx, "off");
|
|
@@ -1335,6 +1543,8 @@ export default function (pi) {
|
|
|
1335
1543
|
}
|
|
1336
1544
|
// ─── Lifecycle ──────────────────────────────────────
|
|
1337
1545
|
pi.on("session_start", async (_event, ctx) => {
|
|
1546
|
+
await cancelPendingStartup();
|
|
1547
|
+
compactionGate.reset();
|
|
1338
1548
|
singlePlayerRuntime.resetShutdownState();
|
|
1339
1549
|
slackRequestRuntime.reset();
|
|
1340
1550
|
resetRemoteControlState();
|
|
@@ -1347,43 +1557,65 @@ export default function (pi) {
|
|
|
1347
1557
|
console.log("[slack-bridge] detected local subagent context; skipping Pinet registration");
|
|
1348
1558
|
currentRuntimeMode = "off";
|
|
1349
1559
|
setExtStatus(ctx, "off");
|
|
1560
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1350
1561
|
return;
|
|
1351
1562
|
}
|
|
1352
1563
|
refreshSettings();
|
|
1353
1564
|
maybeWarnSlackUserAccess(ctx);
|
|
1354
1565
|
const startupMode = resolveSlackBridgeStartupRuntimeMode(settings, {
|
|
1355
|
-
brokerSocketExists: fs.existsSync(
|
|
1566
|
+
brokerSocketExists: fs.existsSync(resolveBrokerSocketPath()),
|
|
1356
1567
|
brokerManagedFollowerLaunch: isBrokerManagedFollowerLaunch(),
|
|
1357
1568
|
});
|
|
1358
|
-
|
|
1569
|
+
if (startupMode === "off") {
|
|
1359
1570
|
await transitionToRuntimeMode(ctx, startupMode);
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
await toolRegistrationRuntime.sync(pi, "off");
|
|
1574
|
+
setExtStatus(ctx, "reconnecting");
|
|
1575
|
+
const controller = new AbortController();
|
|
1576
|
+
const startupPromise = (async () => {
|
|
1577
|
+
try {
|
|
1578
|
+
await runRuntimeModeTransition(ctx, startupMode, controller.signal);
|
|
1579
|
+
if (startupMode === "single") {
|
|
1580
|
+
maybeWarnSlackGuardrailPosture(ctx);
|
|
1581
|
+
}
|
|
1582
|
+
console.log(`[slack-bridge] runtime mode: ${startupMode}`);
|
|
1363
1583
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1584
|
+
catch (error) {
|
|
1585
|
+
const cancelled = controller.signal.aborted || isAbortError(error);
|
|
1586
|
+
if (!cancelled) {
|
|
1587
|
+
console.error(`[slack-bridge] runtime start (${startupMode}) failed: ${msg(error)}`);
|
|
1588
|
+
}
|
|
1589
|
+
await runPinetLifecycle(() => stopPinetRuntime(ctx, { releaseIdentity: !cancelled })).catch((cleanupError) => {
|
|
1590
|
+
console.error(`[slack-bridge] runtime cleanup failed: ${msg(cleanupError)}`);
|
|
1591
|
+
});
|
|
1592
|
+
slackRequestRuntime.reset();
|
|
1593
|
+
singlePlayerRuntime.resetShutdownState();
|
|
1366
1594
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1595
|
+
finally {
|
|
1596
|
+
if (pendingStartup?.controller === controller)
|
|
1597
|
+
pendingStartup = null;
|
|
1369
1598
|
}
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
setExtStatus(ctx, "off");
|
|
1375
|
-
}
|
|
1599
|
+
})().catch((error) => {
|
|
1600
|
+
console.error(`[slack-bridge] background runtime start failed: ${msg(error)}`);
|
|
1601
|
+
});
|
|
1602
|
+
pendingStartup = { controller, promise: startupPromise };
|
|
1376
1603
|
});
|
|
1377
1604
|
// ─── Agent event wiring ──────────────────────────────
|
|
1378
1605
|
agentEventRuntime.register(pi);
|
|
1379
|
-
pi.on("
|
|
1380
|
-
|
|
1606
|
+
pi.on("session_before_compact", (event) => {
|
|
1607
|
+
compactionGate.begin(event.signal);
|
|
1608
|
+
});
|
|
1609
|
+
pi.on("session_compact", () => {
|
|
1610
|
+
compactionGate.end();
|
|
1381
1611
|
});
|
|
1382
1612
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
1613
|
+
compactionGate.reset();
|
|
1383
1614
|
resetRemoteControlState();
|
|
1384
1615
|
resetPendingRemoteControlAcks();
|
|
1385
1616
|
sessionUiRuntime.cleanupForSessionShutdown();
|
|
1386
|
-
await
|
|
1617
|
+
await cancelPendingStartup();
|
|
1618
|
+
await runPinetLifecycle(() => stopPinetRuntime(ctx, { releaseIdentity: true }));
|
|
1387
1619
|
pinetRegistrationGate.reset();
|
|
1388
1620
|
});
|
|
1389
1621
|
}
|