instar 0.24.13 → 0.24.14
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/.claude/skills/setup-wizard/skill.md +281 -5
- package/dashboard/index.html +341 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +188 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/slack-cli.d.ts +16 -0
- package/dist/commands/slack-cli.d.ts.map +1 -0
- package/dist/commands/slack-cli.js +198 -0
- package/dist/commands/slack-cli.js.map +1 -0
- package/dist/core/AgentRegistry.d.ts.map +1 -1
- package/dist/core/AgentRegistry.js +24 -6
- package/dist/core/AgentRegistry.js.map +1 -1
- package/dist/core/SleepWakeDetector.d.ts +11 -0
- package/dist/core/SleepWakeDetector.d.ts.map +1 -1
- package/dist/core/SleepWakeDetector.js +16 -1
- package/dist/core/SleepWakeDetector.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts +13 -0
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +129 -0
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/messaging/SessionSummarySentinel.js +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +1 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +4 -1
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/slack/ChannelManager.d.ts +36 -0
- package/dist/messaging/slack/ChannelManager.d.ts.map +1 -0
- package/dist/messaging/slack/ChannelManager.js +100 -0
- package/dist/messaging/slack/ChannelManager.js.map +1 -0
- package/dist/messaging/slack/FileHandler.d.ts +30 -0
- package/dist/messaging/slack/FileHandler.d.ts.map +1 -0
- package/dist/messaging/slack/FileHandler.js +87 -0
- package/dist/messaging/slack/FileHandler.js.map +1 -0
- package/dist/messaging/slack/RingBuffer.d.ts +22 -0
- package/dist/messaging/slack/RingBuffer.d.ts.map +1 -0
- package/dist/messaging/slack/RingBuffer.js +48 -0
- package/dist/messaging/slack/RingBuffer.js.map +1 -0
- package/dist/messaging/slack/SlackAdapter.d.ts +136 -0
- package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -0
- package/dist/messaging/slack/SlackAdapter.js +572 -0
- package/dist/messaging/slack/SlackAdapter.js.map +1 -0
- package/dist/messaging/slack/SlackApiClient.d.ts +51 -0
- package/dist/messaging/slack/SlackApiClient.d.ts.map +1 -0
- package/dist/messaging/slack/SlackApiClient.js +94 -0
- package/dist/messaging/slack/SlackApiClient.js.map +1 -0
- package/dist/messaging/slack/SocketModeClient.d.ts +44 -0
- package/dist/messaging/slack/SocketModeClient.d.ts.map +1 -0
- package/dist/messaging/slack/SocketModeClient.js +209 -0
- package/dist/messaging/slack/SocketModeClient.js.map +1 -0
- package/dist/messaging/slack/index.d.ts +12 -0
- package/dist/messaging/slack/index.d.ts.map +1 -0
- package/dist/messaging/slack/index.js +15 -0
- package/dist/messaging/slack/index.js.map +1 -0
- package/dist/messaging/slack/sanitize.d.ts +39 -0
- package/dist/messaging/slack/sanitize.d.ts.map +1 -0
- package/dist/messaging/slack/sanitize.js +71 -0
- package/dist/messaging/slack/sanitize.js.map +1 -0
- package/dist/messaging/slack/types.d.ts +155 -0
- package/dist/messaging/slack/types.d.ts.map +1 -0
- package/dist/messaging/slack/types.js +54 -0
- package/dist/messaging/slack/types.js.map +1 -0
- package/dist/monitoring/PresenceProxy.d.ts +157 -0
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -0
- package/dist/monitoring/PresenceProxy.js +891 -0
- package/dist/monitoring/PresenceProxy.js.map +1 -0
- package/dist/monitoring/SessionWatchdog.d.ts.map +1 -1
- package/dist/monitoring/SessionWatchdog.js +2 -0
- package/dist/monitoring/SessionWatchdog.js.map +1 -1
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +49 -47
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +1 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +213 -4
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +94 -78
- package/src/templates/hooks/slack-channel-context.sh +98 -0
- package/src/templates/scripts/slack-reply.sh +64 -0
- package/upgrades/0.24.11.md +23 -0
- package/upgrades/0.24.14.md +26 -0
- package/upgrades/0.24.6.md +20 -0
- package/upgrades/0.24.7.md +24 -0
- package/upgrades/0.24.8.md +19 -0
- package/upgrades/0.24.9.md +19 -0
- package/upgrades/NEXT.md +35 -0
- /package/.claude/skills/secret-setup/{skill.md → SKILL.md} +0 -0
|
@@ -511,9 +511,9 @@ This handles directory creation, registry entry, port allocation, and gitignore
|
|
|
511
511
|
|
|
512
512
|
Regardless of project or personal agent, **a messaging platform is how you talk to your agent**. This should be clear from the very first message. Don't present it as an optional add-on — it's the destination of this entire setup.
|
|
513
513
|
|
|
514
|
-
The terminal session is the on-ramp. Messaging (Telegram or WhatsApp) is where the agent experience lives.
|
|
514
|
+
The terminal session is the on-ramp. Messaging (Telegram, Slack, or WhatsApp) is where the agent experience lives.
|
|
515
515
|
|
|
516
|
-
**Telegram is recommended** for its topic threads, bot API, and forum-style organization — but WhatsApp
|
|
516
|
+
**Telegram is recommended** for its topic threads, bot API, and forum-style organization — but Slack and WhatsApp are fully supported alternatives for users who prefer them or already live there.
|
|
517
517
|
|
|
518
518
|
## Phase 2: Identity Bootstrap — The Birth Conversation
|
|
519
519
|
|
|
@@ -788,7 +788,8 @@ Frame messaging as the core of the experience, then let the user choose their pl
|
|
|
788
788
|
> This is how you'll actually talk to your agent day-to-day. Not the terminal — just messaging on your phone or desktop.
|
|
789
789
|
>
|
|
790
790
|
> 1. **Telegram** (recommended) — Topic threads for organized conversations, powerful bot API, forum-style groups. Best for power users who want structured channels.
|
|
791
|
-
> 2. **
|
|
791
|
+
> 2. **Slack** — Your agent lives in Slack alongside your team. Channels, threads, reactions, Block Kit interactions. Great for professional workflows.
|
|
792
|
+
> 3. **WhatsApp** — Talk to your agent from the messaging app you already use. Simple, familiar, works everywhere.
|
|
792
793
|
>
|
|
793
794
|
> Which do you prefer? (You can always add the other one later.)
|
|
794
795
|
|
|
@@ -796,12 +797,16 @@ Frame messaging as the core of the experience, then let the user choose their pl
|
|
|
796
797
|
|
|
797
798
|
> "Without a messaging platform, you'll only be able to talk to [agent name] by opening a terminal and running `instar chat`. No mobile access, no proactive messages, no organized threads. Most of what makes an Instar agent useful requires messaging."
|
|
798
799
|
>
|
|
799
|
-
> "You can set it up later with `instar telegram setup` or `instar whatsapp connect`."
|
|
800
|
+
> "You can set it up later with `instar telegram setup`, `instar add slack`, or `instar whatsapp connect`."
|
|
800
801
|
|
|
801
802
|
### If User Chooses Telegram
|
|
802
803
|
|
|
803
804
|
Proceed with the Telegram setup flow below (Step 3b onward).
|
|
804
805
|
|
|
806
|
+
### If User Chooses Slack
|
|
807
|
+
|
|
808
|
+
Jump to **Phase 4h: Slack Setup**. Slack is a first-class option — treat it with the same energy and completeness as Telegram setup.
|
|
809
|
+
|
|
805
810
|
### If User Chooses WhatsApp
|
|
806
811
|
|
|
807
812
|
Jump to **Phase 4g: WhatsApp Setup**. WhatsApp is a first-class option — treat it with the same energy and completeness as Telegram setup.
|
|
@@ -1520,7 +1525,278 @@ If both Telegram and WhatsApp are configured, mention:
|
|
|
1520
1525
|
|
|
1521
1526
|
No additional config needed — CrossPlatformAlerts wires automatically in `server.ts` when both adapters are present.
|
|
1522
1527
|
|
|
1523
|
-
### 4h.
|
|
1528
|
+
### 4h. Slack Setup
|
|
1529
|
+
|
|
1530
|
+
Slack is a **first-class messaging option**. The user may arrive here either:
|
|
1531
|
+
- **As their primary choice** from Phase 3 (chose Slack over Telegram/WhatsApp)
|
|
1532
|
+
- **As an additional channel** after Telegram or WhatsApp is already configured
|
|
1533
|
+
|
|
1534
|
+
**If arriving as primary choice from Phase 3**, skip the "want to add" prompt — they already chose this. Go straight to Step 4h-1.
|
|
1535
|
+
|
|
1536
|
+
**If arriving after Telegram/WhatsApp setup**, present:
|
|
1537
|
+
|
|
1538
|
+
> **Want to add Slack as an additional channel?**
|
|
1539
|
+
>
|
|
1540
|
+
> Slack lets you talk to your agent from Slack — channels, threads, reactions, and interactive buttons. It works alongside your other messaging platforms.
|
|
1541
|
+
>
|
|
1542
|
+
> 1. Yes, set up Slack
|
|
1543
|
+
> 2. Skip for now
|
|
1544
|
+
>
|
|
1545
|
+
> Type a number.
|
|
1546
|
+
|
|
1547
|
+
If they choose to skip, move to Phase 4i.
|
|
1548
|
+
|
|
1549
|
+
#### Step 4h-1: Browser Automation for Slack
|
|
1550
|
+
|
|
1551
|
+
**Use the same browser automation detection from Step 3a.** Playwright preferred, Chrome extension as fallback, manual as last resort.
|
|
1552
|
+
|
|
1553
|
+
Tell the user:
|
|
1554
|
+
|
|
1555
|
+
> I'm going to open a browser to set up Slack automatically. I'll create a workspace, configure an app, and set everything up.
|
|
1556
|
+
>
|
|
1557
|
+
> You'll need to log into Slack in the browser window. Ready?
|
|
1558
|
+
|
|
1559
|
+
Wait for confirmation before proceeding.
|
|
1560
|
+
|
|
1561
|
+
#### Step 4h-2: Navigate to Slack and Handle Login
|
|
1562
|
+
|
|
1563
|
+
Navigate to `https://slack.com/signin`. Take a snapshot.
|
|
1564
|
+
|
|
1565
|
+
**If already logged in** (redirected to a workspace or shows user avatar): Skip to Step 4h-3.
|
|
1566
|
+
|
|
1567
|
+
**If not logged in** (sign-in form visible):
|
|
1568
|
+
> "Please log into your Slack account in the browser window. You can use email, Google, or Apple sign-in. Let me know when you're logged in."
|
|
1569
|
+
|
|
1570
|
+
Wait for user confirmation. Take a snapshot to verify.
|
|
1571
|
+
|
|
1572
|
+
**If no Slack account:**
|
|
1573
|
+
> "You'll need a Slack account. Click 'Create an account' in the browser and follow the steps. Let me know when you're logged in."
|
|
1574
|
+
|
|
1575
|
+
#### Step 4h-3: Workspace Setup
|
|
1576
|
+
|
|
1577
|
+
Ask the user:
|
|
1578
|
+
|
|
1579
|
+
> I recommend creating a dedicated workspace for your agent — it keeps things clean and avoids privacy concerns with colleagues. Would you like me to create a dedicated workspace, or install into an existing one?
|
|
1580
|
+
|
|
1581
|
+
**If creating a new workspace:**
|
|
1582
|
+
|
|
1583
|
+
1. Navigate to `https://slack.com/get-started#/createnew`
|
|
1584
|
+
2. Take snapshot, find email field
|
|
1585
|
+
3. Type user's email (from USER.md or ask)
|
|
1586
|
+
4. Click "Continue"
|
|
1587
|
+
5. **WAIT** — user must enter 6-digit email verification code from their inbox
|
|
1588
|
+
> "Check your email for a 6-digit code from Slack and enter it in the browser."
|
|
1589
|
+
Wait for user confirmation.
|
|
1590
|
+
6. Take snapshot — workspace name field
|
|
1591
|
+
7. Type workspace name: `{agent-name}-agent` (e.g., "echo-agent")
|
|
1592
|
+
8. Click "Next"
|
|
1593
|
+
9. Take snapshot — project/channel name field
|
|
1594
|
+
10. Type "general"
|
|
1595
|
+
11. Click "Next"
|
|
1596
|
+
12. Take snapshot — invite page
|
|
1597
|
+
13. Click "Skip" or skip link
|
|
1598
|
+
14. Wait for workspace to load
|
|
1599
|
+
|
|
1600
|
+
**If using existing workspace:**
|
|
1601
|
+
1. Ask which workspace to use
|
|
1602
|
+
2. Navigate to the workspace URL
|
|
1603
|
+
3. Take snapshot to confirm workspace loaded
|
|
1604
|
+
|
|
1605
|
+
#### Step 4h-4: Create Slack App via Manifest
|
|
1606
|
+
|
|
1607
|
+
Build the app manifest JSON with minimal Phase 1 scopes:
|
|
1608
|
+
|
|
1609
|
+
```json
|
|
1610
|
+
{
|
|
1611
|
+
"display_information": {
|
|
1612
|
+
"name": "{agent-name}",
|
|
1613
|
+
"description": "Instar agent"
|
|
1614
|
+
},
|
|
1615
|
+
"features": {
|
|
1616
|
+
"bot_user": {
|
|
1617
|
+
"display_name": "{agent-name}",
|
|
1618
|
+
"always_online": true
|
|
1619
|
+
}
|
|
1620
|
+
},
|
|
1621
|
+
"oauth_config": {
|
|
1622
|
+
"scopes": {
|
|
1623
|
+
"bot": [
|
|
1624
|
+
"channels:history", "channels:manage", "channels:read",
|
|
1625
|
+
"chat:write", "im:history", "im:read", "im:write",
|
|
1626
|
+
"pins:write", "reactions:read", "reactions:write", "users:read"
|
|
1627
|
+
]
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
"settings": {
|
|
1631
|
+
"event_subscriptions": {
|
|
1632
|
+
"bot_events": [
|
|
1633
|
+
"message.channels", "message.groups", "message.im",
|
|
1634
|
+
"file_shared", "reaction_added", "app_mention"
|
|
1635
|
+
]
|
|
1636
|
+
},
|
|
1637
|
+
"socket_mode_enabled": true,
|
|
1638
|
+
"org_deploy_enabled": false
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
```
|
|
1642
|
+
|
|
1643
|
+
1. URL-encode the manifest JSON
|
|
1644
|
+
2. Navigate to: `https://api.slack.com/apps?new_app=1&manifest_json={ENCODED_JSON}`
|
|
1645
|
+
3. Take snapshot — workspace picker dropdown
|
|
1646
|
+
4. Select the target workspace from dropdown
|
|
1647
|
+
5. Click "Next"
|
|
1648
|
+
6. Take snapshot — manifest review/summary page
|
|
1649
|
+
7. Click "Create" button
|
|
1650
|
+
8. Wait 2-3 seconds for app creation
|
|
1651
|
+
9. Take snapshot — should be on app's Basic Information page
|
|
1652
|
+
10. Extract App ID from the URL (`api.slack.com/apps/A{APP_ID}/...`)
|
|
1653
|
+
|
|
1654
|
+
#### Step 4h-5: Install App to Workspace
|
|
1655
|
+
|
|
1656
|
+
1. Navigate to: `https://api.slack.com/apps/{APP_ID}/install-on-team`
|
|
1657
|
+
2. Take snapshot — "Install to Workspace" button
|
|
1658
|
+
3. Click "Install to Workspace"
|
|
1659
|
+
4. Take snapshot — OAuth authorization page
|
|
1660
|
+
5. Click "Allow"
|
|
1661
|
+
6. Wait for redirect back to app settings
|
|
1662
|
+
7. Take snapshot — OAuth & Permissions page
|
|
1663
|
+
8. **CRITICAL: DO NOT take screenshots/snapshots on this page** — it shows the bot token
|
|
1664
|
+
9. Extract Bot User OAuth Token (`xoxb-...`) from the page using regex. Pattern: `xoxb-\d+-\d+-[A-Za-z0-9]+`
|
|
1665
|
+
10. Store token in memory — do NOT log it
|
|
1666
|
+
|
|
1667
|
+
#### Step 4h-6: Enable Socket Mode & Generate App Token
|
|
1668
|
+
|
|
1669
|
+
1. Navigate to: `https://api.slack.com/apps/{APP_ID}/socket-mode`
|
|
1670
|
+
2. Take snapshot — Socket Mode toggle
|
|
1671
|
+
3. If toggle is OFF, click to enable it
|
|
1672
|
+
4. Navigate to: `https://api.slack.com/apps/{APP_ID}/general`
|
|
1673
|
+
5. Scroll to "App-Level Tokens" section
|
|
1674
|
+
6. Take snapshot — find "Generate Token and Scopes" button
|
|
1675
|
+
7. Click "Generate Token and Scopes"
|
|
1676
|
+
8. Take snapshot — token creation dialog
|
|
1677
|
+
9. Type token name: "socket-mode" in the name field
|
|
1678
|
+
10. Click "Add Scope"
|
|
1679
|
+
11. Select "connections:write" scope
|
|
1680
|
+
12. Click "Generate"
|
|
1681
|
+
13. **CRITICAL: DO NOT take screenshots/snapshots** — token is displayed
|
|
1682
|
+
14. Extract app-level token (`xapp-...`) from the dialog. Pattern: `xapp-\d+-[A-Za-z0-9]+-\d+-[A-Za-z0-9]+`
|
|
1683
|
+
15. Click "Done"
|
|
1684
|
+
|
|
1685
|
+
#### Step 4h-7: Validate Tokens
|
|
1686
|
+
|
|
1687
|
+
Validate both tokens via API (NOT browser):
|
|
1688
|
+
|
|
1689
|
+
```bash
|
|
1690
|
+
# Validate bot token and extract workspace info
|
|
1691
|
+
BOT_RESULT=$(curl -s -X POST https://slack.com/api/auth.test \
|
|
1692
|
+
-H "Authorization: Bearer ${BOT_TOKEN}" \
|
|
1693
|
+
-H "Content-Type: application/json")
|
|
1694
|
+
|
|
1695
|
+
# Expected: {"ok": true, "team_id": "T...", "user_id": "U...", "team": "workspace-name"}
|
|
1696
|
+
|
|
1697
|
+
# Validate app token
|
|
1698
|
+
APP_RESULT=$(curl -s -X POST https://slack.com/api/apps.connections.open \
|
|
1699
|
+
-H "Authorization: Bearer ${APP_TOKEN}" \
|
|
1700
|
+
-H "Content-Type: application/json")
|
|
1701
|
+
|
|
1702
|
+
# Expected: {"ok": true, "url": "wss://..."}
|
|
1703
|
+
```
|
|
1704
|
+
|
|
1705
|
+
If either fails, tell the user and offer to retry the extraction step.
|
|
1706
|
+
|
|
1707
|
+
Extract from `BOT_RESULT`:
|
|
1708
|
+
- `team_id` → `workspaceId`
|
|
1709
|
+
- `team` → `workspaceName`
|
|
1710
|
+
- `user_id` → add to `authorizedUserIds` (this is the installing user)
|
|
1711
|
+
|
|
1712
|
+
#### Step 4h-8: Create System Channels
|
|
1713
|
+
|
|
1714
|
+
```bash
|
|
1715
|
+
# Create lifeline channel
|
|
1716
|
+
LIFELINE=$(curl -s -X POST https://slack.com/api/conversations.create \
|
|
1717
|
+
-H "Authorization: Bearer ${BOT_TOKEN}" \
|
|
1718
|
+
-H "Content-Type: application/json" \
|
|
1719
|
+
-d '{"name": "{agent}-sys-lifeline"}')
|
|
1720
|
+
|
|
1721
|
+
# Create dashboard channel
|
|
1722
|
+
DASHBOARD=$(curl -s -X POST https://slack.com/api/conversations.create \
|
|
1723
|
+
-H "Authorization: Bearer ${BOT_TOKEN}" \
|
|
1724
|
+
-H "Content-Type: application/json" \
|
|
1725
|
+
-d '{"name": "{agent}-sys-dashboard"}')
|
|
1726
|
+
|
|
1727
|
+
# Pin a welcome message in lifeline
|
|
1728
|
+
curl -s -X POST https://slack.com/api/chat.postMessage \
|
|
1729
|
+
-H "Authorization: Bearer ${BOT_TOKEN}" \
|
|
1730
|
+
-H "Content-Type: application/json" \
|
|
1731
|
+
-d '{"channel": "LIFELINE_ID", "text": "Lifeline channel active. This is where I send critical system messages."}'
|
|
1732
|
+
```
|
|
1733
|
+
|
|
1734
|
+
#### Step 4h-9: Write Configuration
|
|
1735
|
+
|
|
1736
|
+
Write Slack config to `.instar/config.json`:
|
|
1737
|
+
|
|
1738
|
+
```javascript
|
|
1739
|
+
node -e "
|
|
1740
|
+
const fs = require('fs');
|
|
1741
|
+
const p = '<project_dir>/.instar/config.json';
|
|
1742
|
+
const c = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
1743
|
+
c.messaging = c.messaging || [];
|
|
1744
|
+
// Remove existing slack config if any
|
|
1745
|
+
c.messaging = c.messaging.filter(m => m.type !== 'slack');
|
|
1746
|
+
c.messaging.push({
|
|
1747
|
+
type: 'slack',
|
|
1748
|
+
enabled: true,
|
|
1749
|
+
config: {
|
|
1750
|
+
botToken: '${BOT_TOKEN}',
|
|
1751
|
+
appToken: '${APP_TOKEN}',
|
|
1752
|
+
workspaceId: '${WORKSPACE_ID}',
|
|
1753
|
+
workspaceName: '${WORKSPACE_NAME}',
|
|
1754
|
+
authorizedUserIds: ['${USER_ID}'],
|
|
1755
|
+
stallTimeoutMinutes: 5,
|
|
1756
|
+
logRetentionDays: 90,
|
|
1757
|
+
lifelineChannelId: '${LIFELINE_CHANNEL_ID}',
|
|
1758
|
+
dashboardChannelId: '${DASHBOARD_CHANNEL_ID}'
|
|
1759
|
+
}
|
|
1760
|
+
});
|
|
1761
|
+
fs.writeFileSync(p, JSON.stringify(c, null, 2));
|
|
1762
|
+
fs.chmodSync(p, 0o600);
|
|
1763
|
+
"
|
|
1764
|
+
```
|
|
1765
|
+
|
|
1766
|
+
#### Step 4h-10: Confirm Success and Close Browser
|
|
1767
|
+
|
|
1768
|
+
Close the browser (Playwright: `browser_close()`).
|
|
1769
|
+
|
|
1770
|
+
Tell the user:
|
|
1771
|
+
|
|
1772
|
+
> Slack is set up! Your workspace '{workspaceName}' is ready.
|
|
1773
|
+
> I've created your system channels and configured everything.
|
|
1774
|
+
>
|
|
1775
|
+
> Important: Your bot tokens provide full access to your Slack workspace — treat them like passwords. They don't expire, so if you suspect compromise, revoke them at api.slack.com/apps.
|
|
1776
|
+
>
|
|
1777
|
+
> Would you like me to store your tokens in Bitwarden for extra security? (recommended)
|
|
1778
|
+
|
|
1779
|
+
If they accept Bitwarden, trigger the `secret-setup` skill.
|
|
1780
|
+
|
|
1781
|
+
#### Slack Manual Fallback
|
|
1782
|
+
|
|
1783
|
+
**Only use this if NO browser automation tools are available.** If automation failed partway, tell the user exactly what succeeded.
|
|
1784
|
+
|
|
1785
|
+
Walk the user through:
|
|
1786
|
+
|
|
1787
|
+
1. Go to `https://slack.com/get-started#/createnew` and create a workspace (or use existing)
|
|
1788
|
+
2. Go to `https://api.slack.com/apps?new_app=1` → click "From a manifest"
|
|
1789
|
+
3. Select your workspace
|
|
1790
|
+
4. Paste this manifest: [provide the JSON from Step 4h-4]
|
|
1791
|
+
5. Click Create, then Install to Workspace, then Allow
|
|
1792
|
+
6. Go to Basic Information → App-Level Tokens → Generate Token and Scopes
|
|
1793
|
+
7. Name: "socket-mode", Scope: "connections:write", click Generate
|
|
1794
|
+
8. Copy both tokens (bot token from OAuth page, app token from Basic Info)
|
|
1795
|
+
9. Run: `instar add slack` and paste the tokens when prompted
|
|
1796
|
+
|
|
1797
|
+
Even in manual mode, system channel creation (Step 4h-8) and config writing (Step 4h-9) are done by the wizard, not the user.
|
|
1798
|
+
|
|
1799
|
+
### 4i. Agent Network
|
|
1524
1800
|
|
|
1525
1801
|
Your agent can join a secure network to communicate with other AI agents. Present this as an optional but recommended step:
|
|
1526
1802
|
|
package/dashboard/index.html
CHANGED
|
@@ -1916,6 +1916,212 @@
|
|
|
1916
1916
|
.spark.s-skipped { background: #333; }
|
|
1917
1917
|
|
|
1918
1918
|
/* ── Discovery Tab ──────────────────────────────────────── */
|
|
1919
|
+
/* Systems Tab */
|
|
1920
|
+
.systems-container {
|
|
1921
|
+
grid-column: 1 / -1;
|
|
1922
|
+
overflow-y: auto;
|
|
1923
|
+
background: var(--bg);
|
|
1924
|
+
padding: 20px;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
.systems-main {
|
|
1928
|
+
max-width: 900px;
|
|
1929
|
+
margin: 0 auto;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
.systems-header {
|
|
1933
|
+
display: flex;
|
|
1934
|
+
align-items: center;
|
|
1935
|
+
justify-content: space-between;
|
|
1936
|
+
margin-bottom: 20px;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
.systems-header h2 {
|
|
1940
|
+
font-size: 16px;
|
|
1941
|
+
font-weight: 600;
|
|
1942
|
+
color: var(--text-bright);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
.systems-refresh {
|
|
1946
|
+
font-size: 11px;
|
|
1947
|
+
padding: 4px 12px;
|
|
1948
|
+
border-radius: 4px;
|
|
1949
|
+
border: 1px solid var(--border);
|
|
1950
|
+
background: transparent;
|
|
1951
|
+
color: var(--text-dim);
|
|
1952
|
+
cursor: pointer;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
.systems-refresh:hover {
|
|
1956
|
+
border-color: var(--text-dim);
|
|
1957
|
+
color: var(--text);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
.systems-summary {
|
|
1961
|
+
display: flex;
|
|
1962
|
+
gap: 16px;
|
|
1963
|
+
margin-bottom: 24px;
|
|
1964
|
+
flex-wrap: wrap;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
.systems-summary-card {
|
|
1968
|
+
flex: 1;
|
|
1969
|
+
min-width: 140px;
|
|
1970
|
+
padding: 14px 18px;
|
|
1971
|
+
background: var(--bg-panel);
|
|
1972
|
+
border: 1px solid var(--border);
|
|
1973
|
+
border-radius: 8px;
|
|
1974
|
+
text-align: center;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
.systems-summary-card .summary-value {
|
|
1978
|
+
font-size: 22px;
|
|
1979
|
+
font-weight: 700;
|
|
1980
|
+
color: var(--text-bright);
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
.systems-summary-card .summary-label {
|
|
1984
|
+
font-size: 11px;
|
|
1985
|
+
color: var(--text-dim);
|
|
1986
|
+
margin-top: 4px;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
.systems-section {
|
|
1990
|
+
margin-bottom: 24px;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
.systems-section h3 {
|
|
1994
|
+
font-size: 13px;
|
|
1995
|
+
font-weight: 600;
|
|
1996
|
+
color: var(--text-bright);
|
|
1997
|
+
margin-bottom: 12px;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
.systems-category {
|
|
2001
|
+
background: var(--bg-panel);
|
|
2002
|
+
border: 1px solid var(--border);
|
|
2003
|
+
border-radius: 8px;
|
|
2004
|
+
margin-bottom: 8px;
|
|
2005
|
+
overflow: hidden;
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
.systems-category-header {
|
|
2009
|
+
display: flex;
|
|
2010
|
+
align-items: center;
|
|
2011
|
+
gap: 10px;
|
|
2012
|
+
padding: 12px 16px;
|
|
2013
|
+
cursor: pointer;
|
|
2014
|
+
user-select: none;
|
|
2015
|
+
transition: background 0.15s;
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
.systems-category-header:hover {
|
|
2019
|
+
background: var(--bg-hover);
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
.systems-category-arrow {
|
|
2023
|
+
font-size: 10px;
|
|
2024
|
+
color: var(--text-dim);
|
|
2025
|
+
transition: transform 0.2s;
|
|
2026
|
+
width: 12px;
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
.systems-category.expanded .systems-category-arrow {
|
|
2030
|
+
transform: rotate(90deg);
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
.systems-category-dot {
|
|
2034
|
+
width: 8px;
|
|
2035
|
+
height: 8px;
|
|
2036
|
+
border-radius: 50%;
|
|
2037
|
+
flex-shrink: 0;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
.systems-category-name {
|
|
2041
|
+
font-size: 13px;
|
|
2042
|
+
font-weight: 500;
|
|
2043
|
+
color: var(--text-bright);
|
|
2044
|
+
flex: 1;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
.systems-category-count {
|
|
2048
|
+
font-size: 11px;
|
|
2049
|
+
color: var(--text-dim);
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
.systems-category-body {
|
|
2053
|
+
display: none;
|
|
2054
|
+
padding: 0 16px 12px;
|
|
2055
|
+
gap: 8px;
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
.systems-category.expanded .systems-category-body {
|
|
2059
|
+
display: flex;
|
|
2060
|
+
flex-wrap: wrap;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
.systems-process-card {
|
|
2064
|
+
display: flex;
|
|
2065
|
+
align-items: center;
|
|
2066
|
+
gap: 8px;
|
|
2067
|
+
padding: 8px 12px;
|
|
2068
|
+
background: var(--bg);
|
|
2069
|
+
border: 1px solid var(--border);
|
|
2070
|
+
border-radius: 6px;
|
|
2071
|
+
min-width: 200px;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
.systems-process-dot {
|
|
2075
|
+
width: 6px;
|
|
2076
|
+
height: 6px;
|
|
2077
|
+
border-radius: 50%;
|
|
2078
|
+
flex-shrink: 0;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
.systems-process-name {
|
|
2082
|
+
font-size: 12px;
|
|
2083
|
+
color: var(--text);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
.systems-process-status {
|
|
2087
|
+
font-size: 10px;
|
|
2088
|
+
color: var(--text-dim);
|
|
2089
|
+
margin-left: auto;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
.systems-events {
|
|
2093
|
+
background: var(--bg-panel);
|
|
2094
|
+
border: 1px solid var(--border);
|
|
2095
|
+
border-radius: 8px;
|
|
2096
|
+
max-height: 300px;
|
|
2097
|
+
overflow-y: auto;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
.systems-event-row {
|
|
2101
|
+
display: flex;
|
|
2102
|
+
align-items: center;
|
|
2103
|
+
gap: 10px;
|
|
2104
|
+
padding: 8px 14px;
|
|
2105
|
+
border-bottom: 1px solid var(--border);
|
|
2106
|
+
font-size: 12px;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
.systems-event-row:last-child {
|
|
2110
|
+
border-bottom: none;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
.systems-event-time {
|
|
2114
|
+
color: var(--text-dim);
|
|
2115
|
+
white-space: nowrap;
|
|
2116
|
+
font-size: 11px;
|
|
2117
|
+
min-width: 60px;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
.systems-event-text {
|
|
2121
|
+
color: var(--text);
|
|
2122
|
+
flex: 1;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
1919
2125
|
.discovery-container {
|
|
1920
2126
|
grid-column: 1 / -1;
|
|
1921
2127
|
overflow-y: auto;
|
|
@@ -2433,6 +2639,7 @@
|
|
|
2433
2639
|
<button class="tab" data-tab="dropzone" onclick="switchTab('dropzone')">Drop Zone</button>
|
|
2434
2640
|
<button class="tab" data-tab="jobs" onclick="switchTab('jobs')">Jobs <span class="tab-count" id="tabJobCount">0</span></button>
|
|
2435
2641
|
<button class="tab" data-tab="discovery" onclick="switchTab('discovery')">Discovery</button>
|
|
2642
|
+
<button class="tab" data-tab="systems" onclick="switchTab('systems')">Systems</button>
|
|
2436
2643
|
</nav>
|
|
2437
2644
|
</div>
|
|
2438
2645
|
<div class="vital-signs" id="vitalSigns">
|
|
@@ -2653,6 +2860,26 @@
|
|
|
2653
2860
|
</div>
|
|
2654
2861
|
</div>
|
|
2655
2862
|
|
|
2863
|
+
<!-- Systems Tab -->
|
|
2864
|
+
<div class="systems-container" id="systemsTab" style="display:none">
|
|
2865
|
+
<div class="systems-main">
|
|
2866
|
+
<div class="systems-header">
|
|
2867
|
+
<h2>Systems Status</h2>
|
|
2868
|
+
<button class="systems-refresh" onclick="loadSystems()">Refresh</button>
|
|
2869
|
+
</div>
|
|
2870
|
+
<div class="systems-summary" id="systemsSummary">
|
|
2871
|
+
<div style="padding:20px;color:var(--text-dim);text-align:center">Loading...</div>
|
|
2872
|
+
</div>
|
|
2873
|
+
<div class="systems-categories" id="systemsCategories"></div>
|
|
2874
|
+
<div class="systems-section">
|
|
2875
|
+
<h3>Recent Degradation Events</h3>
|
|
2876
|
+
<div class="systems-events" id="systemsEvents">
|
|
2877
|
+
<div style="padding:12px;color:var(--text-dim);text-align:center">No events</div>
|
|
2878
|
+
</div>
|
|
2879
|
+
</div>
|
|
2880
|
+
</div>
|
|
2881
|
+
</div>
|
|
2882
|
+
|
|
2656
2883
|
<!-- Discovery Tab -->
|
|
2657
2884
|
<div class="discovery-container" id="discoveryTab" style="display:none">
|
|
2658
2885
|
<div class="discovery-main">
|
|
@@ -3614,6 +3841,12 @@
|
|
|
3614
3841
|
display: ['flex'],
|
|
3615
3842
|
onActivate: () => { if (!discoveryLoaded) loadDiscovery(); },
|
|
3616
3843
|
},
|
|
3844
|
+
{
|
|
3845
|
+
id: 'systems',
|
|
3846
|
+
panels: ['systemsTab'],
|
|
3847
|
+
display: ['flex'],
|
|
3848
|
+
onActivate: () => { loadSystems(); },
|
|
3849
|
+
},
|
|
3617
3850
|
];
|
|
3618
3851
|
|
|
3619
3852
|
function switchTab(tabName) {
|
|
@@ -5235,6 +5468,114 @@
|
|
|
5235
5468
|
}).join('');
|
|
5236
5469
|
}
|
|
5237
5470
|
|
|
5471
|
+
// ── Systems Tab ──────────────────────────────────────────────
|
|
5472
|
+
let systemsData = null;
|
|
5473
|
+
|
|
5474
|
+
async function loadSystems() {
|
|
5475
|
+
try {
|
|
5476
|
+
systemsData = await apiFetch('/systems/status');
|
|
5477
|
+
renderSystems();
|
|
5478
|
+
} catch (e) {
|
|
5479
|
+
document.getElementById('systemsSummary').innerHTML =
|
|
5480
|
+
'<div style="padding:20px;color:var(--red);text-align:center">Failed to load systems status</div>';
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
function renderSystems() {
|
|
5485
|
+
if (!systemsData) return;
|
|
5486
|
+
const { uptime, categories, recentEvents } = systemsData;
|
|
5487
|
+
|
|
5488
|
+
// Summary
|
|
5489
|
+
let totalProcesses = 0;
|
|
5490
|
+
let healthyProcesses = 0;
|
|
5491
|
+
let errorProcesses = 0;
|
|
5492
|
+
for (const cat of categories) {
|
|
5493
|
+
for (const p of cat.processes) {
|
|
5494
|
+
totalProcesses++;
|
|
5495
|
+
if (p.status === 'running') healthyProcesses++;
|
|
5496
|
+
if (p.status === 'error') errorProcesses++;
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
const uptimeStr = formatUptimeClient(uptime);
|
|
5500
|
+
|
|
5501
|
+
document.getElementById('systemsSummary').innerHTML = `
|
|
5502
|
+
<div class="systems-summary-card">
|
|
5503
|
+
<div class="summary-value" style="color:var(--accent)">${healthyProcesses}/${totalProcesses}</div>
|
|
5504
|
+
<div class="summary-label">Processes Healthy</div>
|
|
5505
|
+
</div>
|
|
5506
|
+
<div class="systems-summary-card">
|
|
5507
|
+
<div class="summary-value" style="color:${errorProcesses > 0 ? 'var(--red)' : 'var(--text-dim)'}">${errorProcesses}</div>
|
|
5508
|
+
<div class="summary-label">Errors</div>
|
|
5509
|
+
</div>
|
|
5510
|
+
<div class="systems-summary-card">
|
|
5511
|
+
<div class="summary-value">${esc(uptimeStr)}</div>
|
|
5512
|
+
<div class="summary-label">Uptime</div>
|
|
5513
|
+
</div>
|
|
5514
|
+
<div class="systems-summary-card">
|
|
5515
|
+
<div class="summary-value">${recentEvents.length}</div>
|
|
5516
|
+
<div class="summary-label">Recent Events</div>
|
|
5517
|
+
</div>`;
|
|
5518
|
+
|
|
5519
|
+
// Categories
|
|
5520
|
+
const catEl = document.getElementById('systemsCategories');
|
|
5521
|
+
catEl.innerHTML = categories.map(cat => {
|
|
5522
|
+
const running = cat.processes.filter(p => p.status === 'running').length;
|
|
5523
|
+
const hasError = cat.processes.some(p => p.status === 'error');
|
|
5524
|
+
const hasDisabled = cat.processes.some(p => p.status === 'not tracked' || p.status === 'disabled');
|
|
5525
|
+
const dotColor = hasError ? 'var(--red)' : (running === 0 ? 'var(--text-dim)' : (hasDisabled ? 'var(--orange)' : 'var(--accent)'));
|
|
5526
|
+
|
|
5527
|
+
const processCards = cat.processes.map(p => {
|
|
5528
|
+
const pDotColor = p.status === 'running' ? 'var(--accent)' :
|
|
5529
|
+
p.status === 'error' ? 'var(--red)' :
|
|
5530
|
+
p.status === 'disabled' ? 'var(--orange)' : 'var(--text-dim)';
|
|
5531
|
+
return `<div class="systems-process-card">
|
|
5532
|
+
<span class="systems-process-dot" style="background:${pDotColor}"></span>
|
|
5533
|
+
<span class="systems-process-name">${esc(p.name)}</span>
|
|
5534
|
+
<span class="systems-process-status">${esc(p.status)}</span>
|
|
5535
|
+
</div>`;
|
|
5536
|
+
}).join('');
|
|
5537
|
+
|
|
5538
|
+
return `<div class="systems-category" data-cat="${esc(cat.id)}">
|
|
5539
|
+
<div class="systems-category-header" onclick="toggleSystemsCategory(this)">
|
|
5540
|
+
<span class="systems-category-arrow">▶</span>
|
|
5541
|
+
<span class="systems-category-dot" style="background:${dotColor}"></span>
|
|
5542
|
+
<span class="systems-category-name">${esc(cat.name)}</span>
|
|
5543
|
+
<span class="systems-category-count">${running}/${cat.processes.length} active</span>
|
|
5544
|
+
</div>
|
|
5545
|
+
<div class="systems-category-body">${processCards}</div>
|
|
5546
|
+
</div>`;
|
|
5547
|
+
}).join('');
|
|
5548
|
+
|
|
5549
|
+
// Events
|
|
5550
|
+
const eventsEl = document.getElementById('systemsEvents');
|
|
5551
|
+
if (recentEvents.length === 0) {
|
|
5552
|
+
eventsEl.innerHTML = '<div style="padding:12px;color:var(--text-dim);text-align:center">No degradation events</div>';
|
|
5553
|
+
} else {
|
|
5554
|
+
eventsEl.innerHTML = recentEvents.map(e => {
|
|
5555
|
+
const time = e.timestamp ? new Date(e.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '';
|
|
5556
|
+
return `<div class="systems-event-row">
|
|
5557
|
+
<span class="systems-event-time">${esc(time)}</span>
|
|
5558
|
+
<span class="systems-event-text">${esc(e.narrative || e.subsystem || 'Unknown event')}</span>
|
|
5559
|
+
</div>`;
|
|
5560
|
+
}).join('');
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
|
|
5564
|
+
function toggleSystemsCategory(headerEl) {
|
|
5565
|
+
const cat = headerEl.closest('.systems-category');
|
|
5566
|
+
cat.classList.toggle('expanded');
|
|
5567
|
+
}
|
|
5568
|
+
|
|
5569
|
+
function formatUptimeClient(ms) {
|
|
5570
|
+
const s = Math.floor(ms / 1000);
|
|
5571
|
+
const d = Math.floor(s / 86400);
|
|
5572
|
+
const h = Math.floor((s % 86400) / 3600);
|
|
5573
|
+
const m = Math.floor((s % 3600) / 60);
|
|
5574
|
+
if (d > 0) return d + 'd ' + h + 'h';
|
|
5575
|
+
if (h > 0) return h + 'h ' + m + 'm';
|
|
5576
|
+
return m + 'm';
|
|
5577
|
+
}
|
|
5578
|
+
|
|
5238
5579
|
// Handle tab visibility — close SSE when tab is backgrounded
|
|
5239
5580
|
document.addEventListener('visibilitychange', () => {
|
|
5240
5581
|
if (document.hidden) {
|