instar 0.26.3 → 0.26.5

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.
Files changed (102) hide show
  1. package/README.md +61 -7
  2. package/dashboard/index.html +55 -0
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +2 -1
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/server.d.ts.map +1 -1
  7. package/dist/commands/server.js +188 -3
  8. package/dist/commands/server.js.map +1 -1
  9. package/dist/commands/slack-cli.d.ts.map +1 -1
  10. package/dist/commands/slack-cli.js +6 -0
  11. package/dist/commands/slack-cli.js.map +1 -1
  12. package/dist/core/CapabilityMapper.d.ts.map +1 -1
  13. package/dist/core/CapabilityMapper.js +2 -0
  14. package/dist/core/CapabilityMapper.js.map +1 -1
  15. package/dist/core/EvolutionManager.d.ts +17 -0
  16. package/dist/core/EvolutionManager.d.ts.map +1 -1
  17. package/dist/core/EvolutionManager.js +64 -0
  18. package/dist/core/EvolutionManager.js.map +1 -1
  19. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  20. package/dist/core/PostUpdateMigrator.js +37 -0
  21. package/dist/core/PostUpdateMigrator.js.map +1 -1
  22. package/dist/core/SessionManager.d.ts +31 -0
  23. package/dist/core/SessionManager.d.ts.map +1 -1
  24. package/dist/core/SessionManager.js +169 -16
  25. package/dist/core/SessionManager.js.map +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/messaging/imessage/IMessageAdapter.d.ts +128 -0
  31. package/dist/messaging/imessage/IMessageAdapter.d.ts.map +1 -0
  32. package/dist/messaging/imessage/IMessageAdapter.js +541 -0
  33. package/dist/messaging/imessage/IMessageAdapter.js.map +1 -0
  34. package/dist/messaging/imessage/NativeBackend.d.ts +82 -0
  35. package/dist/messaging/imessage/NativeBackend.d.ts.map +1 -0
  36. package/dist/messaging/imessage/NativeBackend.js +353 -0
  37. package/dist/messaging/imessage/NativeBackend.js.map +1 -0
  38. package/dist/messaging/imessage/OutboundAuditLog.d.ts +49 -0
  39. package/dist/messaging/imessage/OutboundAuditLog.d.ts.map +1 -0
  40. package/dist/messaging/imessage/OutboundAuditLog.js +58 -0
  41. package/dist/messaging/imessage/OutboundAuditLog.js.map +1 -0
  42. package/dist/messaging/imessage/OutboundRateLimiter.d.ts +54 -0
  43. package/dist/messaging/imessage/OutboundRateLimiter.d.ts.map +1 -0
  44. package/dist/messaging/imessage/OutboundRateLimiter.js +111 -0
  45. package/dist/messaging/imessage/OutboundRateLimiter.js.map +1 -0
  46. package/dist/messaging/imessage/index.d.ts +10 -0
  47. package/dist/messaging/imessage/index.d.ts.map +1 -0
  48. package/dist/messaging/imessage/index.js +13 -0
  49. package/dist/messaging/imessage/index.js.map +1 -0
  50. package/dist/messaging/imessage/normalize-phone.d.ts +26 -0
  51. package/dist/messaging/imessage/normalize-phone.d.ts.map +1 -0
  52. package/dist/messaging/imessage/normalize-phone.js +55 -0
  53. package/dist/messaging/imessage/normalize-phone.js.map +1 -0
  54. package/dist/messaging/imessage/types.d.ts +95 -0
  55. package/dist/messaging/imessage/types.d.ts.map +1 -0
  56. package/dist/messaging/imessage/types.js +5 -0
  57. package/dist/messaging/imessage/types.js.map +1 -0
  58. package/dist/messaging/shared/MessagingEventBus.d.ts +5 -0
  59. package/dist/messaging/shared/MessagingEventBus.d.ts.map +1 -1
  60. package/dist/messaging/shared/MessagingEventBus.js.map +1 -1
  61. package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
  62. package/dist/messaging/slack/SlackAdapter.js +65 -1
  63. package/dist/messaging/slack/SlackAdapter.js.map +1 -1
  64. package/dist/messaging/slack/SocketModeClient.d.ts.map +1 -1
  65. package/dist/messaging/slack/SocketModeClient.js +6 -0
  66. package/dist/messaging/slack/SocketModeClient.js.map +1 -1
  67. package/dist/monitoring/PresenceProxy.d.ts +6 -0
  68. package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
  69. package/dist/monitoring/PresenceProxy.js +46 -0
  70. package/dist/monitoring/PresenceProxy.js.map +1 -1
  71. package/dist/monitoring/QuotaExhaustionDetector.d.ts +15 -0
  72. package/dist/monitoring/QuotaExhaustionDetector.d.ts.map +1 -1
  73. package/dist/monitoring/QuotaExhaustionDetector.js +26 -3
  74. package/dist/monitoring/QuotaExhaustionDetector.js.map +1 -1
  75. package/dist/monitoring/SessionMonitor.d.ts.map +1 -1
  76. package/dist/monitoring/SessionMonitor.js +5 -2
  77. package/dist/monitoring/SessionMonitor.js.map +1 -1
  78. package/dist/monitoring/SessionRecovery.d.ts +16 -1
  79. package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
  80. package/dist/monitoring/SessionRecovery.js +71 -8
  81. package/dist/monitoring/SessionRecovery.js.map +1 -1
  82. package/dist/scaffold/templates.d.ts +1 -1
  83. package/dist/scaffold/templates.d.ts.map +1 -1
  84. package/dist/scaffold/templates.js +32 -1
  85. package/dist/scaffold/templates.js.map +1 -1
  86. package/dist/scheduler/JobScheduler.js +1 -1
  87. package/dist/scheduler/JobScheduler.js.map +1 -1
  88. package/dist/server/AgentServer.d.ts +1 -0
  89. package/dist/server/AgentServer.d.ts.map +1 -1
  90. package/dist/server/AgentServer.js +1 -0
  91. package/dist/server/AgentServer.js.map +1 -1
  92. package/dist/server/routes.d.ts +1 -0
  93. package/dist/server/routes.d.ts.map +1 -1
  94. package/dist/server/routes.js +169 -0
  95. package/dist/server/routes.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/data/builtin-manifest.json +83 -67
  98. package/src/templates/hooks/intercept-imsg-send.js +68 -0
  99. package/src/templates/hooks/settings-template.json +11 -0
  100. package/src/templates/scripts/imessage-reply.sh +130 -0
  101. package/upgrades/0.26.4.md +17 -0
  102. package/upgrades/0.26.5.md +15 -0
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">instar</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Persistent Claude Code agents with scheduling, sessions, memory, and Telegram.</strong>
8
+ <strong>Persistent Claude Code agents with scheduling, sessions, memory, and messaging.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -31,11 +31,11 @@
31
31
  npx instar
