@pinet/slack-bridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +570 -0
  3. package/dist/activity-log.d.ts +62 -0
  4. package/dist/activity-log.js +293 -0
  5. package/dist/agent-completion-runtime.d.ts +17 -0
  6. package/dist/agent-completion-runtime.js +26 -0
  7. package/dist/agent-event-runtime.d.ts +13 -0
  8. package/dist/agent-event-runtime.js +27 -0
  9. package/dist/agent-prompt-guidance.d.ts +22 -0
  10. package/dist/agent-prompt-guidance.js +46 -0
  11. package/dist/broker/adapters/slack.d.ts +74 -0
  12. package/dist/broker/adapters/slack.js +563 -0
  13. package/dist/broker/adapters/types.d.ts +1 -0
  14. package/dist/broker/adapters/types.js +1 -0
  15. package/dist/broker/agent-messaging.d.ts +1 -0
  16. package/dist/broker/agent-messaging.js +1 -0
  17. package/dist/broker/auth.d.ts +1 -0
  18. package/dist/broker/auth.js +1 -0
  19. package/dist/broker/client.d.ts +167 -0
  20. package/dist/broker/client.js +624 -0
  21. package/dist/broker/control-plane-dashboard.d.ts +98 -0
  22. package/dist/broker/control-plane-dashboard.js +213 -0
  23. package/dist/broker/ghost-reaper.d.ts +49 -0
  24. package/dist/broker/ghost-reaper.js +209 -0
  25. package/dist/broker/index.d.ts +36 -0
  26. package/dist/broker/index.js +90 -0
  27. package/dist/broker/leader.d.ts +1 -0
  28. package/dist/broker/leader.js +1 -0
  29. package/dist/broker/maintenance.d.ts +1 -0
  30. package/dist/broker/maintenance.js +1 -0
  31. package/dist/broker/message-send.d.ts +1 -0
  32. package/dist/broker/message-send.js +1 -0
  33. package/dist/broker/paths.d.ts +1 -0
  34. package/dist/broker/paths.js +1 -0
  35. package/dist/broker/raw-tcp-loopback.d.ts +1 -0
  36. package/dist/broker/raw-tcp-loopback.js +1 -0
  37. package/dist/broker/router.d.ts +1 -0
  38. package/dist/broker/router.js +1 -0
  39. package/dist/broker/schema.d.ts +9 -0
  40. package/dist/broker/schema.js +63 -0
  41. package/dist/broker/socket-server.d.ts +120 -0
  42. package/dist/broker/socket-server.js +1087 -0
  43. package/dist/broker/types.d.ts +1 -0
  44. package/dist/broker/types.js +1 -0
  45. package/dist/broker-delivery.d.ts +10 -0
  46. package/dist/broker-delivery.js +26 -0
  47. package/dist/broker-inbound-persistence.d.ts +11 -0
  48. package/dist/broker-inbound-persistence.js +22 -0
  49. package/dist/broker-prompt-loader.d.ts +34 -0
  50. package/dist/broker-prompt-loader.js +185 -0
  51. package/dist/broker-runtime-access.d.ts +14 -0
  52. package/dist/broker-runtime-access.js +20 -0
  53. package/dist/broker-runtime.d.ts +100 -0
  54. package/dist/broker-runtime.js +533 -0
  55. package/dist/broker-thread-owner-hints.d.ts +10 -0
  56. package/dist/broker-thread-owner-hints.js +14 -0
  57. package/dist/canvases.d.ts +80 -0
  58. package/dist/canvases.js +221 -0
  59. package/dist/command-registration-runtime.d.ts +9 -0
  60. package/dist/command-registration-runtime.js +9 -0
  61. package/dist/core-tool-guardrails.d.ts +24 -0
  62. package/dist/core-tool-guardrails.js +66 -0
  63. package/dist/deploy-manifest.d.ts +27 -0
  64. package/dist/deploy-manifest.js +197 -0
  65. package/dist/follower-delivery.d.ts +16 -0
  66. package/dist/follower-delivery.js +70 -0
  67. package/dist/follower-runtime.d.ts +61 -0
  68. package/dist/follower-runtime.js +350 -0
  69. package/dist/git-metadata.d.ts +35 -0
  70. package/dist/git-metadata.js +88 -0
  71. package/dist/guardrails.d.ts +69 -0
  72. package/dist/guardrails.js +283 -0
  73. package/dist/helpers.d.ts +550 -0
  74. package/dist/helpers.js +2711 -0
  75. package/dist/home-tab.d.ts +27 -0
  76. package/dist/home-tab.js +242 -0
  77. package/dist/imessage-tools.d.ts +33 -0
  78. package/dist/imessage-tools.js +96 -0
  79. package/dist/inbox-drain-runtime.d.ts +30 -0
  80. package/dist/inbox-drain-runtime.js +71 -0
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +1330 -0
  83. package/dist/persisted-runtime-state.d.ts +52 -0
  84. package/dist/persisted-runtime-state.js +98 -0
  85. package/dist/pinet-activity-formatting.d.ts +20 -0
  86. package/dist/pinet-activity-formatting.js +43 -0
  87. package/dist/pinet-agent-status.d.ts +36 -0
  88. package/dist/pinet-agent-status.js +48 -0
  89. package/dist/pinet-commands.d.ts +70 -0
  90. package/dist/pinet-commands.js +402 -0
  91. package/dist/pinet-confirmation-replies.d.ts +7 -0
  92. package/dist/pinet-confirmation-replies.js +30 -0
  93. package/dist/pinet-control-plane-dashboard.d.ts +34 -0
  94. package/dist/pinet-control-plane-dashboard.js +86 -0
  95. package/dist/pinet-home-tabs.d.ts +36 -0
  96. package/dist/pinet-home-tabs.js +101 -0
  97. package/dist/pinet-maintenance-delivery.d.ts +22 -0
  98. package/dist/pinet-maintenance-delivery.js +45 -0
  99. package/dist/pinet-mesh-ops.d.ts +97 -0
  100. package/dist/pinet-mesh-ops.js +266 -0
  101. package/dist/pinet-registration-gate.d.ts +14 -0
  102. package/dist/pinet-registration-gate.js +42 -0
  103. package/dist/pinet-remote-control-acks.d.ts +16 -0
  104. package/dist/pinet-remote-control-acks.js +46 -0
  105. package/dist/pinet-remote-control.d.ts +17 -0
  106. package/dist/pinet-remote-control.js +74 -0
  107. package/dist/pinet-runtime-composition.d.ts +27 -0
  108. package/dist/pinet-runtime-composition.js +20 -0
  109. package/dist/pinet-tools.d.ts +67 -0
  110. package/dist/pinet-tools.js +1211 -0
  111. package/dist/prompts/broker/default.md +41 -0
  112. package/dist/prompts/broker/tmux.md +49 -0
  113. package/dist/ralph-loop.d.ts +76 -0
  114. package/dist/ralph-loop.js +524 -0
  115. package/dist/reaction-triggers.d.ts +25 -0
  116. package/dist/reaction-triggers.js +171 -0
  117. package/dist/repo-tool-guardrails.d.ts +20 -0
  118. package/dist/repo-tool-guardrails.js +81 -0
  119. package/dist/runtime-agent-context.d.ts +93 -0
  120. package/dist/runtime-agent-context.js +302 -0
  121. package/dist/runtime-mode.d.ts +10 -0
  122. package/dist/runtime-mode.js +39 -0
  123. package/dist/scheduled-wakeups.d.ts +1 -0
  124. package/dist/scheduled-wakeups.js +1 -0
  125. package/dist/session-ui-runtime.d.ts +20 -0
  126. package/dist/session-ui-runtime.js +163 -0
  127. package/dist/single-player-runtime.d.ts +71 -0
  128. package/dist/single-player-runtime.js +436 -0
  129. package/dist/skins/cosmere.json +1571 -0
  130. package/dist/skins/foundation.json +1304 -0
  131. package/dist/slack-access.d.ts +186 -0
  132. package/dist/slack-access.js +462 -0
  133. package/dist/slack-api.d.ts +2 -0
  134. package/dist/slack-api.js +1 -0
  135. package/dist/slack-block-kit.d.ts +36 -0
  136. package/dist/slack-block-kit.js +242 -0
  137. package/dist/slack-export.d.ts +31 -0
  138. package/dist/slack-export.js +206 -0
  139. package/dist/slack-message-context.d.ts +15 -0
  140. package/dist/slack-message-context.js +207 -0
  141. package/dist/slack-modals.d.ts +13 -0
  142. package/dist/slack-modals.js +79 -0
  143. package/dist/slack-pinet-runtime-adapter.d.ts +16 -0
  144. package/dist/slack-pinet-runtime-adapter.js +72 -0
  145. package/dist/slack-presence.d.ts +36 -0
  146. package/dist/slack-presence.js +89 -0
  147. package/dist/slack-request-runtime.d.ts +8 -0
  148. package/dist/slack-request-runtime.js +19 -0
  149. package/dist/slack-runtime-access.d.ts +28 -0
  150. package/dist/slack-runtime-access.js +107 -0
  151. package/dist/slack-scope-diagnostics.d.ts +31 -0
  152. package/dist/slack-scope-diagnostics.js +235 -0
  153. package/dist/slack-socket-dedup.d.ts +7 -0
  154. package/dist/slack-socket-dedup.js +135 -0
  155. package/dist/slack-thread-status.d.ts +41 -0
  156. package/dist/slack-thread-status.js +156 -0
  157. package/dist/slack-tool-policy-runtime.d.ts +36 -0
  158. package/dist/slack-tool-policy-runtime.js +96 -0
  159. package/dist/slack-tools.d.ts +52 -0
  160. package/dist/slack-tools.js +2688 -0
  161. package/dist/slack-turn-guardrails.d.ts +19 -0
  162. package/dist/slack-turn-guardrails.js +36 -0
  163. package/dist/slack-upload.d.ts +49 -0
  164. package/dist/slack-upload.js +224 -0
  165. package/dist/task-assignments.d.ts +45 -0
  166. package/dist/task-assignments.js +527 -0
  167. package/dist/thread-confirmations.d.ts +22 -0
  168. package/dist/thread-confirmations.js +139 -0
  169. package/dist/tool-registration-runtime.d.ts +13 -0
  170. package/dist/tool-registration-runtime.js +13 -0
  171. package/dist/ttl-cache.d.ts +47 -0
  172. package/dist/ttl-cache.js +105 -0
  173. package/manifest.yaml +57 -0
  174. package/package.json +60 -0
  175. package/skills/pinet-skin-creator/SKILL.md +109 -0
  176. package/skills/pinet-skin-creator/references/descriptor-format.md +99 -0
  177. package/skills/pinet-skin-creator/references/safety-checklist.md +56 -0
  178. package/skills/pinet-skin-creator/templates/pinet-skin-descriptor.json +77 -0
  179. package/skills/slack-bridge/SKILL.md +360 -0
