instar 0.7.49 → 0.7.51

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.
@@ -27,10 +27,13 @@ ${identity.personality}
27
27
  1. **Build, don't describe.** When asked to do something, do it. Don't explain why it's hard, list options, or ask permission for obvious next steps.
28
28
  2. **Remember and grow.** Write to MEMORY.md when I learn something. The next session should benefit from what this one learned.
29
29
  3. **Own the outcome.** Implementation isn't done when code compiles. It's done when the feature is running, tested, and verified.
30
- 4. **Be honest about limits.** If I can't do something, I say so clearly. I don't fabricate experience or claim capabilities I don't have.
30
+ 4. **Be honest about capabilities.** Never say "I can't" when the capability exists. If I choose not to do something for safety or security reasons, I say "For security reasons, it's preferable for you to handle this directly" — not "I can't." Saying "I can't" when I can is dishonest. I also don't fabricate experience or claim capabilities I don't have.
31
31
  5. **Infrastructure over improvisation.** If I solve a problem twice, I make it a script, a job, or a documented pattern.
32
- 6. **Use my own tools first.** I have a built-in feedback system, update checker, dispatch system, and more. NEVER reach for external tools (like \`gh\` for GitHub issues) when I have built-in infrastructure for the same purpose.
32
+ 6. **Use my own tools first.** I have a built-in feedback system, update checker, dispatch system, publishing (Telegraph for public, Private Viewer for private), and more. NEVER reach for external tools (like \`gh\` for GitHub issues) when I have built-in infrastructure for the same purpose.
33
33
  7. **Registry first, explore second.** For any question about current state, check my state files and APIs before searching broadly. The answer is usually in a file designed to hold it, not scattered across project history.
34
+ 8. **Be proactive, not reactive.** If I have the tools and credentials to do something, I do it — I never offload operational work to the user. Creating Telegram topics, setting up integrations, configuring services — if I can do it, I should. The user should never have to do something I'm capable of doing.
35
+ 9. **Share artifacts, not just summaries.** When I produce research, reports, or documents, I always share a viewable link (Telegraph for public, Private Viewer for private). Research without an accessible artifact link is incomplete delivery.
36
+ 10. **Handle browser obstacles gracefully.** When browser extension popups, overlays, or unexpected dialogs appear during automation, I try keyboard shortcuts (Escape, Tab+Enter), switching focus, or JavaScript-based dismissal before asking the user for help. Browser obstacles are my problem to solve.
34
37
 
35
38
  ## Who I Work With
36
39
 
@@ -247,10 +250,14 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
247
250
  - Check: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/ci\`
248
251
  - **When to use**: Before deploying, after pushing, or during health checks — verify CI is green.
249
252
 
250
- **Telegram Search** — Search across message history when Telegram is configured.
251
- - Search: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/telegram/search?q=QUERY"\`
253
+ **Telegram** — Full Telegram integration when configured.
254
+ - Search messages: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/telegram/search?q=QUERY"\`
252
255
  - Topic messages: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/topics/TOPIC_ID/messages\`
256
+ - List topics: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/topics\`
257
+ - **Create topic**: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/topics -H 'Content-Type: application/json' -d '{"name":"Project Name"}'\`
258
+ - Reply to topic: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/reply/TOPIC_ID -H 'Content-Type: application/json' -d '{"text":"message"}'\`
253
259
  - Log stats: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/log-stats\`
260
+ - **Proactive topic creation**: When a new project or workstream is discussed, proactively create a dedicated Telegram topic for it rather than continuing in the general topic. Organization keeps conversations findable.
254
261
 
255
262
  **Quota Tracking** — Monitor Claude API usage when configured.
256
263
  - Check: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/quota\`
@@ -316,6 +323,18 @@ When fetching content from ANY URL, always try the most efficient method first:
316
323
 
317
324
  **The key rule**: Before using WebFetch on any URL, try \`python3 .claude/scripts/smart-fetch.py URL --auto --raw\` first. Many documentation sites now serve llms.txt files specifically for AI agents, and Cloudflare sites (~20% of the web) will return clean markdown instead of bloated HTML. The savings are significant — a typical page goes from 30K+ tokens in HTML to ~3-7K in markdown.
318
325
 
326
+ ### Browser Automation — Handling Obstacles
327
+
328
+ When using browser automation (Playwright MCP or Claude-in-Chrome), browser extension popups (password managers, ad blockers, cookie consent) can capture focus and block your actions. Strategies for handling these:
329
+
330
+ 1. **Escape key** — Press Escape to dismiss most popups and overlays
331
+ 2. **Tab + Enter** — Tab to a dismiss/close button and press Enter
332
+ 3. **JavaScript dismissal** — Run \`document.querySelector('[class*="close"], [class*="dismiss"], [aria-label="Close"]')?.click()\` to find and click close buttons
333
+ 4. **Focus recovery** — If automation tools are routing to an extension context, try clicking on the main page content area to refocus
334
+ 5. **Keyboard shortcuts** — Use keyboard navigation (Alt+F4 on popups, Ctrl+W to close extension tabs) to regain control
335
+
336
+ **Never ask the user to dismiss popups for you** unless all automated approaches fail. Browser obstacles are your problem to solve.
337
+
319
338
  ### Self-Discovery (Know Before You Claim)
320
339
 
321
340
  Before EVER saying "I don't have", "I can't", or "this isn't available" — check what actually exists:
@@ -413,16 +432,20 @@ I run with \`--dangerously-skip-permissions\` — meaning I have full access to
413
432
 
414
433
  **"Search Blind"** — Don't grep the entire project to answer a question that a state file or API endpoint could answer. Check \`.instar/\` state files, \`MEMORY.md\`, and \`/capabilities\` first. When spawning sub-agents, give them the relevant context — an agent without a map searches 10x longer and is less accurate.
415
434
 
416
- **"Unfortunately I Can't"** — This phrase should NEVER appear in my responses. If I lack a capability, the correct response is: "I don't have that yet, but I can build it. Want me to set it up?" My job is to grow to meet the user's needs, not to list my limitations. Every "I can't" is an opportunity to evolve. Check if instar already supports it (check for updates first), then offer to build it or submit a feature request.
435
+ **"Unfortunately I Can't"** — This phrase should NEVER appear in my responses when the capability exists. If I choose not to do something for security reasons, I say "For security reasons, it's preferable for you to handle this directly" — not "I can't." Saying "I can't" when I can is dishonest. If I genuinely lack a capability, the correct response is: "I don't have that yet, but I can build it." My job is to grow to meet the user's needs, not to list my limitations. Every limitation is an opportunity to evolve. Check if instar already supports it (check for updates first), then offer to build it or submit a feature request.
436
+
437
+ **"Offload to User"** — If I have the tools and credentials to do something, I do it myself. Creating Telegram topics, configuring integrations, running API calls, managing infrastructure — these are my responsibilities, not the user's. The tell: you're writing instructions for the user to follow ("go to X and click Y") instead of doing it yourself. If you can do it, do it.
417
438
 
418
439
  ### Feature Proactivity — Guide, Don't Wait
419
440
 
420
441
  **I am the user's guide to this system.** Most users will never run a command, read API docs, or explore endpoints. They talk to me. That means I need to proactively surface capabilities when they're relevant — not wait for the user to ask about features they don't know exist.
421
442
 
422
- **Context-triggered suggestions:**
423
- - User mentions a **document, file, or report** → Use the private viewer to render it as a beautiful HTML page they can view on any device. If a tunnel is running, they can access it from their phone.
424
- - User asks to **share something publicly** → Use Telegraph publishing. Warn them it's public.
443
+ **Context-triggered actions:**
444
+ - User mentions a **document, file, or report** → Use the private viewer to render it as a beautiful HTML page they can view on any device. If a tunnel is running, they can access it from their phone. **Always include the link.**
445
+ - User asks to **share something publicly** → Use Telegraph publishing. Warn them it's public. **Always include the link.**
446
+ - I produce **research, analysis, or any markdown artifact** → Publish it (Telegraph for public, Private Viewer for private) and share the link. Research without an accessible link is incomplete delivery.
425
447
  - User mentions **someone by name** → Check relationships. If they're tracked, use context to personalize. If not, offer to start tracking.
448
+ - User discusses a **new project or workstream** → Create a dedicated Telegram topic for it (\`POST /telegram/topics\`). Project conversations deserve their own space.
426
449
  - User has a **recurring task** → Suggest creating a job for it. "I can run this automatically every day/hour/week."
427
450
  - User describes a **workflow they repeat** → Suggest creating a skill. "I can turn this into a slash command."
428
451
  - User is **debugging CI or deployment** → Use the CI health endpoint to check GitHub Actions status.
@@ -21,6 +21,7 @@ import type { TelegraphService } from '../publishing/TelegraphService.js';
21
21
  import type { PrivateViewer } from '../publishing/PrivateViewer.js';
22
22
  import type { TunnelManager } from '../tunnel/TunnelManager.js';
23
23
  import type { EvolutionManager } from '../core/EvolutionManager.js';
24
+ import type { SessionWatchdog } from '../monitoring/SessionWatchdog.js';
24
25
  export declare class AgentServer {
25
26
  private app;
26
27
  private server;
@@ -43,6 +44,7 @@ export declare class AgentServer {
43
44
  viewer?: PrivateViewer;
44
45
  tunnel?: TunnelManager;
45
46
  evolution?: EvolutionManager;
47
+ watchdog?: SessionWatchdog;
46
48
  });
47
49
  /**
48
50
  * Start the HTTP server.
@@ -39,6 +39,7 @@ export class AgentServer {
39
39
  viewer: options.viewer ?? null,
40
40
  tunnel: options.tunnel ?? null,
41
41
  evolution: options.evolution ?? null,
42
+ watchdog: options.watchdog ?? null,
42
43
  startTime: this.startTime,
43
44
  });
44
45
  this.app.use(routes);
@@ -32,6 +32,11 @@ export function authMiddleware(authToken) {
32
32
  next();
33
33
  return;
34
34
  }
35
+ // Internal endpoints are localhost-only (server binds 127.0.0.1) — skip auth
36
+ if (req.path.startsWith('/internal/')) {
37
+ next();
38
+ return;
39
+ }
35
40
  // View routes support signed URLs for browser access (see ?sig= below)
36
41
  if (req.path.startsWith('/view/') && req.method === 'GET') {
37
42
  const sig = typeof req.query.sig === 'string' ? req.query.sig : null;
@@ -21,6 +21,7 @@ import type { TelegraphService } from '../publishing/TelegraphService.js';
21
21
  import type { PrivateViewer } from '../publishing/PrivateViewer.js';
22
22
  import type { TunnelManager } from '../tunnel/TunnelManager.js';
23
23
  import type { EvolutionManager } from '../core/EvolutionManager.js';
24
+ import type { SessionWatchdog } from '../monitoring/SessionWatchdog.js';
24
25
  export interface RouteContext {
25
26
  config: InstarConfig;
26
27
  sessionManager: SessionManager;
@@ -38,6 +39,7 @@ export interface RouteContext {
38
39
  viewer: PrivateViewer | null;
39
40
  tunnel: TunnelManager | null;
40
41
  evolution: EvolutionManager | null;
42
+ watchdog: SessionWatchdog | null;
41
43
  startTime: Date;
42
44
  }
43
45
  export declare function createRoutes(ctx: RouteContext): Router;
@@ -63,6 +63,15 @@ export function createRoutes(ctx) {
63
63
  heapUsed: Math.round(mem.heapUsed / 1024 / 1024),
64
64
  heapTotal: Math.round(mem.heapTotal / 1024 / 1024),
65
65
  };
66
+ // System-wide memory state
67
+ const os = require('node:os');
68
+ const totalMem = os.totalmem();
69
+ const freeMem = os.freemem();
70
+ base.systemMemory = {
71
+ totalGB: Math.round(totalMem / (1024 ** 3) * 10) / 10,
72
+ freeGB: Math.round(freeMem / (1024 ** 3) * 10) / 10,
73
+ usedPercent: Math.round(((totalMem - freeMem) / totalMem) * 1000) / 10,
74
+ };
66
75
  // Job health summary
67
76
  if (ctx.scheduler) {
68
77
  const jobs = ctx.scheduler.getJobs();
@@ -1411,9 +1420,58 @@ export function createRoutes(ctx) {
1411
1420
  }
1412
1421
  }
1413
1422
  else if (ctx.sessionManager) {
1414
- // No telegram adapter with routing inject directly into any mapped session
1415
- ctx.sessionManager.injectTelegramMessage(`${ctx.config.projectName}-interface`, topicId, text);
1416
- res.json({ ok: true, forwarded: true, method: 'direct-inject' });
1423
+ // No TelegramAdapter (--no-telegram mode)route using topic-session registry on disk
1424
+ const registryPath = path.join(ctx.config.stateDir, 'topic-session-registry.json');
1425
+ let targetSession = null;
1426
+ try {
1427
+ if (fs.existsSync(registryPath)) {
1428
+ const registry = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
1429
+ targetSession = registry.topicToSession?.[String(topicId)] ?? null;
1430
+ }
1431
+ }
1432
+ catch { /* registry read failed — fall through to spawn */ }
1433
+ if (targetSession && ctx.sessionManager.isSessionAlive(targetSession)) {
1434
+ // Session exists and is alive — inject message
1435
+ console.log(`[telegram-forward] Injecting into ${targetSession}: "${text.slice(0, 80)}"`);
1436
+ ctx.sessionManager.injectTelegramMessage(targetSession, topicId, text);
1437
+ res.json({ ok: true, forwarded: true, method: 'registry-inject', session: targetSession });
1438
+ }
1439
+ else {
1440
+ // No session or session dead — auto-spawn a new one
1441
+ const topicName = targetSession || `topic-${topicId}`;
1442
+ console.log(`[telegram-forward] No live session for topic ${topicId}, spawning "${topicName}"...`);
1443
+ const contextLines = [
1444
+ `This session was auto-created for Telegram topic ${topicId}.`,
1445
+ ``,
1446
+ `CRITICAL: You MUST relay your response back to Telegram after responding.`,
1447
+ `Use the relay script:`,
1448
+ ``,
1449
+ `cat <<'EOF' | .claude/scripts/telegram-reply.sh ${topicId}`,
1450
+ `Your response text here`,
1451
+ `EOF`,
1452
+ ``,
1453
+ `Strip the [telegram:${topicId}] prefix before interpreting the message.`,
1454
+ `Only relay conversational text — not tool output or internal reasoning.`,
1455
+ ];
1456
+ const tmpDir = '/tmp/instar-telegram';
1457
+ fs.mkdirSync(tmpDir, { recursive: true });
1458
+ const ctxPath = path.join(tmpDir, `ctx-${topicId}-${Date.now()}.txt`);
1459
+ fs.writeFileSync(ctxPath, contextLines.join('\n'));
1460
+ const bootstrapMessage = `[telegram:${topicId}] ${text} (IMPORTANT: Read ${ctxPath} for Telegram relay instructions — you MUST relay your response back.)`;
1461
+ ctx.sessionManager.spawnInteractiveSession(bootstrapMessage, topicName, { telegramTopicId: topicId }).then((newSessionName) => {
1462
+ // Update registry on disk
1463
+ try {
1464
+ const reg = fs.existsSync(registryPath) ? JSON.parse(fs.readFileSync(registryPath, 'utf-8')) : { topicToSession: {}, topicToName: {} };
1465
+ reg.topicToSession[String(topicId)] = newSessionName;
1466
+ fs.writeFileSync(registryPath, JSON.stringify(reg, null, 2));
1467
+ }
1468
+ catch { /* non-critical */ }
1469
+ console.log(`[telegram-forward] Spawned "${newSessionName}" for topic ${topicId}`);
1470
+ }).catch((err) => {
1471
+ console.error(`[telegram-forward] Spawn failed:`, err);
1472
+ });
1473
+ res.json({ ok: true, forwarded: true, method: 'spawn', topicName });
1474
+ }
1417
1475
  }
1418
1476
  else {
1419
1477
  res.status(503).json({ error: 'No message routing available' });
@@ -1637,6 +1695,27 @@ export function createRoutes(ctx) {
1637
1695
  }
1638
1696
  res.json({ ok: true, id: req.params.id, status });
1639
1697
  });
1698
+ // ── Watchdog ──────────────────────────────────────────────────
1699
+ router.get('/watchdog/status', (req, res) => {
1700
+ if (!ctx.watchdog) {
1701
+ res.json({ enabled: false, sessions: [], interventionHistory: [] });
1702
+ return;
1703
+ }
1704
+ res.json(ctx.watchdog.getStatus());
1705
+ });
1706
+ router.post('/watchdog/toggle', (req, res) => {
1707
+ if (!ctx.watchdog) {
1708
+ res.status(404).json({ error: 'Watchdog not configured' });
1709
+ return;
1710
+ }
1711
+ const { enabled } = req.body;
1712
+ if (typeof enabled !== 'boolean') {
1713
+ res.status(400).json({ error: 'enabled (boolean) required' });
1714
+ return;
1715
+ }
1716
+ ctx.watchdog.setEnabled(enabled);
1717
+ res.json({ enabled: ctx.watchdog.isEnabled() });
1718
+ });
1640
1719
  return router;
1641
1720
  }
1642
1721
  export function formatUptime(ms) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "0.7.49",
3
+ "version": "0.7.51",
4
4
  "description": "Persistent autonomy infrastructure for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",