32
32
  ```
33
33
 
34
- One command. Guided setup. Talking to your agent from Telegram within minutes.
34
+ One command. Guided setup. Talking to your agent from your phone within minutes.
35
35
 
36
36
  ---
37
37
 
38
- Instar turns Claude Code from a powerful CLI tool into a **coherent, autonomous partner**. Persistent identity, memory that survives every restart, job scheduling, two-way Telegram messaging, and the infrastructure to evolve.
38
+ Instar turns Claude Code from a powerful CLI tool into a **coherent, autonomous partner**. Persistent identity, memory that survives every restart, job scheduling, two-way messaging (Telegram, WhatsApp, iMessage), and the infrastructure to evolve.
39
39
 
40
40
  ## Quick Start
41
41
 
@@ -48,10 +48,10 @@ npx instar
48
48
  # 2. Start your agent
49
49
  instar server start
50
50
 
51
- # 3. Message it on Telegram — it responds, runs jobs, and remembers everything
51
+ # 3. Message it from your phone — it responds, runs jobs, and remembers everything
52
52
  ```
53
53
 
54
- The wizard discovers your environment, configures messaging (Telegram and/or WhatsApp), sets up identity files, and gets your agent running. **Within minutes, you're talking to your partner from your phone.**
54
+ The wizard discovers your environment, configures messaging (Telegram, WhatsApp, and/or iMessage), sets up identity files, and gets your agent running. **Within minutes, you're talking to your partner from your phone.**
55
55
 
