astro-claw 1.0.2 → 1.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-claw",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Claude Code over Slack — your AI crew member. One command: npx astro-claw",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "display_information": {
3
- "name": "Astronaut",
3
+ "name": "Astro Claw",
4
4
  "description": "AI crew member powered by Claude Code",
5
5
  "background_color": "#1a1a2e"
6
6
  },
@@ -11,7 +11,7 @@
11
11
  "messages_tab_read_only_enabled": false
12
12
  },
13
13
  "bot_user": {
14
- "display_name": "Astronaut",
14
+ "display_name": "Astro Claw",
15
15
  "always_online": true
16
16
  }
17
17
  },
@@ -1,5 +1,5 @@
1
1
  display_information:
2
- name: Astronaut
2
+ name: Astro Claw
3
3
  description: AI crew member powered by Claude Code
4
4
  background_color: "#1a1a2e"
5
5
  features:
package/slack-setup.js CHANGED
@@ -117,6 +117,45 @@ export default async function selfDrivingSlackSetup() {
117
117
 
118
118
  const page = (await browser.pages())[0] || await browser.newPage();
119
119
 
120
+ // ── Visual cue: inject banner on every page load ──
121
+ const BANNER_CSS = `
122
+ position: fixed; top: 0; left: 0; right: 0; z-index: 2147483647;
123
+ height: 36px; display: flex; align-items: center; justify-content: center; gap: 8px;
124
+ background: linear-gradient(135deg, #6C5CE7, #A855F7);
125
+ color: #fff; font: 600 13px/1 -apple-system, BlinkMacSystemFont, sans-serif;
126
+ box-shadow: 0 2px 8px rgba(108, 92, 231, 0.4);
127
+ letter-spacing: 0.3px;
128
+ `;
129
+ const BANNER_HTML = `
130
+ <div id="astro-claw-banner" style="${BANNER_CSS}">
131
+ <span style="font-size: 16px;">🤖</span>
132
+ <span>Astro Claw is driving this browser</span>
133
+ <span style="opacity: 0.6; font-weight: 400; font-size: 11px; margin-left: 4px;">— do not close</span>
134
+ </div>
135
+ `;
136
+ const BODY_PADDING = `
137
+ if (!document.body.dataset.astroClaw) {
138
+ document.body.style.paddingTop = (parseFloat(getComputedStyle(document.body).paddingTop) + 36) + 'px';
139
+ document.body.dataset.astroClaw = '1';
140
+ }
141
+ `;
142
+ const injectBanner = async (p) => {
143
+ try {
144
+ await p.evaluate((html, bodyJs) => {
145
+ if (!document.getElementById('astro-claw-banner')) {
146
+ document.body.insertAdjacentHTML('beforeend', html);
147
+ eval(bodyJs);
148
+ }
149
+ }, BANNER_HTML, BODY_PADDING);
150
+ } catch {}
151
+ };
152
+
153
+ // Inject banner after every navigation and periodically
154
+ page.on('load', () => injectBanner(page));
155
+ page.on('domcontentloaded', () => injectBanner(page));
156
+ page.on('framenavigated', () => setTimeout(() => injectBanner(page), 500));
157
+ const bannerInterval = setInterval(() => injectBanner(page), 2000);
158
+
120
159
  // ── Step 1: Sign in to Slack (single tab, no interruptions) ──
121
160
  console.log(` → Checking Slack login...`);
122
161
  await page.goto("https://api.slack.com/apps", { waitUntil: "networkidle2", timeout: 30000 });
@@ -246,50 +285,41 @@ export default async function selfDrivingSlackSetup() {
246
285
  }
247
286
  }
248
287
 
249
- // Click "Next" (Step 1 Step 2 of the wizard)
250
- await new Promise((r) => setTimeout(r, 1000));
251
- try {
252
- // Try multiple selectors for the primary/next button
253
- const nextBtn = await page.$('button.c-button--primary')
288
+ // Helper: check if we've landed on the app page (creation complete)
289
+ const isOnAppPage = () => /api\.slack\.com\/apps\/[A-Z0-9]+(?:\/|$)/.test(page.url());
290
+
291
+ // Click through the wizard steps Slack may have 2 or 3 steps
292
+ // After each click, check if the app was already created
293
+ console.log(` → Walking through wizard...`);
294
+ for (let step = 0; step < 3; step++) {
295
+ if (isOnAppPage()) break;
296
+
297
+ // Look for the primary action button (Next or Create)
298
+ const btn = await page.$('button.c-button--primary')
254
299
  || await page.$('button[data-qa="next"]')
255
300
  || await page.$('button[type="submit"]');
256
- if (nextBtn) {
257
- await nextBtn.click();
258
- await new Promise((r) => setTimeout(r, 2000));
259
- }
260
- } catch {}
261
301
 
262
- // Step 2→3: manifest review — click "Next" again
263
- console.log(` → Reviewing manifest...`);
264
- try {
265
- const nextBtn2 = await page.$('button.c-button--primary');
266
- if (nextBtn2) {
267
- await nextBtn2.click();
268
- await new Promise((r) => setTimeout(r, 2000));
269
- }
270
- } catch {}
271
-
272
- // Step 3: Click "Create"
273
- console.log(` → Creating app...`);
274
- try {
275
- // Look for the Create button (usually the primary button on step 3)
276
- const buttons = await page.$$('button');
277
- for (const btn of buttons) {
278
- const text = await page.evaluate((el) => el.textContent?.trim(), btn);
279
- if (text === "Create" || text === "Create App") {
280
- await btn.click();
281
- await new Promise((r) => setTimeout(r, 3000));
282
- break;
302
+ if (btn) {
303
+ const btnText = await page.evaluate((el) => el.textContent?.trim(), btn);
304
+ if (btnText === "Create" || btnText === "Create App") {
305
+ console.log(` → Creating app...`);
306
+ } else {
307
+ console.log(` → ${btnText || "Next"}...`);
283
308
  }
309
+ await btn.click();
310
+ await new Promise((r) => setTimeout(r, 3000));
311
+ } else {
312
+ break;
284
313
  }
285
- } catch {}
314
+ }
286
315
 
287
- // After creation, we should be on the app's Basic Information page
288
- // URL pattern: https://api.slack.com/apps/APPID
289
- await page.waitForFunction(
290
- () => /api\.slack\.com\/apps\/[A-Z0-9]+/.test(window.location.href),
291
- { timeout: 15000 }
292
- ).catch(() => {});
316
+ // Wait for redirect to app page
317
+ if (!isOnAppPage()) {
318
+ await page.waitForFunction(
319
+ () => /api\.slack\.com\/apps\/[A-Z0-9]+/.test(window.location.href),
320
+ { timeout: 30000 }
321
+ ).catch(() => {});
322
+ }
293
323
 
294
324
  const appUrl = page.url();
295
325
  const appIdMatch = appUrl.match(/apps\/([A-Z0-9]+)/);
@@ -518,6 +548,7 @@ export default async function selfDrivingSlackSetup() {
518
548
  }
519
549
 
520
550
  // ── Clean up ──
551
+ clearInterval(bannerInterval);
521
552
  await browser.close();
522
553
 
523
554
  // Return whatever we captured
@@ -533,6 +564,7 @@ export default async function selfDrivingSlackSetup() {
533
564
  return result;
534
565
  } catch (err) {
535
566
  console.log(` ${WARN} Browser automation error: ${err.message}`);
567
+ clearInterval(bannerInterval);
536
568
  if (browser) await browser.close().catch(() => {});
537
569
  return null;
538
570
  }