@pinet/slack-bridge 0.2.2 → 0.2.6
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 +316 -451
- 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 +26 -0
- package/dist/broker/socket-server.js +287 -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 +341 -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 +9 -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 +10 -0
- package/dist/slack-tools.js +51 -64
- 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,
|
|
@@ -1002,6 +1158,7 @@ export default function (pi) {
|
|
|
1002
1158
|
getBotUserId: () => botUserId,
|
|
1003
1159
|
registerConfirmationRequest,
|
|
1004
1160
|
pinetDelivery: {
|
|
1161
|
+
isEnabled: () => pinetEnabled,
|
|
1005
1162
|
isAvailable: () => pinetEnabled && brokerRole !== null,
|
|
1006
1163
|
sendSlackMessage: async (input) => {
|
|
1007
1164
|
const content = {
|
|
@@ -1093,6 +1250,21 @@ export default function (pi) {
|
|
|
1093
1250
|
ralphSnoozeStatus: () => currentRuntimeMode === "broker" ? brokerRuntime.getRalphSnoozeStatus() : null,
|
|
1094
1251
|
snoozeRalphLoop: (input) => brokerRuntime.snoozeRalphLoop(input),
|
|
1095
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
|
+
},
|
|
1096
1268
|
},
|
|
1097
1269
|
iMessageTools: {
|
|
1098
1270
|
pinetEnabled: () => pinetEnabled,
|
|
@@ -1122,11 +1294,16 @@ export default function (pi) {
|
|
|
1122
1294
|
});
|
|
1123
1295
|
toolRegistrationRuntime.register(pi);
|
|
1124
1296
|
// ─── Commands ───────────────────────────────────────
|
|
1125
|
-
async function connectAsBroker(ctx) {
|
|
1126
|
-
|
|
1297
|
+
async function connectAsBroker(ctx, options = {}, signal) {
|
|
1298
|
+
signal?.throwIfAborted();
|
|
1299
|
+
setExtStatus(ctx, "reconnecting");
|
|
1300
|
+
if (options.refreshSettings !== false) {
|
|
1301
|
+
refreshSettings();
|
|
1302
|
+
}
|
|
1127
1303
|
maybeWarnSlackUserAccess(ctx);
|
|
1128
1304
|
maybeWarnSlackGuardrailPosture(ctx);
|
|
1129
|
-
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();
|
|
1130
1307
|
const broker = brokerRuntime.getBroker();
|
|
1131
1308
|
if (!broker) {
|
|
1132
1309
|
throw new Error("Broker runtime failed to initialize.");
|
|
@@ -1148,8 +1325,18 @@ export default function (pi) {
|
|
|
1148
1325
|
else {
|
|
1149
1326
|
try {
|
|
1150
1327
|
const imessageAdapter = createIMessageAdapter();
|
|
1151
|
-
|
|
1152
|
-
|
|
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
|
+
}
|
|
1153
1340
|
if (environment.blockers.length > 0) {
|
|
1154
1341
|
ctx.ui.notify(`iMessage send-first mode enabled — ${readinessSummary}`, "warning");
|
|
1155
1342
|
brokerRuntime.logActivity({
|
|
@@ -1173,11 +1360,13 @@ export default function (pi) {
|
|
|
1173
1360
|
}
|
|
1174
1361
|
}
|
|
1175
1362
|
}
|
|
1363
|
+
signal?.throwIfAborted();
|
|
1176
1364
|
broker.server.setOutboundMessageAdapters?.(broker.adapters);
|
|
1177
1365
|
brokerRole = "broker";
|
|
1178
1366
|
pinetEnabled = true;
|
|
1179
1367
|
desiredAgentStatus = "idle";
|
|
1180
1368
|
currentRuntimeMode = "broker";
|
|
1369
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1181
1370
|
if (recoveredBrokerMessages > 0 || releasedBrokerClaims > 0) {
|
|
1182
1371
|
const recoveredTargetedDetail = recoveredTargetedBacklogCount > 0
|
|
1183
1372
|
? ` including ${recoveredTargetedBacklogCount} recovered targeted backlog item${recoveredTargetedBacklogCount === 1 ? "" : "s"}`
|
|
@@ -1185,7 +1374,6 @@ export default function (pi) {
|
|
|
1185
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");
|
|
1186
1375
|
}
|
|
1187
1376
|
brokerRuntime.startObservability(ctx);
|
|
1188
|
-
setExtStatus(ctx, "ok");
|
|
1189
1377
|
brokerRuntime.logActivity({
|
|
1190
1378
|
kind: "broker_started",
|
|
1191
1379
|
level: "actions",
|
|
@@ -1233,6 +1421,11 @@ export default function (pi) {
|
|
|
1233
1421
|
},
|
|
1234
1422
|
getAgentMetadata,
|
|
1235
1423
|
applyRegistrationIdentity,
|
|
1424
|
+
onRegistrationIdentityApplied: async () => {
|
|
1425
|
+
if (currentRuntimeMode === "follower") {
|
|
1426
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1236
1429
|
persistState,
|
|
1237
1430
|
updateBadge,
|
|
1238
1431
|
maybeDrainInboxIfIdle,
|
|
@@ -1240,6 +1433,7 @@ export default function (pi) {
|
|
|
1240
1433
|
deferControlAck: deferFollowerControlAck,
|
|
1241
1434
|
runRemoteControl,
|
|
1242
1435
|
deliverFollowUpMessage,
|
|
1436
|
+
deliverSteeringMessage,
|
|
1243
1437
|
setExtStatus,
|
|
1244
1438
|
getRuntimeDiagnostic: () => followerRuntimeDiagnostic,
|
|
1245
1439
|
setRuntimeDiagnostic: (diagnostic) => {
|
|
@@ -1292,7 +1486,15 @@ export default function (pi) {
|
|
|
1292
1486
|
lastBrokerControlPlaneHomeTabRefreshAt: () => brokerRuntime.getLastHomeTabRefreshAt(),
|
|
1293
1487
|
lastBrokerControlPlaneHomeTabError: () => brokerRuntime.getLastHomeTabError(),
|
|
1294
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
|
+
},
|
|
1295
1496
|
getPinetRegistrationBlockReason: pinetRegistrationGate.getBlockReason,
|
|
1497
|
+
replaceGlobalBroker: async () => replaceBrokerOwner({ meshSecret: resolveLocalMeshSecretValue() }),
|
|
1296
1498
|
connectAsBroker: (ctx) => transitionToRuntimeMode(ctx, "broker"),
|
|
1297
1499
|
connectAsFollower: (ctx) => transitionToRuntimeMode(ctx, "follower"),
|
|
1298
1500
|
reloadPinetRuntime,
|
|
@@ -1302,21 +1504,27 @@ export default function (pi) {
|
|
|
1302
1504
|
spawnSubtreeWorker: (ctx, input) => subtreeBrokerRuntime.spawnWorker(ctx, input),
|
|
1303
1505
|
sendPinetAgentMessage,
|
|
1304
1506
|
signalAgentFree,
|
|
1305
|
-
applyLocalAgentIdentity,
|
|
1507
|
+
applyLocalAgentIdentity: async (name, emoji, personality) => {
|
|
1508
|
+
applyLocalAgentIdentity(name, emoji, personality);
|
|
1509
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1510
|
+
},
|
|
1306
1511
|
setExtStatus,
|
|
1307
1512
|
setExtCtx: sessionUiRuntime.setExtCtx,
|
|
1308
1513
|
},
|
|
1309
1514
|
});
|
|
1310
1515
|
commandRegistrationRuntime.register(pi);
|
|
1311
|
-
async function connectAsFollower(ctx) {
|
|
1516
|
+
async function connectAsFollower(ctx, signal) {
|
|
1517
|
+
signal?.throwIfAborted();
|
|
1312
1518
|
pinetRegistrationGate.assertCanRegister();
|
|
1313
|
-
const clientRef = await followerRuntime.connect(ctx);
|
|
1519
|
+
const clientRef = await followerRuntime.connect(ctx, signal);
|
|
1520
|
+
signal?.throwIfAborted();
|
|
1314
1521
|
brokerClient = clientRef;
|
|
1315
1522
|
followerRuntimeDiagnostic = null;
|
|
1316
1523
|
brokerRole = "follower";
|
|
1317
1524
|
pinetEnabled = true;
|
|
1318
1525
|
desiredAgentStatus = "idle";
|
|
1319
1526
|
currentRuntimeMode = "follower";
|
|
1527
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1320
1528
|
setExtStatus(ctx, "ok");
|
|
1321
1529
|
}
|
|
1322
1530
|
async function disconnectFollower(ctx, options = {}) {
|
|
@@ -1326,6 +1534,7 @@ export default function (pi) {
|
|
|
1326
1534
|
brokerRole = null;
|
|
1327
1535
|
pinetEnabled = false;
|
|
1328
1536
|
currentRuntimeMode = "off";
|
|
1537
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1329
1538
|
if (!options.preserveErrorState) {
|
|
1330
1539
|
followerRuntimeDiagnostic = null;
|
|
1331
1540
|
setExtStatus(ctx, "off");
|
|
@@ -1334,6 +1543,8 @@ export default function (pi) {
|
|
|
1334
1543
|
}
|
|
1335
1544
|
// ─── Lifecycle ──────────────────────────────────────
|
|
1336
1545
|
pi.on("session_start", async (_event, ctx) => {
|
|
1546
|
+
await cancelPendingStartup();
|
|
1547
|
+
compactionGate.reset();
|
|
1337
1548
|
singlePlayerRuntime.resetShutdownState();
|
|
1338
1549
|
slackRequestRuntime.reset();
|
|
1339
1550
|
resetRemoteControlState();
|
|
@@ -1346,43 +1557,65 @@ export default function (pi) {
|
|
|
1346
1557
|
console.log("[slack-bridge] detected local subagent context; skipping Pinet registration");
|
|
1347
1558
|
currentRuntimeMode = "off";
|
|
1348
1559
|
setExtStatus(ctx, "off");
|
|
1560
|
+
await toolRegistrationRuntime.sync(pi, currentRuntimeMode);
|
|
1349
1561
|
return;
|
|
1350
1562
|
}
|
|
1351
1563
|
refreshSettings();
|
|
1352
1564
|
maybeWarnSlackUserAccess(ctx);
|
|
1353
1565
|
const startupMode = resolveSlackBridgeStartupRuntimeMode(settings, {
|
|
1354
|
-
brokerSocketExists: fs.existsSync(
|
|
1566
|
+
brokerSocketExists: fs.existsSync(resolveBrokerSocketPath()),
|
|
1355
1567
|
brokerManagedFollowerLaunch: isBrokerManagedFollowerLaunch(),
|
|
1356
1568
|
});
|
|
1357
|
-
|
|
1569
|
+
if (startupMode === "off") {
|
|
1358
1570
|
await transitionToRuntimeMode(ctx, startupMode);
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
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}`);
|
|
1362
1583
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
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();
|
|
1365
1594
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1595
|
+
finally {
|
|
1596
|
+
if (pendingStartup?.controller === controller)
|
|
1597
|
+
pendingStartup = null;
|
|
1368
1598
|
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
setExtStatus(ctx, "off");
|
|
1374
|
-
}
|
|
1599
|
+
})().catch((error) => {
|
|
1600
|
+
console.error(`[slack-bridge] background runtime start failed: ${msg(error)}`);
|
|
1601
|
+
});
|
|
1602
|
+
pendingStartup = { controller, promise: startupPromise };
|
|
1375
1603
|
});
|
|
1376
1604
|
// ─── Agent event wiring ──────────────────────────────
|
|
1377
1605
|
agentEventRuntime.register(pi);
|
|
1378
|
-
pi.on("
|
|
1379
|
-
|
|
1606
|
+
pi.on("session_before_compact", (event) => {
|
|
1607
|
+
compactionGate.begin(event.signal);
|
|
1608
|
+
});
|
|
1609
|
+
pi.on("session_compact", () => {
|
|
1610
|
+
compactionGate.end();
|
|
1380
1611
|
});
|
|
1381
1612
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
1613
|
+
compactionGate.reset();
|
|
1382
1614
|
resetRemoteControlState();
|
|
1383
1615
|
resetPendingRemoteControlAcks();
|
|
1384
1616
|
sessionUiRuntime.cleanupForSessionShutdown();
|
|
1385
|
-
await
|
|
1617
|
+
await cancelPendingStartup();
|
|
1618
|
+
await runPinetLifecycle(() => stopPinetRuntime(ctx, { releaseIdentity: true }));
|
|
1386
1619
|
pinetRegistrationGate.reset();
|
|
1387
1620
|
});
|
|
1388
1621
|
}
|