shraga 0.1.2 → 0.1.4

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.
@@ -189,7 +189,7 @@ export async function* runAgentTurn(msg: IngressMessage): AsyncGenerator<AgentEv
189
189
  : `#${channelName || 'channel'} context`;
190
190
  appendMessage(sessionId, {
191
191
  id: crypto.randomUUID(), role: 'user',
192
- blocks: [{ type: 'context', label, text: `${channelCtx}\n\n[Use mcp-slack tools (get_slack_history_by_channel, post_slack_message) for further context or replies. Always read channel history before posting.]` }],
192
+ blocks: [{ type: 'context', label, text: `${channelCtx}\n\n[Use mcp-slack-use tools (get_slack_history_by_channel, post_slack_message) for further context or replies. Always read channel history before posting.]` }],
193
193
  });
194
194
  }
195
195
  }
@@ -1,4 +1,4 @@
1
- // slackFeature — the ServerFeature that mounts Slack in this app. It wires the mcp-slack package
1
+ // slackFeature — the ServerFeature that mounts Slack in this app. It wires the mcp-slack-use package
2
2
  // `ingress` (protocol) to the agent-glue (bot.ts) and subscribes the data-sync deploy notifier
3
3
  // (event bus → owner DMs). Slack ships in this app, so index.ts registers this directly.
4
4
  import type { ServerFeature, FeatureContext } from '../features.ts';
@@ -27,6 +27,13 @@ export function registerTurnContext(name: string, contribute: TurnContextContrib
27
27
  contributors.set(name, contribute);
28
28
  }
29
29
 
30
+ /** Clear all registered contributors. For tests: the registry is a process-global, so a test that
31
+ * asserts the empty-registry (no-contributor) behavior must reset it first or it inherits whatever
32
+ * another test file registered — bun's cross-file order is not stable across platforms. */
33
+ export function clearTurnContext(): void {
34
+ contributors.clear();
35
+ }
36
+
30
37
  /**
31
38
  * Collect every contributor's block for this turn, joined by a blank line. Empty when none is
32
39
  * registered — which is the core's own state, so the core's prompt is byte-identical to before.
@@ -1,85 +0,0 @@
1
- import { writeFileSync, mkdirSync } from 'node:fs';
2
- import path from 'node:path';
3
- import { dataPath } from '../paths.ts';
4
-
5
- const PREFIX = '[artifacts:export]';
6
-
7
- let browserInstance: any = null;
8
- let idleTimer: ReturnType<typeof setTimeout> | null = null;
9
- const IDLE_TIMEOUT = 60_000;
10
-
11
- async function getBrowser() {
12
- if (browserInstance) {
13
- resetIdleTimer();
14
- return browserInstance;
15
- }
16
-
17
- let puppeteer: any;
18
- try {
19
- puppeteer = await import('puppeteer');
20
- } catch {
21
- throw new Error('puppeteer not installed. Run: bun add puppeteer');
22
- }
23
-
24
- console.log(PREFIX, 'launching browser');
25
- browserInstance = await puppeteer.default.launch({
26
- headless: true,
27
- args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
28
- });
29
-
30
- browserInstance.on('disconnected', () => { browserInstance = null; });
31
- resetIdleTimer();
32
- return browserInstance;
33
- }
34
-
35
- function resetIdleTimer() {
36
- if (idleTimer) clearTimeout(idleTimer);
37
- idleTimer = setTimeout(async () => {
38
- if (browserInstance) {
39
- console.log(PREFIX, 'closing idle browser');
40
- await browserInstance.close().catch(() => {});
41
- browserInstance = null;
42
- }
43
- }, IDLE_TIMEOUT);
44
- }
45
-
46
- export async function exportToPng(
47
- html: string,
48
- dimensions: [number, number],
49
- ): Promise<Buffer> {
50
- const [width, height] = dimensions;
51
- const browser = await getBrowser();
52
- const page = await browser.newPage();
53
-
54
- try {
55
- await page.setViewport({ width, height, deviceScaleFactor: 2 });
56
- await page.setContent(html, { waitUntil: 'networkidle0', timeout: 15_000 });
57
- const png = await page.screenshot({ type: 'png', clip: { x: 0, y: 0, width, height } });
58
- return Buffer.from(png);
59
- } finally {
60
- await page.close();
61
- }
62
- }
63
-
64
- export async function exportAndSave(
65
- sessionId: string,
66
- artifactId: string,
67
- html: string,
68
- dimensions: [number, number],
69
- ): Promise<string> {
70
- const png = await exportToPng(html, dimensions);
71
- const dir = dataPath(`sessions/${sessionId}/artifacts`);
72
- mkdirSync(dir, { recursive: true });
73
- const filePath = path.join(dir, `${artifactId}.png`);
74
- writeFileSync(filePath, png);
75
- console.log(PREFIX, `saved ${filePath} (${png.length} bytes)`);
76
- return filePath;
77
- }
78
-
79
- export async function closeBrowser() {
80
- if (idleTimer) clearTimeout(idleTimer);
81
- if (browserInstance) {
82
- await browserInstance.close().catch(() => {});
83
- browserInstance = null;
84
- }
85
- }