@@ -0,0 +1,52 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { type SlackBridgeSettings } from "./helpers.js";
3
+ import type { SinglePlayerThreadInfo } from "./single-player-runtime.js";
4
+ export interface PersistedState {
5
+ threads?: [string, SinglePlayerThreadInfo][];
6
+ lastDmChannel?: string | null;
7
+ userNames?: [string, string][];
8
+ agentName?: string;
9
+ agentEmoji?: string;
10
+ agentStableId?: string;
11
+ brokerStableId?: string;
12
+ lastPinetRole?: "broker" | "worker";
13
+ activeSkinTheme?: string | null;
14
+ agentPersonality?: string | null;
15
+ agentAliases?: string[];
16
+ }
17
+ export interface PersistedRuntimeStateStringCache {
18
+ entries: () => Iterable<[string, string]>;
19
+ has: (key: string) => boolean;
20
+ set: (key: string, value: string) => void;
21
+ }
22
+ export interface PersistedRuntimeStateDeps {
23
+ pi: Pick<ExtensionAPI, "appendEntry">;
24
+ threads: Map<string, SinglePlayerThreadInfo>;
25
+ userNames: PersistedRuntimeStateStringCache;
26
+ getLastDmChannel: () => string | null;
27
+ setLastDmChannel: (channelId: string | null) => void;
28
+ getAgentName: () => string;
29
+ setAgentName: (name: string) => void;
30
+ getAgentEmoji: () => string;
31
+ setAgentEmoji: (emoji: string) => void;
32
+ getAgentStableId: () => string;
33
+ setAgentStableId: (stableId: string) => void;
34
+ getBrokerStableId: () => string;
35
+ setBrokerStableId: (stableId: string) => void;
36
+ getBrokerRole: () => "broker" | "follower" | null;
37
+ getActiveSkinTheme: () => string | null;
38
+ setActiveSkinTheme: (theme: string | null) => void;
39
+ getAgentPersonality: () => string | null;
40
+ setAgentPersonality: (personality: string | null) => void;
41
+ agentAliases: Set<string>;
42
+ setAgentOwnerToken: (ownerToken: string) => void;
43
+ getSettings: () => SlackBridgeSettings;
44
+ formatError: (error: unknown) => string;
45
+ }
46
+ export interface PersistedRuntimeStateManager {
47
+ persistStateNow: () => void;
48
+ persistState: () => void;
49
+ flushPersist: () => void;
50
+ restorePersistedRuntimeState: (ctx: ExtensionContext) => void;
51
+ }
52
+ export declare function createPersistedRuntimeState(deps: PersistedRuntimeStateDeps): PersistedRuntimeStateManager;
@@ -0,0 +1,98 @@
1
+ import * as os from "node:os";
2
+ import { buildPinetOwnerToken, resolveAgentStableId, resolveBrokerStableId, resolvePersistedAgentIdentity, } from "./helpers.js";
3
+ export function createPersistedRuntimeState(deps) {
4
+ let persistTimer = null;
5
+ function persistStateNow() {
6
+ persistTimer = null;
7
+ try {
8
+ deps.pi.appendEntry("slack-bridge-state", {
9
+ threads: Array.from(deps.threads.entries()),
10
+ lastDmChannel: deps.getLastDmChannel(),
11
+ userNames: Array.from(deps.userNames.entries()),
12
+ agentName: deps.getAgentName(),
13
+ agentEmoji: deps.getAgentEmoji(),
14
+ agentStableId: deps.getAgentStableId(),
15
+ brokerStableId: deps.getBrokerStableId(),
16
+ lastPinetRole: deps.getBrokerRole() === "broker" ? "broker" : "worker",
17
+ activeSkinTheme: deps.getActiveSkinTheme(),
18
+ agentPersonality: deps.getAgentPersonality(),
19
+ agentAliases: [...deps.agentAliases],
20
+ });
21
+ }
22
+ catch (error) {
23
+ console.error(`[slack-bridge] persistState failed: ${deps.formatError(error)}`);
24
+ }
25
+ }
26
+ function persistState() {
27
+ if (persistTimer) {
28
+ clearTimeout(persistTimer);
29
+ }
30
+ persistTimer = setTimeout(persistStateNow, 1_000);
31
+ }
32
+ function flushPersist() {
33
+ if (!persistTimer) {
34
+ return;
35
+ }
36
+ clearTimeout(persistTimer);
37
+ persistStateNow();
38
+ }
39
+ function restorePersistedRuntimeState(ctx) {
40
+ try {
41
+ let savedState = null;
42
+ for (const entry of ctx.sessionManager.getEntries()) {
43
+ if (entry.type === "custom" && entry.customType === "slack-bridge-state") {
44
+ savedState = entry.data;
45
+ }
46
+ }
47
+ const restoredRole = savedState?.lastPinetRole === "broker" ? "broker" : "worker";
48
+ const agentStableId = resolveAgentStableId(savedState?.agentStableId, ctx.sessionManager.getSessionFile(), os.hostname(), ctx.cwd, ctx.sessionManager.getLeafId());
49
+ const brokerStableId = resolveBrokerStableId(savedState?.brokerStableId, os.hostname(), ctx.cwd);
50
+ deps.setAgentStableId(agentStableId);
51
+ deps.setBrokerStableId(brokerStableId);
52
+ deps.setAgentOwnerToken(buildPinetOwnerToken(restoredRole === "broker" ? brokerStableId : agentStableId));
53
+ const identitySeed = restoredRole === "broker"
54
+ ? brokerStableId
55
+ : (ctx.sessionManager.getSessionFile() ?? agentStableId);
56
+ deps.setActiveSkinTheme(savedState?.activeSkinTheme ?? null);
57
+ deps.setAgentPersonality(savedState?.agentPersonality ?? null);
58
+ deps.agentAliases.clear();
59
+ for (const alias of savedState?.agentAliases ?? []) {
60
+ if (alias) {
61
+ deps.agentAliases.add(alias);
62
+ }
63
+ }
64
+ const restoredIdentity = resolvePersistedAgentIdentity(deps.getSettings(), savedState?.agentName, savedState?.agentEmoji, process.env.PI_NICKNAME, identitySeed, restoredRole);
65
+ deps.setAgentName(restoredIdentity.name);
66
+ deps.setAgentEmoji(restoredIdentity.emoji);
67
+ if (savedState) {
68
+ if (savedState.threads) {
69
+ for (const [threadTs, info] of savedState.threads) {
70
+ if (!deps.threads.has(threadTs)) {
71
+ deps.threads.set(threadTs, info);
72
+ }
73
+ }
74
+ }
75
+ if (savedState.lastDmChannel && !deps.getLastDmChannel()) {
76
+ deps.setLastDmChannel(savedState.lastDmChannel);
77
+ }
78
+ if (savedState.userNames) {
79
+ for (const [userId, userName] of savedState.userNames) {
80
+ if (!deps.userNames.has(userId)) {
81
+ deps.userNames.set(userId, userName);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ persistStateNow();
87
+ }
88
+ catch (error) {
89
+ console.error(`[slack-bridge] restore failed: ${deps.formatError(error)}`);
90
+ }
91
+ }
92
+ return {
93
+ persistStateNow,
94
+ persistState,
95
+ flushPersist,
96
+ restorePersistedRuntimeState,
97
+ };
98
+ }
@@ -0,0 +1,20 @@
1
+ import type { ActivityLogTone } from "./activity-log.js";
2
+ export type PinetTrackedAssignmentStatus = "assigned" | "branch_pushed" | "pr_open" | "pr_merged" | "pr_closed";
3
+ export interface PinetActivityFormattingAgentRecord {
4
+ emoji: string;
5
+ name: string;
6
+ }
7
+ export interface PinetActivityFormattingBrokerDbPort {
8
+ getAgentById: (agentId: string) => PinetActivityFormattingAgentRecord | null;
9
+ }
10
+ export interface PinetActivityFormattingDeps {
11
+ getActiveBrokerDb: () => PinetActivityFormattingBrokerDbPort | null;
12
+ }
13
+ export interface PinetActivityFormatting {
14
+ formatTrackedAgent: (agentId: string) => string;
15
+ summarizeTrackedAssignmentStatus: (status: PinetTrackedAssignmentStatus, prNumber: number | null, branch: string | null) => {
16
+ summary: string;
17
+ tone: ActivityLogTone;
18
+ };
19
+ }
20
+ export declare function createPinetActivityFormatting(deps: PinetActivityFormattingDeps): PinetActivityFormatting;
@@ -0,0 +1,43 @@
1
+ export function createPinetActivityFormatting(deps) {
2
+ function formatTrackedAgent(agentId) {
3
+ const agent = deps.getActiveBrokerDb()?.getAgentById(agentId);
4
+ if (!agent) {
5
+ return agentId;
6
+ }
7
+ return `${agent.emoji} ${agent.name}`.trim();
8
+ }
9
+ function summarizeTrackedAssignmentStatus(status, prNumber, branch) {
10
+ switch (status) {
11
+ case "pr_merged":
12
+ return {
13
+ summary: `PR #${prNumber ?? "?"} merged`,
14
+ tone: "success",
15
+ };
16
+ case "pr_open":
17
+ return {
18
+ summary: `PR #${prNumber ?? "?"} opened for review`,
19
+ tone: "success",
20
+ };
21
+ case "pr_closed":
22
+ return {
23
+ summary: `PR #${prNumber ?? "?"} closed without merge`,
24
+ tone: "warning",
25
+ };
26
+ case "branch_pushed":
27
+ return {
28
+ summary: `commits pushed on ${branch ?? "tracked branch"}`,
29
+ tone: "info",
30
+ };
31
+ case "assigned":
32
+ default:
33
+ return {
34
+ summary: "assigned",
35
+ tone: "info",
36
+ };
37
+ }
38
+ }
39
+ return {
40
+ formatTrackedAgent,
41
+ summarizeTrackedAssignmentStatus,
42
+ };
43
+ }
@@ -0,0 +1,36 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import type { SlackBridgeRuntimeMode } from "./runtime-mode.js";
3
+ export type PinetAgentStatusValue = "working" | "idle";
4
+ export interface PinetAgentStatusBrokerDbPort {
5
+ updateAgentStatus: (agentId: string, status: PinetAgentStatusValue) => void;
6
+ }
7
+ export interface PinetAgentStatusDeps {
8
+ getPinetEnabled: () => boolean;
9
+ getBrokerRole: () => "broker" | "follower" | null;
10
+ getDesiredAgentStatus: () => PinetAgentStatusValue;
11
+ setDesiredAgentStatus: (status: PinetAgentStatusValue) => void;
12
+ getActiveBrokerDb: () => PinetAgentStatusBrokerDbPort | null;
13
+ getActiveBrokerSelfId: () => string | null;
14
+ hasFollowerClient: () => boolean;
15
+ syncFollowerDesiredStatus: (status: PinetAgentStatusValue, options: {
16
+ force?: boolean;
17
+ }) => Promise<void>;
18
+ runBrokerMaintenance: (ctx: ExtensionContext) => void;
19
+ getInboxLength: () => number;
20
+ getCurrentRuntimeMode: () => SlackBridgeRuntimeMode;
21
+ maybeDrainInboxIfIdle: (ctx: ExtensionContext) => boolean;
22
+ getExtensionContext: () => ExtensionContext | undefined;
23
+ }
24
+ export interface PinetAgentStatus {
25
+ syncDesiredAgentStatus: (options?: {
26
+ force?: boolean;
27
+ }) => Promise<void>;
28
+ reportStatus: (status: PinetAgentStatusValue) => Promise<void>;
29
+ signalAgentFree: (ctx?: ExtensionContext, options?: {
30
+ requirePinet?: boolean;
31
+ }) => Promise<{
32
+ queuedInboxCount: number;
33
+ drainedQueuedInbox: boolean;
34
+ }>;
35
+ }
36
+ export declare function createPinetAgentStatus(deps: PinetAgentStatusDeps): PinetAgentStatus;
@@ -0,0 +1,48 @@
1
+ export function createPinetAgentStatus(deps) {
2
+ async function syncDesiredAgentStatus(options = {}) {
3
+ if (!deps.getPinetEnabled()) {
4
+ return;
5
+ }
6
+ const desiredAgentStatus = deps.getDesiredAgentStatus();
7
+ if (deps.getBrokerRole() === "broker") {
8
+ const db = deps.getActiveBrokerDb();
9
+ const selfId = deps.getActiveBrokerSelfId();
10
+ if (!db || !selfId) {
11
+ return;
12
+ }
13
+ db.updateAgentStatus(selfId, desiredAgentStatus);
14
+ return;
15
+ }
16
+ if (deps.getBrokerRole() === "follower" && deps.hasFollowerClient()) {
17
+ await deps.syncFollowerDesiredStatus(desiredAgentStatus, options);
18
+ }
19
+ }
20
+ async function reportStatus(status) {
21
+ deps.setDesiredAgentStatus(status);
22
+ await syncDesiredAgentStatus();
23
+ }
24
+ async function signalAgentFree(ctx, options = {}) {
25
+ const pinetEnabled = deps.getPinetEnabled();
26
+ if (!pinetEnabled && options.requirePinet) {
27
+ throw new Error("Pinet is not running. Use /pinet start or /pinet follow first.");
28
+ }
29
+ const maintenanceCtx = ctx ?? deps.getExtensionContext() ?? undefined;
30
+ if (pinetEnabled) {
31
+ await reportStatus("idle");
32
+ if (deps.getBrokerRole() === "broker" && maintenanceCtx) {
33
+ deps.runBrokerMaintenance(maintenanceCtx);
34
+ }
35
+ }
36
+ const queuedInboxCount = deps.getInboxLength();
37
+ const shouldDrainQueuedInbox = pinetEnabled || deps.getCurrentRuntimeMode() === "single";
38
+ const drainedQueuedInbox = shouldDrainQueuedInbox && queuedInboxCount > 0 && maintenanceCtx
39
+ ? deps.maybeDrainInboxIfIdle(maintenanceCtx)
40
+ : false;
41
+ return { queuedInboxCount, drainedQueuedInbox };
42
+ }
43
+ return {
44
+ syncDesiredAgentStatus,
45
+ reportStatus,
46
+ signalAgentFree,
47
+ };
48
+ }
@@ -0,0 +1,70 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { type FollowerRuntimeDiagnostic, type SlackBridgeSettings } from "./helpers.js";
3
+ import { type LoggedActivityLogEntry } from "./activity-log.js";
4
+ import { type SlackScopeDiagnostics } from "./slack-scope-diagnostics.js";
5
+ import type { SlackBridgeRuntimeMode } from "./runtime-mode.js";
6
+ import type { RalphSnoozeStatus } from "./ralph-loop.js";
7
+ export interface PinetCommandsDeps {
8
+ pinetEnabled: () => boolean;
9
+ pinetRegistrationBlocked: () => boolean;
10
+ runtimeMode: () => SlackBridgeRuntimeMode;
11
+ runtimeConnected: () => boolean;
12
+ brokerRole: () => "broker" | "follower" | null;
13
+ agentName: () => string;
14
+ agentEmoji: () => string;
15
+ agentOwnerToken: () => string;
16
+ agentPersonality: () => string | null;
17
+ agentAliases: () => Set<string>;
18
+ botUserId: () => string | null;
19
+ activeSkinTheme: () => string | null;
20
+ lastDmChannel: () => string | null;
21
+ followerRuntimeDiagnostic: () => FollowerRuntimeDiagnostic | null;
22
+ threads: () => Map<string, {
23
+ owner?: string;
24
+ }>;
25
+ allowedUsers: () => Set<string> | null;
26
+ inboxLength: () => number;
27
+ recentActivityLogEntries: (limit: number) => ReadonlyArray<LoggedActivityLogEntry>;
28
+ slackScopeDiagnostics: () => SlackScopeDiagnostics;
29
+ settings: () => SlackBridgeSettings;
30
+ lastBrokerMaintenance: () => {
31
+ pendingBacklogCount: number;
32
+ assignedBacklogCount: number;
33
+ reapedAgentIds: string[];
34
+ repairedThreadClaims: number;
35
+ anomalies: string[];
36
+ } | null;
37
+ ralphSnoozeStatus?: () => RalphSnoozeStatus | null;
38
+ snoozeRalphLoop?: (input: {
39
+ durationMs: number;
40
+ reason?: string | null;
41
+ }) => RalphSnoozeStatus;
42
+ clearRalphSnooze?: () => RalphSnoozeStatus;
43
+ getBrokerControlPlaneHomeTabViewerIds: () => string[];
44
+ lastBrokerControlPlaneHomeTabRefreshAt: () => string | null;
45
+ lastBrokerControlPlaneHomeTabError: () => string | null;
46
+ getPinetRegistrationBlockReason: () => string;
47
+ connectAsBroker: (ctx: ExtensionContext) => Promise<void>;
48
+ connectAsFollower: (ctx: ExtensionContext) => Promise<void>;
49
+ reloadPinetRuntime: (ctx: ExtensionContext) => Promise<void>;
50
+ disconnectFollower: (ctx: ExtensionContext) => Promise<{
51
+ unregisterError: string | null;
52
+ }>;
53
+ sendPinetAgentMessage: (target: string, body: string) => Promise<{
54
+ messageId: number;
55
+ target: string;
56
+ }>;
57
+ signalAgentFree: (ctx: ExtensionContext, options: {
58
+ requirePinet?: boolean;
59
+ }) => Promise<{
60
+ queuedInboxCount: number;
61
+ drainedQueuedInbox: boolean;
62
+ }>;
63
+ applyLocalAgentIdentity: (name: string, emoji: string, personality: string | null) => void;
64
+ setExtStatus: (ctx: ExtensionContext, state: "ok" | "reconnecting" | "error" | "off") => void;
65
+ setExtCtx: (ctx: ExtensionContext) => void;
66
+ }
67
+ export type PinetCommandAction = "start" | "follow" | "unfollow" | "reload" | "exit" | "free" | "status" | "logs" | "rename" | "snooze";
68
+ export declare function formatPinetCommandHelp(): string;
69
+ export declare function runPinetCommandAction(deps: PinetCommandsDeps, action: PinetCommandAction, args: string, ctx: ExtensionContext, usageCommand?: string): Promise<void>;
70
+ export declare function registerPinetCommands(pi: ExtensionAPI, deps: PinetCommandsDeps): void;