56
56
  **Requirements:** Node.js 20+ · [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) · [API key](https://console.anthropic.com/) or Claude subscription
57
57
 
@@ -60,7 +60,7 @@ The wizard discovers your environment, configures messaging (Telegram and/or Wha
60
60
  ## How It Works
61
61
 
62
62
  ```
63
- You (Telegram / WhatsApp / Terminal)
63
+ You (Telegram / WhatsApp / iMessage / Terminal)
64
64
 
65
65
  conversation
66
66
 
@@ -103,6 +103,7 @@ Instar solves the six dimensions of agent coherence:
103
103
  | **Job Scheduler** | Cron-based tasks with priority levels, model tiering, and quota awareness | [→](https://instar.sh/features/scheduler/) |
104
104
  | **Telegram** | Two-way messaging via forum topics. Each topic maps to a Claude session | [→](https://instar.sh/features/telegram/) |
105
105
  | **WhatsApp** | Full messaging via local Baileys library. No cloud dependency | [→](https://instar.sh/features/whatsapp/) |
106
+ | **iMessage** | Native macOS messaging via Messages.app database polling + `imsg` CLI. [Setup guide](#imessage-setup-macos) | |
106
107
  | **Lifeline** | Persistent supervisor. Detects crashes, auto-recovers, queues messages | [→](https://instar.sh/features/lifeline/) |
107
108
  | **Conversational Memory** | Per-topic SQLite with FTS5, rolling summaries, context re-injection | [→](https://instar.sh/features/memory/) |
108
109
  | **Evolution System** | Proposals, learnings, gap tracking, commitment follow-through | [→](https://instar.sh/features/evolution/) |
@@ -158,7 +159,7 @@ Different tools solve different problems. Here's where Instar fits:
158
159
  | **Persistence** | Multi-layered memory across sessions | Session-bound context | Plugin-based memory | Framework-dependent |
159
160
  | **Identity** | Hooks enforce identity at every boundary | Manual CLAUDE.md | Not addressed | Not addressed |
160
161
  | **Scheduling** | Native cron with priority & quotas | None | None | External required |
161
- | **Messaging** | Telegram + WhatsApp (two-way) | None | 22+ channels, voice, device apps | External required |
162
+ | **Messaging** | Telegram + WhatsApp + iMessage (two-way) | None | 22+ channels, voice, device apps | External required |
162
163
  | **Safety** | LLM-supervised gates, decision journaling | Permission prompts | Behavioral hooks | Guardrails libraries |
163
164
  | **Process model** | One process per session, isolated | Single process | All agents in one Gateway | Single orchestrator |
164
165
  | **State storage** | 100% file-based (JSON/JSONL/SQLite) | Session only | Database-backed | Framework-dependent |
@@ -197,6 +198,59 @@ The AI systems we build today set precedents for how AI is treated tomorrow. **T
197
198
 
198
199
  </details>
199
200
 
201
+ ## iMessage Setup (macOS)
202
+
203
+ iMessage support lets your agent send and receive iMessages on macOS. Messages are read directly from the native Messages database and sent via the [`imsg`](https://github.com/steipete/imsg) CLI.
204
+
205
+ ### Prerequisites
206
+
207
+ 1. **macOS** with Messages.app signed into an Apple ID
208
+ 2. **Full Disk Access** for your terminal app (System Settings → Privacy & Security → Full Disk Access → add Terminal.app or iTerm)
209
+ 3. **imsg CLI** installed:
210
+ ```bash
211
+ brew install steipete/tap/imsg
212
+ ```
213
+ 4. **Automation permission** for Messages.app — macOS will prompt on first send
214
+
215
+ ### Configuration
216
+
217
+ Add to your `.instar/config.json`:
218
+
219
+ ```json
220
+ {
221
+ "messaging": [
222
+ {
223
+ "type": "imessage",
224
+ "enabled": true,
225
+ "config": {
226
+ "authorizedSenders": ["+14081234567"],
227
+ "cliPath": "/opt/homebrew/bin/imsg"
228
+ }
229
+ }
230
+ ]
231
+ }
232
+ ```
233
+
234
+ `authorizedSenders` is required (fail-closed). Only messages from these phone numbers or email addresses will be processed.
235
+
236
+ ### How it works
237
+
238
+ - **Receiving**: The server polls `~/Library/Messages/chat.db` every 2 seconds for new messages. Uses the `query_only` SQLite pragma to read the WAL (write-ahead log) where Messages.app writes new data.
239
+ - **Sending**: Claude Code sessions run `imessage-reply.sh` which calls `imsg send` and notifies the server for logging. Sending requires Automation permission for Messages.app, which only works from user-context processes (tmux sessions), not the LaunchAgent server.
240
+ - **Session lifecycle**: Follows the same pattern as Telegram — each sender maps to a Claude Code session that receives conversation context on spawn and respawns with full history when needed.
241
+
242
+ ### Endpoints
243
+
244
+ | Endpoint | Description |
245
+ |----------|-------------|
246
+ | `GET /imessage/status` | Connection state |
247
+ | `POST /imessage/validate-send/:recipient` | Validate recipient + issue single-use send token (outbound safety layer) |
248
+ | `POST /imessage/reply/:recipient` | Confirm delivery with send token (called by imessage-reply.sh after `imsg send`) |
249
+ | `GET /imessage/chats` | List recent conversations |
250
+ | `GET /imessage/chats/:chatId/history` | Message history for a chat |
251
+ | `GET /imessage/search?q=query` | Search messages |
252
+ | `GET /imessage/log-stats` | Outbound audit log statistics |
253
+
200
254
  ## Origin
201
255
 
202
256
  Instar was extracted from the [Dawn/Portal project](https://dawn.bot-me.ai) -- a production AI system where a human and an AI have been building together for months. The infrastructure patterns were **earned through real experience**, refined through real failures and growth in a real human-AI relationship.
@@ -58,6 +58,8 @@
58
58
  display: flex;
59
59
  align-items: center;
60
60
  gap: 12px;
61
+ min-width: 0;
62
+ flex: 1;
61
63
  }
62
64
 
63
65
  .header h1 {
@@ -255,6 +257,7 @@
255
257
  .dropzone-container {
256
258
  display: flex;
257
259
  justify-content: center;
260
+ grid-column: 1 / -1;
258
261
  padding: 24px;
259
262
  overflow-y: auto;
260
263
  height: calc(100vh - 56px);
@@ -718,7 +721,11 @@
718
721
  display: flex;
719
722
  gap: 0;
720
723
  margin-left: 24px;
724
+ overflow-x: auto;
725
+ -webkit-overflow-scrolling: touch;
726
+ scrollbar-width: none; /* hide scrollbar on Firefox */
721
727
  }
728
+ .tab-bar::-webkit-scrollbar { display: none; }
722
729
 
723
730
  .tab-bar .tab {
724
731
  padding: 6px 16px;
@@ -732,6 +739,8 @@
732
739
  border-bottom: none;
733
740
  margin-bottom: -1px;
734
741
  transition: color 0.15s, background 0.15s;
742
+ white-space: nowrap;
743
+ flex-shrink: 0;
735
744
  }
736
745
 
737
746
  .tab-bar .tab:hover {
@@ -2259,10 +2268,12 @@
2259
2268
  display: flex;
2260
2269
  gap: 12px;
2261
2270
  margin-bottom: 16px;
2271
+ flex-wrap: wrap;
2262
2272
  }
2263
2273
 
2264
2274
  .metric-card {
2265
2275
  flex: 1;
2276
+ min-width: 100px;
2266
2277
  background: var(--bg-panel);
2267
2278
  border: 1px solid var(--border);
2268
2279
  border-radius: 8px;
@@ -3214,6 +3225,9 @@
3214
3225
  // Update active state in sidebar
3215
3226
  renderSessionList();
3216
3227
 
3228
+ // Persist session in URL for refresh
3229
+ updateFileUrl();
3230
+
3217
3231
  // Focus input
3218
3232
  document.getElementById('termInput').focus();
3219
3233
  }
@@ -3399,7 +3413,18 @@
3399
3413
  pendingOutputData = null;
3400
3414
  term.clear();
3401
3415
  term.write(data);
3416
+ // Delay scrollToBottom until after xterm renders the written data
3417
+ requestAnimationFrame(() => {
3418
+ term.scrollToBottom();
3419
+ // Also scroll the browser viewport to show the terminal bottom
3420
+ const container = document.getElementById('terminalContainer');
3421
+ if (container) container.scrollIntoView({ block: 'end', behavior: 'instant' });
3422
+ });
3423
+ } else {
3424
+ // No pending data — just snap to bottom of existing content
3402
3425
  term.scrollToBottom();
3426
+ const container = document.getElementById('terminalContainer');
3427
+ if (container) container.scrollIntoView({ block: 'end', behavior: 'instant' });
3403
3428
  }
3404
3429
  hideResumeButton();
3405
3430
  };
@@ -3425,6 +3450,7 @@
3425
3450
  document.getElementById('terminalView').style.display = 'none';
3426
3451
  document.getElementById('noSession').style.display = 'flex';
3427
3452
  renderSessionList();
3453
+ updateFileUrl(); // Clear session from URL
3428
3454
  }
3429
3455
 
3430
3456
  // ── Input ────────────────────────────────────────────────
@@ -4478,9 +4504,16 @@
4478
4504
  } else {
4479
4505
  params.delete('path');
4480
4506
  }
4507
+ params.delete('session');
4481
4508
  } else {
4482
4509
  params.delete('tab');
4483
4510
  params.delete('path');
4511
+ // Persist active session in URL
4512
+ if (activeSession) {
4513
+ params.set('session', activeSession);
4514
+ } else {
4515
+ params.delete('session');
4516
+ }
4484
4517
  }
4485
4518
  const qs = params.toString();
4486
4519
  const newUrl = window.location.pathname + (qs ? '?' + qs : '');
@@ -4491,6 +4524,7 @@
4491
4524
  const params = new URLSearchParams(window.location.search);
4492
4525
  const tab = params.get('tab');
4493
4526
  const filePath = params.get('path');
4527
+ const sessionParam = params.get('session');
4494
4528
 
4495
4529
  if (tab === 'files') {
4496
4530
  switchTab('files');
@@ -4512,6 +4546,27 @@
4512
4546
  };
4513
4547
  waitForTree();
4514
4548
  }
4549
+ } else if (sessionParam) {
4550
+ // Restore active session from URL — wait for session list to populate
4551
+ let attempts = 0;
4552
+ const waitForSessions = () => {
4553
+ if (sessions.length > 0) {
4554
+ const match = sessions.find(s => s.tmuxSession === sessionParam);
4555
+ if (match) {
4556
+ selectSession(match.tmuxSession, match);
4557
+ }
4558
+ // If no match, session ended — clear stale param
4559
+ if (!match) {
4560
+ const p = new URLSearchParams(window.location.search);
4561
+ p.delete('session');
4562
+ const qs = p.toString();
4563
+ history.replaceState(null, '', window.location.pathname + (qs ? '?' + qs : ''));
4564
+ }
4565
+ } else if (++attempts < 15) {
4566
+ setTimeout(waitForSessions, 200);
4567
+ }
4568
+ };
4569
+ waitForSessions();
4515
4570
  }
4516
4571
  }
4517
4572
 
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA+CH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBrE;AAk3FD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAiBlF"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA+CH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBrE;AAm3FD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAiBlF"}
@@ -2414,7 +2414,8 @@ function installAutonomousSkill(skillsDir) {
2414
2414
  const hooksDir = path.join(autonomousDir, 'hooks');
2415
2415
  const scriptsDir = path.join(autonomousDir, 'scripts');
2416
2416
  // Copy from instar's bundled skill files if they exist
2417
- const bundledDir = path.join(path.dirname(path.dirname(__dirname)), '.claude', 'skills', 'autonomous');
2417
+ const modDir = path.dirname(new URL(import.meta.url).pathname);
2418
+ const bundledDir = path.join(path.dirname(path.dirname(modDir)), '.claude', 'skills', 'autonomous');
2418
2419
  if (fs.existsSync(bundledDir)) {
2419
2420
  // Copy from bundled source
2420
2421
  fs.mkdirSync(hooksDir, { recursive: true });