@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/canvases.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type SlackCanvasApiObject = Record<string, unknown>;
|
|
1
2
|
export interface SlackCanvasDocumentContent {
|
|
2
3
|
type: "markdown";
|
|
3
4
|
markdown: string;
|
|
@@ -59,6 +60,15 @@ export interface SlackCanvasSectionLookupRequest {
|
|
|
59
60
|
export interface SlackCanvasSectionLookupResult {
|
|
60
61
|
id?: string;
|
|
61
62
|
}
|
|
63
|
+
export interface SlackChannelCanvasInfoResponse extends SlackCanvasApiObject {
|
|
64
|
+
channel?: SlackCanvasApiObject;
|
|
65
|
+
}
|
|
66
|
+
export interface SlackCanvasCommentsResponse extends SlackCanvasApiObject {
|
|
67
|
+
file?: SlackCanvasApiObject;
|
|
68
|
+
comments?: SlackCanvasApiObject[];
|
|
69
|
+
paging?: SlackCanvasApiObject;
|
|
70
|
+
response_metadata?: SlackCanvasApiObject;
|
|
71
|
+
}
|
|
62
72
|
export declare function normalizeSlackCanvasCreateKind(kind?: string): SlackCanvasCreateKind;
|
|
63
73
|
export declare function normalizeSlackCanvasUpdateMode(mode?: string): SlackCanvasUpdateMode;
|
|
64
74
|
export declare function normalizeSlackCanvasSectionType(type?: string): SlackCanvasSectionType | undefined;
|
|
@@ -76,5 +86,5 @@ export declare function buildSlackCanvasSectionsLookupRequest(input: {
|
|
|
76
86
|
sectionType?: string;
|
|
77
87
|
}): SlackCanvasSectionLookupRequest;
|
|
78
88
|
export declare function pickSlackCanvasSectionId(sections: SlackCanvasSectionLookupResult[] | undefined, sectionIndex?: number): string;
|
|
79
|
-
export declare function extractSlackChannelCanvasId(response:
|
|
80
|
-
export declare function extractSlackCanvasCommentsPage(response:
|
|
89
|
+
export declare function extractSlackChannelCanvasId(response: SlackChannelCanvasInfoResponse): string | null;
|
|
90
|
+
export declare function extractSlackCanvasCommentsPage(response: SlackCanvasCommentsResponse, fallbackCanvasId?: string): SlackCanvasCommentsPage;
|
package/dist/canvases.js
CHANGED
|
@@ -187,9 +187,7 @@ function extractSlackCanvasCommentText(comment) {
|
|
|
187
187
|
}
|
|
188
188
|
export function extractSlackCanvasCommentsPage(response, fallbackCanvasId) {
|
|
189
189
|
const file = asRecord(response.file) ?? {};
|
|
190
|
-
const comments = Array.isArray(response.comments)
|
|
191
|
-
? response.comments
|
|
192
|
-
: [];
|
|
190
|
+
const comments = Array.isArray(response.comments) ? response.comments : [];
|
|
193
191
|
const paging = asRecord(response.paging);
|
|
194
192
|
const responseMetadata = asRecord(response.response_metadata);
|
|
195
193
|
const canvasId = asString(file.id) ?? normalizeOptionalString(fallbackCanvasId);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function createCompactionGate(onRelease) {
|
|
2
|
+
let generation = 0;
|
|
3
|
+
let active = false;
|
|
4
|
+
function end(expectedGeneration = generation) {
|
|
5
|
+
if (!active || expectedGeneration !== generation)
|
|
6
|
+
return;
|
|
7
|
+
// session_compact fires before Pi reconnects persistence.
|
|
8
|
+
setTimeout(() => {
|
|
9
|
+
if (expectedGeneration !== generation)
|
|
10
|
+
return;
|
|
11
|
+
active = false;
|
|
12
|
+
generation += 1;
|
|
13
|
+
onRelease();
|
|
14
|
+
}, 0);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
isActive: () => active,
|
|
18
|
+
begin(signal) {
|
|
19
|
+
const currentGeneration = ++generation;
|
|
20
|
+
active = true;
|
|
21
|
+
signal?.addEventListener("abort", () => end(currentGeneration), { once: true });
|
|
22
|
+
},
|
|
23
|
+
end,
|
|
24
|
+
reset() {
|
|
25
|
+
active = false;
|
|
26
|
+
generation += 1;
|
|
27
|
+
},
|
|
28
|
+
tryDeliver(deliver) {
|
|
29
|
+
if (active)
|
|
30
|
+
return false;
|
|
31
|
+
deliver();
|
|
32
|
+
return true;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -23,10 +23,16 @@ export interface DeployResult {
|
|
|
23
23
|
appId: string;
|
|
24
24
|
scopeChanges: ManifestScopeChanges;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
type SlackManifestPrimitive = string | number | boolean | null;
|
|
27
|
+
export type SlackManifestValue = SlackManifestPrimitive | SlackManifestObject | SlackManifestValue[];
|
|
28
|
+
export interface SlackManifestObject {
|
|
29
|
+
[key: string]: SlackManifestValue;
|
|
30
|
+
}
|
|
31
|
+
export declare function diffManifestScopes(beforeManifest: SlackManifestObject | null | undefined, afterManifest: SlackManifestObject | null | undefined): ManifestScopeChanges;
|
|
27
32
|
export declare function formatScopeChangeSummary(changes: ManifestScopeChanges): string[];
|
|
28
33
|
export declare function resolveDeployConfig(settings: SlackBridgeSettings, env: NodeJS.ProcessEnv, cwd?: string): ResolvedDeployConfig;
|
|
29
34
|
export declare function getDeployConfigError(config: ResolvedDeployConfig): string | null;
|
|
30
|
-
export declare function applyConfiguredSlashCommands(manifest:
|
|
35
|
+
export declare function applyConfiguredSlashCommands(manifest: SlackManifestObject, settings: SlackBridgeSettings): SlackManifestObject;
|
|
31
36
|
export declare function deploySlackManifest(config: ResolvedDeployConfig): Promise<DeployResult>;
|
|
32
37
|
export declare function run(): Promise<void>;
|
|
38
|
+
export {};
|
package/dist/deploy-manifest.js
CHANGED
|
@@ -56,12 +56,14 @@ function buildSlackRequest(method, token, body) {
|
|
|
56
56
|
},
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
function
|
|
60
|
-
return typeof value === "object" && value
|
|
59
|
+
function asManifestObject(value) {
|
|
60
|
+
return value != null && typeof value === "object" && !Array.isArray(value)
|
|
61
|
+
? value
|
|
62
|
+
: null;
|
|
61
63
|
}
|
|
62
64
|
function readScopeList(manifest, scopeType) {
|
|
63
|
-
const oauthConfig =
|
|
64
|
-
const scopes =
|
|
65
|
+
const oauthConfig = asManifestObject(manifest?.oauth_config);
|
|
66
|
+
const scopes = asManifestObject(oauthConfig?.scopes);
|
|
65
67
|
const raw = scopes?.[scopeType];
|
|
66
68
|
if (!Array.isArray(raw)) {
|
|
67
69
|
return [];
|
|
@@ -127,9 +129,9 @@ export function getDeployConfigError(config) {
|
|
|
127
129
|
}
|
|
128
130
|
export function applyConfiguredSlashCommands(manifest, settings) {
|
|
129
131
|
const commandNames = resolveSlackAgentCommandNames(settings);
|
|
130
|
-
const features =
|
|
131
|
-
const oauthConfig =
|
|
132
|
-
const scopes =
|
|
132
|
+
const features = asManifestObject(manifest.features) ?? {};
|
|
133
|
+
const oauthConfig = asManifestObject(manifest.oauth_config) ?? {};
|
|
134
|
+
const scopes = asManifestObject(oauthConfig.scopes) ?? {};
|
|
133
135
|
const botScopes = readScopeList(manifest, "bot");
|
|
134
136
|
const nextBotScopes = botScopes.includes("commands") ? botScopes : [...botScopes, "commands"];
|
|
135
137
|
return {
|
|
@@ -2,6 +2,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { type FollowerRuntimeDiagnostic, type FollowerThreadState, type InboxMessage, type PinetControlCommand, type PinetRemoteControlRequestResult, type SlackBridgeSettings } from "./helpers.js";
|
|
3
3
|
import { type FollowerDeliveryState } from "./follower-delivery.js";
|
|
4
4
|
import { BrokerClient } from "./broker/client.js";
|
|
5
|
+
export declare function resolveBrokerSocketPath(): string;
|
|
5
6
|
export type BrokerClientRef = {
|
|
6
7
|
client: BrokerClient;
|
|
7
8
|
pollInterval: ReturnType<typeof setInterval> | null;
|
|
@@ -24,12 +25,13 @@ export interface FollowerRuntimeDeps {
|
|
|
24
25
|
getLastDmChannel: () => string | null;
|
|
25
26
|
setLastDmChannel: (channelId: string | null) => void;
|
|
26
27
|
pushInboxMessages: (messages: InboxMessage[]) => void;
|
|
27
|
-
getAgentMetadata: (role: "broker" | "worker") => Promise<Record<string, unknown>>;
|
|
28
|
+
getAgentMetadata: (role: "broker" | "worker", signal?: AbortSignal) => Promise<Record<string, unknown>>;
|
|
28
29
|
applyRegistrationIdentity: (registration: {
|
|
29
30
|
name: string;
|
|
30
31
|
emoji: string;
|
|
31
32
|
metadata?: Record<string, unknown> | null;
|
|
32
33
|
}) => void;
|
|
34
|
+
onRegistrationIdentityApplied: () => Promise<void>;
|
|
33
35
|
persistState: () => void;
|
|
34
36
|
updateBadge: () => void;
|
|
35
37
|
maybeDrainInboxIfIdle: (ctx: ExtensionContext) => boolean;
|
|
@@ -37,6 +39,7 @@ export interface FollowerRuntimeDeps {
|
|
|
37
39
|
deferControlAck: (command: PinetControlCommand, inboxId: number) => void;
|
|
38
40
|
runRemoteControl: (command: PinetControlCommand, ctx: ExtensionContext) => void;
|
|
39
41
|
deliverFollowUpMessage: (text: string) => boolean;
|
|
42
|
+
deliverSteeringMessage: (text: string, ctx: ExtensionContext) => boolean;
|
|
40
43
|
setExtStatus: (ctx: ExtensionContext, state: "ok" | "reconnecting" | "error" | "off") => void;
|
|
41
44
|
getRuntimeDiagnostic: () => FollowerRuntimeDiagnostic | null;
|
|
42
45
|
setRuntimeDiagnostic: (diagnostic: FollowerRuntimeDiagnostic | null) => void;
|
|
@@ -45,7 +48,7 @@ export interface FollowerRuntimeDeps {
|
|
|
45
48
|
deliveryState: FollowerDeliveryState;
|
|
46
49
|
}
|
|
47
50
|
export interface FollowerRuntime {
|
|
48
|
-
connect: (ctx: ExtensionContext) => Promise<BrokerClientRef>;
|
|
51
|
+
connect: (ctx: ExtensionContext, signal?: AbortSignal) => Promise<BrokerClientRef>;
|
|
49
52
|
disconnect: (ctx: ExtensionContext, options?: {
|
|
50
53
|
releaseIdentity?: boolean;
|
|
51
54
|
}) => Promise<{
|
package/dist/follower-runtime.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildFollowerRuntimeDiagnostic, buildPinetOwnerToken, extractPinetControlCommand, formatPinetInboxMessages, getFollowerOwnedThreadReclaims, getFollowerReconnectUiUpdate, partitionFollowerInboxEntries, resolvePinetMeshAuth, resolveRuntimeAgentIdentity, syncFollowerInboxEntries, syncTransferredSlackThreadContexts, } from "./helpers.js";
|
|
1
|
+
import { buildFollowerRuntimeDiagnostic, buildPinetOwnerToken, extractPinetSteeringInboxEntry, extractPinetControlCommand, formatPinetInboxMessages, formatPinetSteeringMessage, getFollowerOwnedThreadReclaims, getFollowerReconnectUiUpdate, partitionFollowerInboxEntries, resolvePinetMeshAuth, resolveRuntimeAgentIdentity, syncFollowerInboxEntries, syncTransferredSlackThreadContexts, } from "./helpers.js";
|
|
2
2
|
import { drainFollowerAckBatches, hasDeliveredFollowerInboxIds, isFollowerInboxIdTracked, markFollowerInboxIdsDelivered, queueFollowerInboxIds, resetFollowerDeliveryState, } from "./follower-delivery.js";
|
|
3
3
|
import { BrokerClient, DEFAULT_SOCKET_PATH } from "./broker/client.js";
|
|
4
|
-
function resolveBrokerSocketPath() {
|
|
4
|
+
export function resolveBrokerSocketPath() {
|
|
5
5
|
const envPath = process.env.PINET_SOCKET_PATH?.trim();
|
|
6
6
|
return envPath && envPath.length > 0 ? envPath : DEFAULT_SOCKET_PATH;
|
|
7
7
|
}
|
|
@@ -91,7 +91,8 @@ export function createFollowerRuntime(deps) {
|
|
|
91
91
|
followerStatusSyncTarget = null;
|
|
92
92
|
resetFollowerDeliveryState(deps.deliveryState);
|
|
93
93
|
}
|
|
94
|
-
async function connect(ctx) {
|
|
94
|
+
async function connect(ctx, signal) {
|
|
95
|
+
signal?.throwIfAborted();
|
|
95
96
|
deps.refreshSettings();
|
|
96
97
|
const meshAuth = resolvePinetMeshAuth(deps.getSettings());
|
|
97
98
|
const client = new BrokerClient({
|
|
@@ -99,6 +100,10 @@ export function createFollowerRuntime(deps) {
|
|
|
99
100
|
...(meshAuth.meshSecret ? { meshSecret: meshAuth.meshSecret } : {}),
|
|
100
101
|
...(meshAuth.meshSecretPath ? { meshSecretPath: meshAuth.meshSecretPath } : {}),
|
|
101
102
|
});
|
|
103
|
+
const abortConnect = () => {
|
|
104
|
+
client.disconnect();
|
|
105
|
+
};
|
|
106
|
+
signal?.addEventListener("abort", abortConnect, { once: true });
|
|
102
107
|
async function registerFollowerRuntime() {
|
|
103
108
|
deps.refreshSettings();
|
|
104
109
|
const settings = deps.getSettings();
|
|
@@ -107,8 +112,9 @@ export function createFollowerRuntime(deps) {
|
|
|
107
112
|
const hasExplicitIdentityRequest = Boolean(settings.agentName?.trim() && settings.agentEmoji?.trim()) ||
|
|
108
113
|
Boolean(process.env.PI_NICKNAME?.trim());
|
|
109
114
|
deps.setAgentOwnerToken(buildPinetOwnerToken(deps.getAgentStableId()));
|
|
110
|
-
const registration = await client.register(hasExplicitIdentityRequest ? workerIdentity.name : "", hasExplicitIdentityRequest ? workerIdentity.emoji : "", await deps.getAgentMetadata("worker"), deps.getAgentStableId());
|
|
115
|
+
const registration = await client.register(hasExplicitIdentityRequest ? workerIdentity.name : "", hasExplicitIdentityRequest ? workerIdentity.emoji : "", await deps.getAgentMetadata("worker", signal), deps.getAgentStableId());
|
|
111
116
|
deps.applyRegistrationIdentity(registration);
|
|
117
|
+
await deps.onRegistrationIdentityApplied();
|
|
112
118
|
client.setHeartbeatMetadataProvider(() => deps.getAgentMetadata("worker"));
|
|
113
119
|
}
|
|
114
120
|
async function resumeThreadClaims() {
|
|
@@ -179,7 +185,29 @@ export function createFollowerRuntime(deps) {
|
|
|
179
185
|
}
|
|
180
186
|
return;
|
|
181
187
|
}
|
|
182
|
-
const
|
|
188
|
+
const steeringEntries = [];
|
|
189
|
+
const queuedEntries = [];
|
|
190
|
+
for (const entry of remainingEntries) {
|
|
191
|
+
const steering = extractPinetSteeringInboxEntry(entry);
|
|
192
|
+
if (steering) {
|
|
193
|
+
steeringEntries.push(steering);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
queuedEntries.push(entry);
|
|
197
|
+
}
|
|
198
|
+
if (steeringEntries.length > 0) {
|
|
199
|
+
const deliveredSteeringIds = [];
|
|
200
|
+
for (const entry of steeringEntries) {
|
|
201
|
+
if (deps.deliverSteeringMessage(formatPinetSteeringMessage(entry), ctx)) {
|
|
202
|
+
deliveredSteeringIds.push(entry.inboxId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (deliveredSteeringIds.length > 0) {
|
|
206
|
+
markFollowerInboxIdsDelivered(deps.deliveryState, deliveredSteeringIds);
|
|
207
|
+
void flushDeliveredAcks();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const { nudges, agentMessages, regular } = partitionFollowerInboxEntries(queuedEntries);
|
|
183
211
|
if (nudges.length > 0) {
|
|
184
212
|
const nudgeText = nudges
|
|
185
213
|
.map((nudge) => nudge.message.body ?? "")
|
|
@@ -233,7 +261,9 @@ export function createFollowerRuntime(deps) {
|
|
|
233
261
|
}
|
|
234
262
|
try {
|
|
235
263
|
await client.connect();
|
|
264
|
+
signal?.throwIfAborted();
|
|
236
265
|
await registerFollowerRuntime();
|
|
266
|
+
signal?.throwIfAborted();
|
|
237
267
|
deps.setRuntimeDiagnostic(null);
|
|
238
268
|
syncedFollowerStatus = "idle";
|
|
239
269
|
clientRef = {
|
|
@@ -304,6 +334,7 @@ export function createFollowerRuntime(deps) {
|
|
|
304
334
|
void deps.handleTerminalReconnectFailure(ctx, reconnectError);
|
|
305
335
|
});
|
|
306
336
|
await resumeThreadClaims();
|
|
337
|
+
signal?.throwIfAborted();
|
|
307
338
|
startPolling();
|
|
308
339
|
return clientRef;
|
|
309
340
|
}
|
|
@@ -315,6 +346,9 @@ export function createFollowerRuntime(deps) {
|
|
|
315
346
|
resetFollowerRuntimeState();
|
|
316
347
|
throw error;
|
|
317
348
|
}
|
|
349
|
+
finally {
|
|
350
|
+
signal?.removeEventListener("abort", abortConnect);
|
|
351
|
+
}
|
|
318
352
|
}
|
|
319
353
|
async function disconnect(_ctx, options = {}) {
|
|
320
354
|
const current = clientRef;
|
package/dist/git-metadata.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ type ExecFileResult = {
|
|
|
4
4
|
export type ExecFileAsyncLike = (file: string, args: string[], options: {
|
|
5
5
|
cwd: string;
|
|
6
6
|
encoding: "utf-8";
|
|
7
|
+
timeout: number;
|
|
8
|
+
signal?: AbortSignal;
|
|
7
9
|
}) => Promise<ExecFileResult>;
|
|
8
10
|
export interface GitContext {
|
|
9
11
|
cwd: string;
|
|
@@ -23,13 +25,7 @@ export interface GitDynamicState {
|
|
|
23
25
|
/** True when any git probe failed; callers should treat omitted values as unknown. */
|
|
24
26
|
probeFailed: boolean;
|
|
25
27
|
}
|
|
26
|
-
export declare function probeGitBranch(cwd?: string, runner?: ExecFileAsyncLike): Promise<string | undefined>;
|
|
27
|
-
export declare function probeGitDynamic(cwd?: string, runner?: ExecFileAsyncLike): Promise<GitDynamicState>;
|
|
28
|
-
export declare function probeGitContext(cwd?: string, runner?: ExecFileAsyncLike): Promise<GitContext>;
|
|
29
|
-
export interface GitContextCache {
|
|
30
|
-
get(): Promise<GitContext>;
|
|
31
|
-
peek(): GitContext | null;
|
|
32
|
-
clear(): void;
|
|
33
|
-
}
|
|
34
|
-
export declare function createGitContextCache(loader: () => Promise<GitContext>): GitContextCache;
|
|
28
|
+
export declare function probeGitBranch(cwd?: string, runner?: ExecFileAsyncLike, signal?: AbortSignal): Promise<string | undefined>;
|
|
29
|
+
export declare function probeGitDynamic(cwd?: string, runner?: ExecFileAsyncLike, signal?: AbortSignal): Promise<GitDynamicState>;
|
|
30
|
+
export declare function probeGitContext(cwd?: string, runner?: ExecFileAsyncLike, signal?: AbortSignal): Promise<GitContext>;
|
|
35
31
|
export {};
|
package/dist/git-metadata.js
CHANGED
|
@@ -2,26 +2,34 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
const execFileAsync = promisify(execFile);
|
|
5
|
-
|
|
5
|
+
const GIT_PROBE_TIMEOUT_MS = 2_000;
|
|
6
|
+
async function runGitCommand(args, cwd, runner, signal) {
|
|
7
|
+
signal?.throwIfAborted();
|
|
6
8
|
try {
|
|
7
|
-
const result = await runner("git", args, {
|
|
9
|
+
const result = await runner("git", args, {
|
|
10
|
+
cwd,
|
|
11
|
+
encoding: "utf-8",
|
|
12
|
+
timeout: GIT_PROBE_TIMEOUT_MS,
|
|
13
|
+
signal,
|
|
14
|
+
});
|
|
8
15
|
const stdout = typeof result.stdout === "string" ? result.stdout : result.stdout?.toString();
|
|
9
16
|
return { stdout, ok: true };
|
|
10
17
|
}
|
|
11
18
|
catch {
|
|
19
|
+
signal?.throwIfAborted();
|
|
12
20
|
return { stdout: undefined, ok: false };
|
|
13
21
|
}
|
|
14
22
|
}
|
|
15
|
-
async function readGitTrimmed(args, cwd, runner) {
|
|
16
|
-
const { stdout, ok } = await runGitCommand(args, cwd, runner);
|
|
23
|
+
async function readGitTrimmed(args, cwd, runner, signal) {
|
|
24
|
+
const { stdout, ok } = await runGitCommand(args, cwd, runner, signal);
|
|
17
25
|
const trimmed = stdout?.trim();
|
|
18
26
|
return { value: trimmed ? trimmed : undefined, ok };
|
|
19
27
|
}
|
|
20
|
-
export async function probeGitBranch(cwd = process.cwd(), runner = execFileAsync) {
|
|
21
|
-
return (await readGitTrimmed(["branch", "--show-current"], cwd, runner)).value;
|
|
28
|
+
export async function probeGitBranch(cwd = process.cwd(), runner = execFileAsync, signal) {
|
|
29
|
+
return (await readGitTrimmed(["branch", "--show-current"], cwd, runner, signal)).value;
|
|
22
30
|
}
|
|
23
|
-
async function probeGitDirty(cwd, runner) {
|
|
24
|
-
const { stdout, ok } = await runGitCommand(["status", "--porcelain", "--untracked-files=normal"], cwd, runner);
|
|
31
|
+
async function probeGitDirty(cwd, runner, signal) {
|
|
32
|
+
const { stdout, ok } = await runGitCommand(["status", "--porcelain", "--untracked-files=normal"], cwd, runner, signal);
|
|
25
33
|
if (!ok) {
|
|
26
34
|
return { ok: false };
|
|
27
35
|
}
|
|
@@ -31,9 +39,9 @@ async function probeGitDirty(cwd, runner) {
|
|
|
31
39
|
.filter((line) => line.length > 0).length;
|
|
32
40
|
return { dirty: dirtyFileCount > 0, dirtyFileCount, ok: true };
|
|
33
41
|
}
|
|
34
|
-
export async function probeGitDynamic(cwd = process.cwd(), runner = execFileAsync) {
|
|
35
|
-
const branchProbe = await readGitTrimmed(["branch", "--show-current"], cwd, runner);
|
|
36
|
-
const dirtyProbe = await probeGitDirty(cwd, runner);
|
|
42
|
+
export async function probeGitDynamic(cwd = process.cwd(), runner = execFileAsync, signal) {
|
|
43
|
+
const branchProbe = await readGitTrimmed(["branch", "--show-current"], cwd, runner, signal);
|
|
44
|
+
const dirtyProbe = await probeGitDirty(cwd, runner, signal);
|
|
37
45
|
return {
|
|
38
46
|
...(branchProbe.value ? { branch: branchProbe.value } : {}),
|
|
39
47
|
...(typeof dirtyProbe.dirty === "boolean" ? { dirty: dirtyProbe.dirty } : {}),
|
|
@@ -43,9 +51,10 @@ export async function probeGitDynamic(cwd = process.cwd(), runner = execFileAsyn
|
|
|
43
51
|
probeFailed: !branchProbe.ok || !dirtyProbe.ok,
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
|
-
export async function probeGitContext(cwd = process.cwd(), runner = execFileAsync) {
|
|
47
|
-
const repoRoot = (await readGitTrimmed(["rev-parse", "--show-toplevel"], cwd, runner))
|
|
48
|
-
|
|
54
|
+
export async function probeGitContext(cwd = process.cwd(), runner = execFileAsync, signal) {
|
|
55
|
+
const repoRoot = (await readGitTrimmed(["rev-parse", "--show-toplevel"], cwd, runner, signal))
|
|
56
|
+
.value;
|
|
57
|
+
const dynamic = await probeGitDynamic(cwd, runner, signal);
|
|
49
58
|
const resolvedRepoRoot = repoRoot ?? cwd;
|
|
50
59
|
return {
|
|
51
60
|
cwd,
|
|
@@ -58,31 +67,3 @@ export async function probeGitContext(cwd = process.cwd(), runner = execFileAsyn
|
|
|
58
67
|
: {}),
|
|
59
68
|
};
|
|
60
69
|
}
|
|
61
|
-
export function createGitContextCache(loader) {
|
|
62
|
-
let cached = null;
|
|
63
|
-
let inflight = null;
|
|
64
|
-
return {
|
|
65
|
-
async get() {
|
|
66
|
-
if (cached)
|
|
67
|
-
return cached;
|
|
68
|
-
if (inflight)
|
|
69
|
-
return inflight;
|
|
70
|
-
inflight = loader()
|
|
71
|
-
.then((result) => {
|
|
72
|
-
cached = result;
|
|
73
|
-
return result;
|
|
74
|
-
})
|
|
75
|
-
.finally(() => {
|
|
76
|
-
inflight = null;
|
|
77
|
-
});
|
|
78
|
-
return inflight;
|
|
79
|
-
},
|
|
80
|
-
peek() {
|
|
81
|
-
return cached;
|
|
82
|
-
},
|
|
83
|
-
clear() {
|
|
84
|
-
cached = null;
|
|
85
|
-
inflight = null;
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
package/dist/guardrails.js
CHANGED
|
@@ -14,6 +14,7 @@ export const READ_ONLY_TOOLS = new Set([
|
|
|
14
14
|
"slack:canvas_comments_read",
|
|
15
15
|
"slack:confirm_action",
|
|
16
16
|
"pinet:agents",
|
|
17
|
+
"pinet:lanes",
|
|
17
18
|
"pinet:read",
|
|
18
19
|
"memory_read",
|
|
19
20
|
"memory_search",
|
|
@@ -47,10 +48,14 @@ export const WRITE_TOOLS = new Set([
|
|
|
47
48
|
"pinet:schedule",
|
|
48
49
|
"pinet:send",
|
|
49
50
|
"pinet:snooze",
|
|
51
|
+
"pinet:spawn",
|
|
52
|
+
"pinet:lanes:write",
|
|
50
53
|
"pinet:free",
|
|
51
54
|
"pinet:ports",
|
|
52
55
|
"pinet:reload",
|
|
53
56
|
"pinet:exit",
|
|
57
|
+
"pinet:hibernate",
|
|
58
|
+
"pinet:wake",
|
|
54
59
|
]);
|
|
55
60
|
/**
|
|
56
61
|
* Match a tool name against glob patterns (supports `*` wildcard).
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type RuntimeScopeCarrier } from "@pinet/transport-core";
|
|
2
|
+
import { createAbortError, isAbortError } from "@pinet/transport-core/async";
|
|
2
3
|
import type { ReactionCommandSettings } from "./reaction-triggers.js";
|
|
3
4
|
import type { AgentSessionSummary } from "./broker/types.js";
|
|
4
5
|
export interface SlackIngressGuardSettings {
|
|
@@ -29,6 +30,8 @@ export interface SlackBridgeSettings {
|
|
|
29
30
|
}[];
|
|
30
31
|
reactionCommands?: ReactionCommandSettings;
|
|
31
32
|
runtimeMode?: "off" | "single" | "broker" | "follower";
|
|
33
|
+
/** Runtime backend for newly spawned subtree workers. Defaults to tmux. */
|
|
34
|
+
subtreeWorkerRuntime?: "tmux" | "herdr";
|
|
32
35
|
brokerPrompt?: string;
|
|
33
36
|
autoConnect?: boolean;
|
|
34
37
|
autoFollow?: boolean;
|
|
@@ -42,6 +45,18 @@ export interface SlackBridgeSettings {
|
|
|
42
45
|
agentEmoji?: string;
|
|
43
46
|
meshSecret?: string;
|
|
44
47
|
meshSecretPath?: string;
|
|
48
|
+
hibernation?: {
|
|
49
|
+
/** Master kill switch. Defaults false; waking/draining existing rows remains permitted. */
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
mode?: "observe" | "manual" | "auto";
|
|
52
|
+
allowedRepos?: string[];
|
|
53
|
+
graceMs?: number;
|
|
54
|
+
idleDebounceMs?: number;
|
|
55
|
+
handshakeTimeoutMs?: number;
|
|
56
|
+
wakeLeaseMs?: number;
|
|
57
|
+
maxConcurrentWakes?: number;
|
|
58
|
+
maxConcurrentWakesPerRepo?: number;
|
|
59
|
+
};
|
|
45
60
|
imessage?: {
|
|
46
61
|
enabled?: boolean;
|
|
47
62
|
};
|
|
@@ -71,6 +86,7 @@ export declare function describeSlackUserAccess(allowlist: Set<string> | null, o
|
|
|
71
86
|
}): string;
|
|
72
87
|
export declare function getSlackUserAccessWarning(allowlist: Set<string> | null): string | null;
|
|
73
88
|
export declare function isUserAllowed(allowlist: Set<string> | null, userId: string): boolean;
|
|
89
|
+
export type InboxMessageMetadata = Record<string, unknown>;
|
|
74
90
|
export interface InboxMessage {
|
|
75
91
|
channel: string;
|
|
76
92
|
threadTs: string;
|
|
@@ -79,7 +95,8 @@ export interface InboxMessage {
|
|
|
79
95
|
timestamp: string;
|
|
80
96
|
isChannelMention?: boolean;
|
|
81
97
|
brokerInboxId?: number;
|
|
82
|
-
|
|
98
|
+
brokerInboxOrigin?: "subtree";
|
|
99
|
+
metadata?: InboxMessageMetadata | null;
|
|
83
100
|
scope?: RuntimeScopeCarrier | null;
|
|
84
101
|
}
|
|
85
102
|
export interface SqliteJournalModeResult {
|
|
@@ -120,36 +137,62 @@ export interface PinetRuntimeReloader<State> {
|
|
|
120
137
|
startRuntime: (role: "broker" | "follower") => Promise<void>;
|
|
121
138
|
}
|
|
122
139
|
export declare function reloadPinetRuntimeSafely<State>(reloader: PinetRuntimeReloader<State>): Promise<void>;
|
|
123
|
-
export
|
|
140
|
+
export declare function reloadPinetRuntimeInPlaceSafely<State>(input: {
|
|
141
|
+
snapshotState: () => State;
|
|
142
|
+
restoreState: (snapshot: State) => void;
|
|
143
|
+
refreshState: () => void;
|
|
144
|
+
validateRefreshedState: () => void | Promise<void>;
|
|
145
|
+
reloadRuntime: () => Promise<void>;
|
|
146
|
+
}): Promise<void>;
|
|
147
|
+
export type PinetControlMetadata = Record<string, unknown>;
|
|
148
|
+
export interface PinetControlEnvelope extends PinetControlMetadata {
|
|
124
149
|
type: "pinet:control";
|
|
125
150
|
action: PinetControlCommand;
|
|
126
151
|
}
|
|
127
152
|
export declare function getPinetControlCommandFromText(text: string | undefined): PinetControlCommand | null;
|
|
128
153
|
export declare function buildPinetControlMetadata(command: PinetControlCommand): PinetControlEnvelope;
|
|
129
154
|
export declare function buildPinetControlMessage(command: PinetControlCommand): string;
|
|
130
|
-
export declare function normalizeOutgoingPinetControlMessage(body: string, metadata?:
|
|
155
|
+
export declare function normalizeOutgoingPinetControlMessage(body: string, metadata?: PinetControlMetadata): {
|
|
156
|
+
body: string;
|
|
157
|
+
metadata: PinetControlMetadata;
|
|
158
|
+
} | null;
|
|
159
|
+
export interface PinetSteeringEnvelope extends PinetControlMetadata {
|
|
160
|
+
type: "pinet:steer";
|
|
161
|
+
message: string;
|
|
162
|
+
}
|
|
163
|
+
export declare function getPinetSteeringMessageFromText(text: string | undefined): string | null;
|
|
164
|
+
export declare function buildPinetSteeringMetadata(message: string): PinetSteeringEnvelope;
|
|
165
|
+
export declare function buildPinetSteeringMessage(message: string): string;
|
|
166
|
+
export declare function normalizeOutgoingPinetSteeringMessage(body: string, metadata?: PinetControlMetadata): {
|
|
131
167
|
body: string;
|
|
132
|
-
metadata:
|
|
168
|
+
metadata: PinetControlMetadata;
|
|
133
169
|
} | null;
|
|
134
170
|
export type PinetSkinStatusKey = "idle" | "working" | "healthy" | "stale" | "ghost" | "resumable";
|
|
135
171
|
export type PinetSkinStatusVocabulary = Partial<Record<PinetSkinStatusKey, string>>;
|
|
136
|
-
export
|
|
172
|
+
export interface PinetControlCommandMessage {
|
|
173
|
+
threadId?: string;
|
|
174
|
+
body?: string;
|
|
175
|
+
metadata?: PinetControlMetadata | null;
|
|
176
|
+
}
|
|
177
|
+
export declare function extractPinetControlCommand(message: PinetControlCommandMessage): PinetControlCommand | null;
|
|
178
|
+
export declare function extractPinetSteeringMessage(message: {
|
|
137
179
|
threadId?: string;
|
|
138
180
|
body?: string;
|
|
139
|
-
metadata?:
|
|
140
|
-
}):
|
|
181
|
+
metadata?: PinetControlMetadata | null;
|
|
182
|
+
}): string | null;
|
|
141
183
|
export declare const FORM_METHODS: Set<string>;
|
|
142
|
-
export
|
|
184
|
+
export type SlackRequestBody = Record<string, unknown>;
|
|
185
|
+
export interface SlackApiRequest {
|
|
143
186
|
url: string;
|
|
144
187
|
init: RequestInit;
|
|
145
|
-
}
|
|
188
|
+
}
|
|
189
|
+
export declare function buildSlackRequest(method: string, token: string, body?: SlackRequestBody): SlackApiRequest;
|
|
146
190
|
export interface AbortableOperationTracker {
|
|
147
191
|
run<T>(operation: (signal: AbortSignal) => Promise<T>): Promise<T>;
|
|
148
192
|
abortAndWait(): Promise<void>;
|
|
149
193
|
isAborting(): boolean;
|
|
150
194
|
}
|
|
151
|
-
export
|
|
152
|
-
export declare function isAbortError(error: unknown): boolean;
|
|
195
|
+
export { createAbortError, isAbortError };
|
|
153
196
|
export declare function abortableDelay(ms: number, signal: AbortSignal): Promise<void>;
|
|
154
197
|
export declare function createAbortableOperationTracker(): AbortableOperationTracker;
|
|
155
198
|
export declare function stripBotMention(text: string, botUserId: string): string;
|
|
@@ -220,6 +263,7 @@ export interface AgentDisplayInfo {
|
|
|
220
263
|
routingScore?: number;
|
|
221
264
|
routingReasons?: string[];
|
|
222
265
|
}
|
|
266
|
+
export type AgentVisibilityMetadata = Record<string, unknown>;
|
|
223
267
|
export interface AgentVisibilityInput {
|
|
224
268
|
emoji: string;
|
|
225
269
|
name: string;
|
|
@@ -228,7 +272,7 @@ export interface AgentVisibilityInput {
|
|
|
228
272
|
stableId?: string | null;
|
|
229
273
|
session?: AgentSessionSummary | null;
|
|
230
274
|
status: "working" | "idle";
|
|
231
|
-
metadata?:
|
|
275
|
+
metadata?: AgentVisibilityMetadata | null;
|
|
232
276
|
lastHeartbeat?: string;
|
|
233
277
|
lastSeen?: string;
|
|
234
278
|
disconnectedAt?: string | null;
|
|
@@ -257,7 +301,7 @@ export interface AgentRoutingHint {
|
|
|
257
301
|
task?: string;
|
|
258
302
|
}
|
|
259
303
|
export declare function shortenPath(p: string, homedir: string): string;
|
|
260
|
-
export declare function extractAgentCapabilities(metadata:
|
|
304
|
+
export declare function extractAgentCapabilities(metadata: AgentVisibilityMetadata | null | undefined): AgentCapabilities;
|
|
261
305
|
export declare function buildAgentCapabilityTags(capabilities: AgentCapabilities): string[];
|
|
262
306
|
export interface MeshVisibilityOptions {
|
|
263
307
|
includeGhosts?: boolean;
|
|
@@ -379,6 +423,7 @@ export interface FollowerThreadState {
|
|
|
379
423
|
source?: string;
|
|
380
424
|
owner?: string;
|
|
381
425
|
}
|
|
426
|
+
export type FollowerInboxMessageMetadata = Record<string, unknown>;
|
|
382
427
|
export interface FollowerInboxEntry {
|
|
383
428
|
inboxId?: number;
|
|
384
429
|
message: {
|
|
@@ -387,7 +432,7 @@ export interface FollowerInboxEntry {
|
|
|
387
432
|
sender?: string;
|
|
388
433
|
body?: string;
|
|
389
434
|
createdAt?: string;
|
|
390
|
-
metadata:
|
|
435
|
+
metadata: FollowerInboxMessageMetadata | null;
|
|
391
436
|
};
|
|
392
437
|
}
|
|
393
438
|
export interface FollowerInboxSyncResult {
|
|
@@ -404,13 +449,21 @@ export interface BrokerInboxControlEntry {
|
|
|
404
449
|
inboxId: number;
|
|
405
450
|
command: PinetControlCommand;
|
|
406
451
|
}
|
|
452
|
+
export interface PinetSteeringInboxEntry {
|
|
453
|
+
inboxId: number;
|
|
454
|
+
message: FollowerInboxEntry["message"];
|
|
455
|
+
steeringText: string;
|
|
456
|
+
}
|
|
407
457
|
export interface BrokerInboxSyncResult {
|
|
408
458
|
controlEntries: BrokerInboxControlEntry[];
|
|
459
|
+
steeringEntries: PinetSteeringInboxEntry[];
|
|
409
460
|
inboxMessages: InboxMessage[];
|
|
410
461
|
}
|
|
411
462
|
export declare function isDirectMessageChannel(channel: string): boolean;
|
|
412
463
|
export declare function syncTransferredSlackThreadContexts(entries: FollowerInboxEntry[], existingThreads: ReadonlyMap<string, FollowerThreadState>, agentOwner: string): TransferredSlackThreadSyncResult;
|
|
413
464
|
export declare function syncFollowerInboxEntries(entries: FollowerInboxEntry[], existingThreads: ReadonlyMap<string, FollowerThreadState>, agentOwner: string, lastDmChannel: string | null): FollowerInboxSyncResult;
|
|
465
|
+
export declare function extractPinetSteeringInboxEntry(entry: FollowerInboxEntry): PinetSteeringInboxEntry | null;
|
|
466
|
+
export declare function formatPinetSteeringMessage(entry: PinetSteeringInboxEntry): string;
|
|
414
467
|
export declare function syncBrokerInboxEntries(entries: FollowerInboxEntry[]): BrokerInboxSyncResult;
|
|
415
468
|
export interface FollowerThreadChannelResolution {
|
|
416
469
|
channelId: string | null;
|
|
@@ -542,24 +595,21 @@ export interface CallSlackAPIOptions {
|
|
|
542
595
|
signal?: AbortSignal;
|
|
543
596
|
retryCount?: number;
|
|
544
597
|
}
|
|
545
|
-
export declare function callSlackAPI(method: string, token: string, body?:
|
|
546
|
-
|
|
598
|
+
export declare function callSlackAPI(method: string, token: string, body?: SlackRequestBody, options?: CallSlackAPIOptions): Promise<SlackResult>;
|
|
599
|
+
interface FollowerInboxMetadataEntry {
|
|
547
600
|
message: {
|
|
548
|
-
metadata?:
|
|
601
|
+
metadata?: FollowerInboxMessageMetadata | null;
|
|
549
602
|
};
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
message: {
|
|
553
|
-
threadId?: string;
|
|
554
|
-
metadata?: Record<string, unknown> | null;
|
|
555
|
-
};
|
|
556
|
-
}): boolean;
|
|
557
|
-
export declare function partitionFollowerInboxEntries<T extends {
|
|
603
|
+
}
|
|
604
|
+
interface FollowerInboxPartitionEntry extends FollowerInboxMetadataEntry {
|
|
558
605
|
message: {
|
|
559
606
|
threadId?: string;
|
|
560
|
-
metadata?:
|
|
607
|
+
metadata?: FollowerInboxMessageMetadata | null;
|
|
561
608
|
};
|
|
562
|
-
}
|
|
609
|
+
}
|
|
610
|
+
export declare function isRalphNudgeEntry(entry: FollowerInboxMetadataEntry): boolean;
|
|
611
|
+
export declare function isAgentToAgentEntry(entry: FollowerInboxPartitionEntry): boolean;
|
|
612
|
+
export declare function partitionFollowerInboxEntries<T extends FollowerInboxPartitionEntry>(entries: T[]): {
|
|
563
613
|
nudges: T[];
|
|
564
614
|
agentMessages: T[];
|
|
565
615
|
regular: T[];
|