@pinet/slack-bridge 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -1
- package/dist/activity-log.d.ts +10 -3
- package/dist/agent-event-runtime.d.ts +0 -2
- package/dist/agent-event-runtime.js +0 -1
- package/dist/agent-prompt-guidance.d.ts +1 -6
- package/dist/agent-prompt-guidance.js +1 -6
- package/dist/broker/adapters/slack.d.ts +4 -1
- package/dist/broker/adapters/slack.js +16 -9
- package/dist/broker/client.d.ts +21 -4
- package/dist/broker/client.js +65 -25
- package/dist/broker/hibernation-activation-authority.d.ts +22 -0
- package/dist/broker/hibernation-activation-authority.js +51 -0
- package/dist/broker/hibernation-activation.d.ts +75 -0
- package/dist/broker/hibernation-activation.js +95 -0
- package/dist/broker/hibernation-command-router.d.ts +54 -0
- package/dist/broker/hibernation-command-router.js +124 -0
- package/dist/broker/hibernation-runtime-adapters.d.ts +79 -0
- package/dist/broker/hibernation-runtime-adapters.js +473 -0
- package/dist/broker/hibernation-runtime-helpers.d.ts +146 -0
- package/dist/broker/hibernation-runtime-helpers.js +243 -0
- package/dist/broker/index.d.ts +16 -1
- package/dist/broker/index.js +68 -10
- package/dist/broker/lock-conflict.d.ts +109 -0
- package/dist/broker/lock-conflict.js +409 -0
- package/dist/broker/socket-server.d.ts +25 -0
- package/dist/broker/socket-server.js +234 -4
- package/dist/broker-delivery.d.ts +1 -0
- package/dist/broker-delivery.js +10 -1
- package/dist/broker-runtime.d.ts +14 -2
- package/dist/broker-runtime.js +114 -3
- package/dist/canvases.d.ts +12 -2
- package/dist/canvases.js +1 -3
- package/dist/compaction-gate.d.ts +7 -0
- package/dist/compaction-gate.js +35 -0
- package/dist/deploy-manifest.d.ts +8 -2
- package/dist/deploy-manifest.js +9 -7
- package/dist/follower-runtime.d.ts +5 -2
- package/dist/follower-runtime.js +39 -5
- package/dist/git-metadata.d.ts +5 -9
- package/dist/git-metadata.js +23 -42
- package/dist/guardrails.js +5 -0
- package/dist/helpers.d.ts +77 -27
- package/dist/helpers.js +150 -39
- package/dist/hibernation-config.d.ts +13 -0
- package/dist/hibernation-config.js +14 -0
- package/dist/home-tab.d.ts +13 -2
- package/dist/imessage-tools.d.ts +4 -1
- package/dist/inbox-drain-runtime.d.ts +1 -0
- package/dist/inbox-drain-runtime.js +5 -1
- package/dist/index.js +340 -108
- package/dist/pinet-commands.d.ts +14 -1
- package/dist/pinet-commands.js +93 -22
- package/dist/pinet-mesh-ops.d.ts +6 -4
- package/dist/pinet-mesh-ops.js +8 -1
- package/dist/pinet-runtime-composition.d.ts +2 -1
- package/dist/pinet-runtime-composition.js +14 -3
- package/dist/pinet-session-formatting.d.ts +26 -2
- package/dist/pinet-session-formatting.js +2 -0
- package/dist/pinet-tools.d.ts +14 -0
- package/dist/pinet-tools.js +355 -50
- package/dist/prompts/broker/default.md +3 -3
- package/dist/prompts/broker/tmux.md +3 -3
- package/dist/runtime-agent-context.d.ts +3 -3
- package/dist/runtime-agent-context.js +12 -6
- package/dist/runtime-mode.js +4 -0
- package/dist/session-ui-runtime.js +3 -1
- package/dist/single-player-runtime.d.ts +1 -1
- package/dist/single-player-runtime.js +21 -5
- package/dist/slack-access.d.ts +10 -2
- package/dist/slack-access.js +64 -22
- package/dist/slack-block-kit.d.ts +44 -2
- package/dist/slack-block-kit.js +5 -5
- package/dist/slack-file-access.d.ts +12 -1
- package/dist/slack-file-access.js +4 -4
- package/dist/slack-message-context.d.ts +9 -2
- package/dist/slack-modals.d.ts +4 -1
- package/dist/slack-modals.js +5 -5
- package/dist/slack-pinet-runtime-adapter.d.ts +1 -0
- package/dist/slack-pinet-runtime-adapter.js +10 -0
- package/dist/slack-presence.d.ts +5 -4
- package/dist/slack-request-runtime.d.ts +3 -2
- package/dist/slack-scope-diagnostics.d.ts +27 -2
- package/dist/slack-socket-dedup.d.ts +8 -5
- package/dist/slack-tools.d.ts +3 -1
- package/dist/slack-tools.js +26 -16
- package/dist/slack-upload.d.ts +17 -1
- package/dist/subtree-broker-runtime.d.ts +83 -2
- package/dist/subtree-broker-runtime.js +774 -109
- package/dist/tool-output-limits.d.ts +11 -0
- package/dist/tool-output-limits.js +20 -0
- package/dist/tool-registration-runtime.d.ts +3 -0
- package/dist/tool-registration-runtime.js +27 -0
- package/package.json +8 -8
package/dist/helpers.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { classifyPinetMail, formatPinetMailClassLabel, } from "@pinet/broker-core/mail-classification";
|
|
5
5
|
import { buildCompatibilityInstanceScope, buildCompatibilityWorkspaceScope, buildRuntimeScopeCarrier, } from "@pinet/transport-core";
|
|
6
|
+
import { createAbortError, isAbortError, sleep } from "@pinet/transport-core/async";
|
|
6
7
|
import { buildPinetReadPointer } from "./broker-inbound-persistence.js";
|
|
7
8
|
import { matchesToolPattern } from "./guardrails.js";
|
|
8
9
|
import { getPinetSessionPath, summarizePinetStableId } from "./pinet-session-formatting.js";
|
|
@@ -421,6 +422,33 @@ export async function reloadPinetRuntimeSafely(reloader) {
|
|
|
421
422
|
throw new Error(`Reload failed: ${reloadMessage}. Restored the previous runtime.`);
|
|
422
423
|
}
|
|
423
424
|
}
|
|
425
|
+
export async function reloadPinetRuntimeInPlaceSafely(input) {
|
|
426
|
+
const snapshot = input.snapshotState();
|
|
427
|
+
try {
|
|
428
|
+
input.refreshState();
|
|
429
|
+
await input.validateRefreshedState();
|
|
430
|
+
}
|
|
431
|
+
catch (validationErr) {
|
|
432
|
+
input.restoreState(snapshot);
|
|
433
|
+
throw validationErr;
|
|
434
|
+
}
|
|
435
|
+
try {
|
|
436
|
+
await input.reloadRuntime();
|
|
437
|
+
}
|
|
438
|
+
catch (reloadErr) {
|
|
439
|
+
input.restoreState(snapshot);
|
|
440
|
+
try {
|
|
441
|
+
await input.reloadRuntime();
|
|
442
|
+
}
|
|
443
|
+
catch (rollbackErr) {
|
|
444
|
+
const reloadMessage = reloadErr instanceof Error ? reloadErr.message : String(reloadErr);
|
|
445
|
+
const rollbackMessage = rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr);
|
|
446
|
+
throw new Error(`Reload failed: ${reloadMessage}. Rollback to the previous runtime also failed: ${rollbackMessage}`);
|
|
447
|
+
}
|
|
448
|
+
const reloadMessage = reloadErr instanceof Error ? reloadErr.message : String(reloadErr);
|
|
449
|
+
throw new Error(`Reload failed: ${reloadMessage}. Restored the previous runtime.`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
424
452
|
function parsePinetControlEnvelope(value) {
|
|
425
453
|
if (typeof value !== "object" || value === null)
|
|
426
454
|
return null;
|
|
@@ -471,6 +499,62 @@ export function normalizeOutgoingPinetControlMessage(body, metadata) {
|
|
|
471
499
|
},
|
|
472
500
|
};
|
|
473
501
|
}
|
|
502
|
+
function normalizePinetSteeringText(value) {
|
|
503
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
504
|
+
}
|
|
505
|
+
function parsePinetSteeringEnvelope(value) {
|
|
506
|
+
if (typeof value !== "object" || value === null)
|
|
507
|
+
return null;
|
|
508
|
+
const record = value;
|
|
509
|
+
if (record.type !== "pinet:steer")
|
|
510
|
+
return null;
|
|
511
|
+
return (normalizePinetSteeringText(record.message) ??
|
|
512
|
+
normalizePinetSteeringText(record.text) ??
|
|
513
|
+
normalizePinetSteeringText(record.body));
|
|
514
|
+
}
|
|
515
|
+
function parseStructuredPinetSteeringMessageFromText(text) {
|
|
516
|
+
const trimmed = text?.trim();
|
|
517
|
+
if (!trimmed)
|
|
518
|
+
return null;
|
|
519
|
+
try {
|
|
520
|
+
return parsePinetSteeringEnvelope(JSON.parse(trimmed));
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
function parseLegacyPinetSteeringMessageFromText(text) {
|
|
527
|
+
const trimmed = text?.trim();
|
|
528
|
+
if (!trimmed?.startsWith("/steer"))
|
|
529
|
+
return null;
|
|
530
|
+
const nextChar = trimmed.charAt("/steer".length);
|
|
531
|
+
if (nextChar && !/\s/.test(nextChar))
|
|
532
|
+
return null;
|
|
533
|
+
return normalizePinetSteeringText(trimmed.slice("/steer".length));
|
|
534
|
+
}
|
|
535
|
+
export function getPinetSteeringMessageFromText(text) {
|
|
536
|
+
return (parseStructuredPinetSteeringMessageFromText(text) ??
|
|
537
|
+
parseLegacyPinetSteeringMessageFromText(text));
|
|
538
|
+
}
|
|
539
|
+
export function buildPinetSteeringMetadata(message) {
|
|
540
|
+
return { type: "pinet:steer", message };
|
|
541
|
+
}
|
|
542
|
+
export function buildPinetSteeringMessage(message) {
|
|
543
|
+
return JSON.stringify(buildPinetSteeringMetadata(message));
|
|
544
|
+
}
|
|
545
|
+
export function normalizeOutgoingPinetSteeringMessage(body, metadata) {
|
|
546
|
+
const message = getPinetSteeringMessageFromText(body);
|
|
547
|
+
if (!message)
|
|
548
|
+
return null;
|
|
549
|
+
return {
|
|
550
|
+
body: buildPinetSteeringMessage(message),
|
|
551
|
+
metadata: {
|
|
552
|
+
...(metadata ?? {}),
|
|
553
|
+
...buildPinetSteeringMetadata(message),
|
|
554
|
+
kind: "pinet_steer",
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
}
|
|
474
558
|
function extractPinetSkinStatusVocabulary(value) {
|
|
475
559
|
const record = asRecord(value);
|
|
476
560
|
if (!record)
|
|
@@ -503,6 +587,23 @@ export function extractPinetControlCommand(message) {
|
|
|
503
587
|
// Backward-compatible fallback for structured JSON or exact slash commands sent over a2a flows.
|
|
504
588
|
return getPinetControlCommandFromText(message.body);
|
|
505
589
|
}
|
|
590
|
+
export function extractPinetSteeringMessage(message) {
|
|
591
|
+
const metadata = message.metadata ?? {};
|
|
592
|
+
if (metadata.scheduledWakeup === true)
|
|
593
|
+
return null;
|
|
594
|
+
const metadataMessage = parsePinetSteeringEnvelope(metadata) ??
|
|
595
|
+
(metadata.kind === "pinet_steer" || metadata.kind === "pinet_steering"
|
|
596
|
+
? (normalizePinetSteeringText(metadata.message) ??
|
|
597
|
+
normalizePinetSteeringText(metadata.text) ??
|
|
598
|
+
normalizePinetSteeringText(metadata.body))
|
|
599
|
+
: null);
|
|
600
|
+
if (metadataMessage)
|
|
601
|
+
return metadataMessage;
|
|
602
|
+
if (metadata.reactionTrigger === true && metadata.reactionAction === "steer") {
|
|
603
|
+
return normalizePinetSteeringText(message.body);
|
|
604
|
+
}
|
|
605
|
+
return getPinetSteeringMessageFromText(message.body);
|
|
606
|
+
}
|
|
506
607
|
// ─── Slack API encoding ──────────────────────────────────
|
|
507
608
|
export const FORM_METHODS = new Set([
|
|
508
609
|
"auth.test",
|
|
@@ -549,30 +650,9 @@ export function buildSlackRequest(method, token, body) {
|
|
|
549
650
|
},
|
|
550
651
|
};
|
|
551
652
|
}
|
|
552
|
-
export
|
|
553
|
-
const error = new Error(message);
|
|
554
|
-
error.name = "AbortError";
|
|
555
|
-
return error;
|
|
556
|
-
}
|
|
557
|
-
export function isAbortError(error) {
|
|
558
|
-
return error instanceof Error && error.name === "AbortError";
|
|
559
|
-
}
|
|
653
|
+
export { createAbortError, isAbortError };
|
|
560
654
|
export function abortableDelay(ms, signal) {
|
|
561
|
-
|
|
562
|
-
return Promise.reject(createAbortError());
|
|
563
|
-
}
|
|
564
|
-
return new Promise((resolve, reject) => {
|
|
565
|
-
const timer = setTimeout(() => {
|
|
566
|
-
signal.removeEventListener("abort", onAbort);
|
|
567
|
-
resolve();
|
|
568
|
-
}, ms);
|
|
569
|
-
function onAbort() {
|
|
570
|
-
clearTimeout(timer);
|
|
571
|
-
signal.removeEventListener("abort", onAbort);
|
|
572
|
-
reject(createAbortError());
|
|
573
|
-
}
|
|
574
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
575
|
-
});
|
|
655
|
+
return sleep(ms, { signal });
|
|
576
656
|
}
|
|
577
657
|
export function createAbortableOperationTracker() {
|
|
578
658
|
let aborting = false;
|
|
@@ -1266,8 +1346,8 @@ export function buildWorkerPromptGuidelines() {
|
|
|
1266
1346
|
"- In PM mode, remain accountable: nominate an implementation lead, delegate implementation, coordinate blockers/status, act as second-pass reviewer, and coordinate merge readiness.",
|
|
1267
1347
|
"- Before delegating through Pinet, call `pinet action=agents` with the target repo to find a suitable connected worker in the same repo/worktree, then delegate via `pinet action=send`.",
|
|
1268
1348
|
"- Keep delegation inside the Pinet or Slack thread so ACKs, blockers, status updates, and final results flow back to the original sender.",
|
|
1269
|
-
"-
|
|
1270
|
-
"- When delegating, include the workflow (`ack/work/ask/report`), the task,
|
|
1349
|
+
"- For work in `gugu91/pinet`, do not start or delegate changes unless the request names a GitHub issue/PR with clear maintainer priority/approval; if missing or unclear, ask first. This gate is specific to `gugu91/pinet`; unrelated repositories, including `tmustier/pi-extensions`, follow their own instructions and normal requester authority.",
|
|
1350
|
+
"- When delegating, include the workflow (`ack/work/ask/report`), the task, repo/branch/worktree setup, important files, acceptance criteria, where to reply, and any issue/PR numbers or maintainer approval required by the target repository's instructions.",
|
|
1271
1351
|
"- Use `pinet action=lanes` to keep PM-mode or complex coordination lane metadata durable when the broker asks you to track lane state/roles.",
|
|
1272
1352
|
];
|
|
1273
1353
|
}
|
|
@@ -1517,8 +1597,39 @@ export function syncFollowerInboxEntries(entries, existingThreads, agentOwner, l
|
|
|
1517
1597
|
changed,
|
|
1518
1598
|
};
|
|
1519
1599
|
}
|
|
1600
|
+
export function extractPinetSteeringInboxEntry(entry) {
|
|
1601
|
+
if (entry.inboxId == null)
|
|
1602
|
+
return null;
|
|
1603
|
+
const steeringText = extractPinetSteeringMessage({
|
|
1604
|
+
threadId: entry.message.threadId,
|
|
1605
|
+
body: entry.message.body,
|
|
1606
|
+
metadata: entry.message.metadata,
|
|
1607
|
+
});
|
|
1608
|
+
if (!steeringText)
|
|
1609
|
+
return null;
|
|
1610
|
+
return {
|
|
1611
|
+
inboxId: entry.inboxId,
|
|
1612
|
+
message: entry.message,
|
|
1613
|
+
steeringText,
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
export function formatPinetSteeringMessage(entry) {
|
|
1617
|
+
const threadTs = entry.message.threadId ?? "";
|
|
1618
|
+
const sender = getPinetSenderLabel(entry.message);
|
|
1619
|
+
const transferSuffix = formatPinetThreadTransferSuffix(entry);
|
|
1620
|
+
const pointer = formatPinetInboxPointer(entry);
|
|
1621
|
+
return [
|
|
1622
|
+
"Pinet steering message:",
|
|
1623
|
+
`[thread ${threadTs}] ${sender}: inbox_id=${entry.inboxId}${transferSuffix} ${pointer}`,
|
|
1624
|
+
"",
|
|
1625
|
+
entry.steeringText,
|
|
1626
|
+
"",
|
|
1627
|
+
"This message was sent with explicit steering semantics. Incorporate it now, even if it interrupts the active turn. Reply via pinet action=send when needed.",
|
|
1628
|
+
].join("\n");
|
|
1629
|
+
}
|
|
1520
1630
|
export function syncBrokerInboxEntries(entries) {
|
|
1521
1631
|
const controlEntries = [];
|
|
1632
|
+
const steeringEntries = [];
|
|
1522
1633
|
const inboxMessages = [];
|
|
1523
1634
|
for (const entry of entries) {
|
|
1524
1635
|
const meta = entry.message.metadata ?? {};
|
|
@@ -1536,6 +1647,11 @@ export function syncBrokerInboxEntries(entries) {
|
|
|
1536
1647
|
controlEntries.push({ inboxId, command: control });
|
|
1537
1648
|
continue;
|
|
1538
1649
|
}
|
|
1650
|
+
const steering = extractPinetSteeringInboxEntry(entry);
|
|
1651
|
+
if (steering) {
|
|
1652
|
+
steeringEntries.push(steering);
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
1539
1655
|
const scope = extractRuntimeScopeCarrier(meta.scope);
|
|
1540
1656
|
inboxMessages.push({
|
|
1541
1657
|
channel: "",
|
|
@@ -1550,6 +1666,7 @@ export function syncBrokerInboxEntries(entries) {
|
|
|
1550
1666
|
}
|
|
1551
1667
|
return {
|
|
1552
1668
|
controlEntries,
|
|
1669
|
+
steeringEntries,
|
|
1553
1670
|
inboxMessages,
|
|
1554
1671
|
};
|
|
1555
1672
|
}
|
|
@@ -2030,7 +2147,7 @@ const MAX_PINET_SKIN_PERSONALITY_LENGTH = 260;
|
|
|
2030
2147
|
const MAX_PINET_SKIN_PROMPT_GUIDELINE_LENGTH = 460;
|
|
2031
2148
|
const PINET_BUILT_IN_SKIN_FILES = ["foundation", "cosmere"];
|
|
2032
2149
|
let cachedBuiltInPinetSkinDescriptors = null;
|
|
2033
|
-
function
|
|
2150
|
+
function isPinetSkinObject(value) {
|
|
2034
2151
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2035
2152
|
}
|
|
2036
2153
|
function readStringProperty(value, key) {
|
|
@@ -2055,13 +2172,13 @@ function validatePinetSkinTheme(value) {
|
|
|
2055
2172
|
return null;
|
|
2056
2173
|
}
|
|
2057
2174
|
function validatePinetSkinStatusVocabulary(value) {
|
|
2058
|
-
if (!
|
|
2175
|
+
if (!isPinetSkinObject(value)) {
|
|
2059
2176
|
return null;
|
|
2060
2177
|
}
|
|
2061
2178
|
return extractPinetSkinStatusVocabulary(value) ?? {};
|
|
2062
2179
|
}
|
|
2063
2180
|
function validateBuiltInPinetSkinCharacter(id, value) {
|
|
2064
|
-
if (!
|
|
2181
|
+
if (!isPinetSkinObject(value)) {
|
|
2065
2182
|
return null;
|
|
2066
2183
|
}
|
|
2067
2184
|
const name = readStringProperty(value, "name");
|
|
@@ -2075,7 +2192,7 @@ function validateBuiltInPinetSkinCharacter(id, value) {
|
|
|
2075
2192
|
return { id, name, ...(aliases.length > 0 ? { aliases } : {}), emoji, persona, style };
|
|
2076
2193
|
}
|
|
2077
2194
|
function validateBuiltInPinetSkinRoleDescriptor(value) {
|
|
2078
|
-
if (!
|
|
2195
|
+
if (!isPinetSkinObject(value)) {
|
|
2079
2196
|
return null;
|
|
2080
2197
|
}
|
|
2081
2198
|
const characterPool = readStringArrayProperty(value, "characterPool");
|
|
@@ -2093,7 +2210,7 @@ function validateBuiltInPinetSkinRoleDescriptor(value) {
|
|
|
2093
2210
|
};
|
|
2094
2211
|
}
|
|
2095
2212
|
function validateBuiltInPinetSkinDescriptor(value) {
|
|
2096
|
-
if (!
|
|
2213
|
+
if (!isPinetSkinObject(value)) {
|
|
2097
2214
|
throw new Error("Pinet skin descriptor must be an object.");
|
|
2098
2215
|
}
|
|
2099
2216
|
const keyValue = readStringProperty(value, "key");
|
|
@@ -2105,7 +2222,7 @@ function validateBuiltInPinetSkinDescriptor(value) {
|
|
|
2105
2222
|
if (!key || !aliases || !displayName || !intent || !statusVocabulary) {
|
|
2106
2223
|
throw new Error("Pinet skin descriptor is missing required top-level fields.");
|
|
2107
2224
|
}
|
|
2108
|
-
if (!
|
|
2225
|
+
if (!isPinetSkinObject(value.roles)) {
|
|
2109
2226
|
throw new Error(`Pinet skin descriptor ${key} must define roles.`);
|
|
2110
2227
|
}
|
|
2111
2228
|
const brokerRole = validateBuiltInPinetSkinRoleDescriptor(value.roles.broker);
|
|
@@ -2113,7 +2230,7 @@ function validateBuiltInPinetSkinDescriptor(value) {
|
|
|
2113
2230
|
if (!brokerRole || !workerRole) {
|
|
2114
2231
|
throw new Error(`Pinet skin descriptor ${key} must define broker and worker roles.`);
|
|
2115
2232
|
}
|
|
2116
|
-
if (!
|
|
2233
|
+
if (!isPinetSkinObject(value.characters)) {
|
|
2117
2234
|
throw new Error(`Pinet skin descriptor ${key} must define characters.`);
|
|
2118
2235
|
}
|
|
2119
2236
|
const characters = {};
|
|
@@ -2704,12 +2821,7 @@ export async function callSlackAPI(method, token, body, options = {}) {
|
|
|
2704
2821
|
throw new Error(`Slack ${method}: rate limited after ${maxRetries} retries`);
|
|
2705
2822
|
}
|
|
2706
2823
|
const wait = Number(res.headers.get("retry-after") ?? "3");
|
|
2707
|
-
|
|
2708
|
-
await abortableDelay(wait * 1000, signal);
|
|
2709
|
-
}
|
|
2710
|
-
else {
|
|
2711
|
-
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
|
|
2712
|
-
}
|
|
2824
|
+
await sleep(wait * 1000, { signal });
|
|
2713
2825
|
return callSlackAPI(method, token, body, { signal, retryCount: retryCount + 1 });
|
|
2714
2826
|
}
|
|
2715
2827
|
const data = (await res.json());
|
|
@@ -2718,7 +2830,6 @@ export async function callSlackAPI(method, token, body, options = {}) {
|
|
|
2718
2830
|
}
|
|
2719
2831
|
return data;
|
|
2720
2832
|
}
|
|
2721
|
-
// ─── Follower inbox partitioning (#102, #175) ───────────
|
|
2722
2833
|
export function isRalphNudgeEntry(entry) {
|
|
2723
2834
|
return entry.message.metadata?.kind === "ralph_loop_nudge";
|
|
2724
2835
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SlackBridgeSettings } from "./helpers.js";
|
|
2
|
+
export interface ResolvedHibernationSettings {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
mode: "observe" | "manual" | "auto";
|
|
5
|
+
allowedRepos: string[];
|
|
6
|
+
graceMs: number;
|
|
7
|
+
idleDebounceMs: number;
|
|
8
|
+
handshakeTimeoutMs: number;
|
|
9
|
+
wakeLeaseMs: number;
|
|
10
|
+
maxConcurrentWakes: number;
|
|
11
|
+
maxConcurrentWakesPerRepo: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function resolveHibernationSettings(settings: Pick<SlackBridgeSettings, "hibernation">): ResolvedHibernationSettings;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function resolveHibernationSettings(settings) {
|
|
2
|
+
const value = settings.hibernation;
|
|
3
|
+
return {
|
|
4
|
+
enabled: value?.enabled === true,
|
|
5
|
+
mode: value?.mode ?? "observe",
|
|
6
|
+
allowedRepos: [...(value?.allowedRepos ?? [])],
|
|
7
|
+
graceMs: value?.graceMs ?? 60 * 60_000,
|
|
8
|
+
idleDebounceMs: value?.idleDebounceMs ?? 2 * 60_000,
|
|
9
|
+
handshakeTimeoutMs: value?.handshakeTimeoutMs ?? 30_000,
|
|
10
|
+
wakeLeaseMs: value?.wakeLeaseMs ?? 90_000,
|
|
11
|
+
maxConcurrentWakes: value?.maxConcurrentWakes ?? 2,
|
|
12
|
+
maxConcurrentWakesPerRepo: value?.maxConcurrentWakesPerRepo ?? 1,
|
|
13
|
+
};
|
|
14
|
+
}
|
package/dist/home-tab.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import type { BrokerControlPlaneDashboardSnapshot } from "./broker/control-plane-dashboard.js";
|
|
2
2
|
import type { SlackBridgeRuntimeMode } from "./runtime-mode.js";
|
|
3
3
|
export type SlackBlock = Record<string, unknown>;
|
|
4
|
+
export type SlackSectionAccessory = Record<string, unknown>;
|
|
5
|
+
export type SlackHomeTabPublishResponse = Record<string, unknown>;
|
|
6
|
+
export interface SlackTextObject extends Record<string, unknown> {
|
|
7
|
+
type: "plain_text" | "mrkdwn";
|
|
8
|
+
text: string;
|
|
9
|
+
emoji?: boolean;
|
|
10
|
+
}
|
|
4
11
|
export interface SlackHomeView {
|
|
5
12
|
type: "home";
|
|
6
13
|
blocks: SlackBlock[];
|
|
7
14
|
}
|
|
15
|
+
export interface SlackHomeTabPublishRequest extends Record<string, unknown> {
|
|
16
|
+
user_id: string;
|
|
17
|
+
view: SlackHomeView;
|
|
18
|
+
}
|
|
8
19
|
export interface PublishSlackHomeTabInput {
|
|
9
|
-
slack: (method: string, token: string, body?:
|
|
20
|
+
slack: (method: string, token: string, body?: SlackHomeTabPublishRequest) => Promise<SlackHomeTabPublishResponse>;
|
|
10
21
|
token: string;
|
|
11
22
|
userId: string;
|
|
12
23
|
view: SlackHomeView;
|
|
@@ -23,5 +34,5 @@ export interface StandalonePinetHomeTabInput {
|
|
|
23
34
|
}
|
|
24
35
|
export declare function renderBrokerControlPlaneHomeTabView(snapshot: BrokerControlPlaneDashboardSnapshot): SlackHomeView;
|
|
25
36
|
export declare function renderStandalonePinetHomeTabView(input: StandalonePinetHomeTabInput): SlackHomeView;
|
|
26
|
-
export declare function buildSlackHomeTabPublishRequest(userId: string, view: SlackHomeView):
|
|
37
|
+
export declare function buildSlackHomeTabPublishRequest(userId: string, view: SlackHomeView): SlackHomeTabPublishRequest;
|
|
27
38
|
export declare function publishSlackHomeTab(input: PublishSlackHomeTabInput): Promise<void>;
|
package/dist/imessage-tools.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { NormalizedMessageContent } from "@pinet/transport-core";
|
|
3
3
|
import type { Broker } from "./broker/index.js";
|
|
4
|
+
export interface IMessageToolMetadata extends Record<string, unknown> {
|
|
5
|
+
recipient: string;
|
|
6
|
+
}
|
|
4
7
|
export interface IMessageToolSendInput {
|
|
5
8
|
threadId: string;
|
|
6
9
|
body: string;
|
|
@@ -10,7 +13,7 @@ export interface IMessageToolSendInput {
|
|
|
10
13
|
agentName: string;
|
|
11
14
|
agentEmoji: string;
|
|
12
15
|
agentOwnerToken: string;
|
|
13
|
-
metadata:
|
|
16
|
+
metadata: IMessageToolMetadata;
|
|
14
17
|
}
|
|
15
18
|
export interface IMessageToolSendResult {
|
|
16
19
|
adapter: string;
|
|
@@ -19,6 +19,7 @@ export interface InboxDrainRuntimeDeps {
|
|
|
19
19
|
hasFollowerClient: () => boolean;
|
|
20
20
|
flushFollowerDeliveredAcks: () => Promise<void>;
|
|
21
21
|
markBrokerInboxIdsDelivered: (inboxIds: number[]) => void;
|
|
22
|
+
markSubtreeInboxIdsDelivered: (inboxIds: number[]) => void;
|
|
22
23
|
getFollowerDeliveryState: () => FollowerDeliveryState;
|
|
23
24
|
maxMessagesPerDrain?: number;
|
|
24
25
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getBrokerInboxIds } from "./broker-delivery.js";
|
|
1
|
+
import { getBrokerInboxIds, getSubtreeInboxIds } from "./broker-delivery.js";
|
|
2
2
|
import { markFollowerInboxIdsDelivered } from "./follower-delivery.js";
|
|
3
3
|
import { formatInboxMessages } from "./helpers.js";
|
|
4
4
|
const DEFAULT_MAX_MESSAGES_PER_DRAIN = 5;
|
|
@@ -31,6 +31,7 @@ export function createInboxDrainRuntime(deps) {
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
const brokerInboxIds = getBrokerInboxIds(pending);
|
|
34
|
+
const subtreeInboxIds = getSubtreeInboxIds(pending);
|
|
34
35
|
deps.updateBadge();
|
|
35
36
|
void deps.reportStatus("working").catch(() => {
|
|
36
37
|
/* best effort */
|
|
@@ -58,6 +59,9 @@ export function createInboxDrainRuntime(deps) {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
}
|
|
62
|
+
if (subtreeInboxIds.length > 0) {
|
|
63
|
+
deps.markSubtreeInboxIdsDelivered(subtreeInboxIds);
|
|
64
|
+
}
|
|
61
65
|
return;
|
|
62
66
|
}
|
|
63
67
|
deps.restoreInboxMessages(pending);
|