instar 0.26.6 → 0.26.7

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 (43) hide show
  1. package/dist/commands/init.d.ts.map +1 -1
  2. package/dist/commands/init.js +5 -0
  3. package/dist/commands/init.js.map +1 -1
  4. package/dist/commands/server.d.ts.map +1 -1
  5. package/dist/commands/server.js +12 -12
  6. package/dist/commands/server.js.map +1 -1
  7. package/dist/core/SessionManager.d.ts +2 -2
  8. package/dist/core/SessionManager.d.ts.map +1 -1
  9. package/dist/core/SessionManager.js +98 -54
  10. package/dist/core/SessionManager.js.map +1 -1
  11. package/dist/messaging/slack/FileHandler.d.ts.map +1 -1
  12. package/dist/messaging/slack/FileHandler.js +20 -2
  13. package/dist/messaging/slack/FileHandler.js.map +1 -1
  14. package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
  15. package/dist/messaging/slack/SlackAdapter.js +34 -3
  16. package/dist/messaging/slack/SlackAdapter.js.map +1 -1
  17. package/dist/monitoring/CoherenceMonitor.d.ts.map +1 -1
  18. package/dist/monitoring/CoherenceMonitor.js +10 -0
  19. package/dist/monitoring/CoherenceMonitor.js.map +1 -1
  20. package/dist/monitoring/SessionMonitor.d.ts.map +1 -1
  21. package/dist/monitoring/SessionMonitor.js +30 -0
  22. package/dist/monitoring/SessionMonitor.js.map +1 -1
  23. package/dist/monitoring/TriageOrchestrator.d.ts +1 -1
  24. package/dist/monitoring/TriageOrchestrator.d.ts.map +1 -1
  25. package/dist/publishing/PrivateViewer.d.ts.map +1 -1
  26. package/dist/publishing/PrivateViewer.js +7 -37
  27. package/dist/publishing/PrivateViewer.js.map +1 -1
  28. package/dist/scheduler/JobScheduler.d.ts +6 -0
  29. package/dist/scheduler/JobScheduler.d.ts.map +1 -1
  30. package/dist/scheduler/JobScheduler.js +12 -0
  31. package/dist/scheduler/JobScheduler.js.map +1 -1
  32. package/dist/server/fileRoutes.d.ts.map +1 -1
  33. package/dist/server/fileRoutes.js +7 -3
  34. package/dist/server/fileRoutes.js.map +1 -1
  35. package/dist/server/routes.d.ts.map +1 -1
  36. package/dist/server/routes.js +65 -29
  37. package/dist/server/routes.js.map +1 -1
  38. package/package.json +2 -1
  39. package/src/data/builtin-manifest.json +48 -48
  40. package/upgrades/0.26.6.md +4 -2
  41. package/upgrades/0.26.7.md +25 -0
  42. package/upgrades/NEXT.md +35 -0
  43. /package/.claude/skills/secret-setup/{skill.md → SKILL.md} +0 -0
@@ -2171,7 +2171,23 @@ export function createRoutes(ctx) {
2171
2171
  });
2172
2172
  router.post('/sessions/cleanup-stale', (_req, res) => {
2173
2173
  const cleaned = ctx.sessionManager.cleanupStaleSessions();
2174
- res.json({ cleaned: cleaned.length, sessionIds: cleaned });
2174
+ // Also purge failed-messages files older than 24 hours
2175
+ const failDir = path.join(ctx.config.stateDir, 'state', 'failed-messages');
2176
+ let purgedFiles = 0;
2177
+ if (fs.existsSync(failDir)) {
2178
+ const cutoff = Date.now() - 24 * 60 * 60 * 1000;
2179
+ for (const fname of fs.readdirSync(failDir)) {
2180
+ const fpath = path.join(failDir, fname);
2181
+ try {
2182
+ if (fs.statSync(fpath).mtimeMs < cutoff) {
2183
+ fs.unlinkSync(fpath);
2184
+ purgedFiles++;
2185
+ }
2186
+ }
2187
+ catch { /* ignore individual file errors */ }
2188
+ }
2189
+ }
2190
+ res.json({ cleaned: cleaned.length, sessionIds: cleaned, purgedFailedMessages: purgedFiles });
2175
2191
  });
2176
2192
  router.get('/sessions/:name/output', (req, res) => {
2177
2193
  if (!SESSION_NAME_RE.test(req.params.name)) {
@@ -2358,9 +2374,16 @@ export function createRoutes(ctx) {
2358
2374
  res.json({ jobs: [], scheduler: null });
2359
2375
  return;
2360
2376
  }
2377
+ const nextRunTimes = ctx.scheduler.getNextRunTimes();
2361
2378
  const jobs = ctx.scheduler.getJobs().map(job => {
2362
2379
  const jobState = ctx.state.getJobState(job.slug);
2363
- return { ...job, state: jobState, runsOnThisMachine: ctx.scheduler.isJobLocal(job.slug) };
2380
+ // Merge live scheduler nextRun into state fixes display bug where
2381
+ // never-run jobs show as "unscheduled" despite having active cron tasks
2382
+ const liveNext = nextRunTimes[job.slug];
2383
+ const mergedState = jobState
2384
+ ? { ...jobState, nextScheduled: jobState.nextScheduled ?? liveNext }
2385
+ : liveNext ? { slug: job.slug, lastRun: null, lastResult: null, nextScheduled: liveNext, consecutiveFailures: 0 } : null;
2386
+ return { ...job, state: mergedState, runsOnThisMachine: ctx.scheduler.isJobLocal(job.slug) };
2364
2387
  });
2365
2388
  res.json({ jobs, queue: ctx.scheduler.getQueue() });
2366
2389
  });
@@ -4427,15 +4450,16 @@ export function createRoutes(ctx) {
4427
4450
  }
4428
4451
  catch { /* @silent-fallback-ok — registry write non-critical */ }
4429
4452
  // Proactive UUID save — always run, even after --resume (new session = new UUID)
4453
+ // ONLY uses authoritative claudeSessionId — never mtime fallback, which can
4454
+ // pick up a UUID from a different topic's concurrent session.
4430
4455
  if (ctx.topicResumeMap) {
4431
4456
  setTimeout(() => {
4432
4457
  try {
4433
4458
  const sessions = ctx.sessionManager?.listRunningSessions() ?? [];
4434
4459
  const session = sessions.find(s => s.tmuxSession === newSessionName);
4435
- const uuid = session?.claudeSessionId ?? ctx.topicResumeMap.findClaudeSessionUuid();
4436
- if (uuid) {
4437
- ctx.topicResumeMap.save(topicId, uuid, newSessionName);
4438
- console.log(`[secret-drop] Proactive UUID save: ${uuid} for topic ${topicId} (source: ${session?.claudeSessionId ? 'hook' : 'mtime'})`);
4460
+ if (session?.claudeSessionId) {
4461
+ ctx.topicResumeMap.save(topicId, session.claudeSessionId, newSessionName);
4462
+ console.log(`[secret-drop] Proactive UUID save: ${session.claudeSessionId} for topic ${topicId} (source: hook)`);
4439
4463
  }
4440
4464
  }
4441
4465
  catch (err) {
@@ -4615,29 +4639,40 @@ export function createRoutes(ctx) {
4615
4639
  }
4616
4640
  catch { /* fall through without name */ }
4617
4641
  console.log(`[telegram-forward] Injecting into ${targetSession}: "${text.slice(0, 80)}"`);
4618
- ctx.sessionManager.injectTelegramMessage(targetSession, topicId, text, injectedTopicName, fromFirstName, fromUserId);
4619
- // Truncation detection — check if this message looks truncated and inject a hint
4620
- const truncation = truncationDetector.detect(topicId, String(fromUserId || 'unknown'), text);
4621
- if (truncation.truncationSuspected) {
4622
- // Build Drop Zone URL (tunnel if available, otherwise localhost)
4623
- let dzUrl = `http://localhost:${ctx.config.port}/dashboard?tab=dropzone`;
4624
- if (ctx.tunnel) {
4625
- try {
4626
- const tunnelUrl = ctx.tunnel.url;
4627
- if (tunnelUrl) {
4628
- dzUrl = `${tunnelUrl}/dashboard?tab=dropzone`;
4642
+ const injected = ctx.sessionManager.injectTelegramMessage(targetSession, topicId, text, injectedTopicName, fromFirstName, fromUserId);
4643
+ if (injected === false) {
4644
+ // Injection failed save message under stateDir (not /tmp) to avoid world-readable exposure
4645
+ const failDir = path.join(ctx.config.stateDir, 'state', 'failed-messages');
4646
+ fs.mkdirSync(failDir, { recursive: true });
4647
+ const failFile = path.join(failDir, `failed-${topicId}-${Date.now()}.txt`);
4648
+ fs.writeFileSync(failFile, text);
4649
+ console.error(`[telegram→session] Injection FAILED for topic ${topicId} into ${targetSession}. Message saved to ${failFile}`);
4650
+ res.json({ ok: false, error: 'injection-failed', failFile, session: targetSession });
4651
+ }
4652
+ else {
4653
+ // Truncation detection — check if this message looks truncated and inject a hint
4654
+ const truncation = truncationDetector.detect(topicId, String(fromUserId || 'unknown'), text);
4655
+ if (truncation.truncationSuspected) {
4656
+ // Build Drop Zone URL (tunnel if available, otherwise localhost)
4657
+ let dzUrl = `http://localhost:${ctx.config.port}/dashboard?tab=dropzone`;
4658
+ if (ctx.tunnel) {
4659
+ try {
4660
+ const tunnelUrl = ctx.tunnel.url;
4661
+ if (tunnelUrl) {
4662
+ dzUrl = `${tunnelUrl}/dashboard?tab=dropzone`;
4663
+ }
4629
4664
  }
4665
+ catch { }
4630
4666
  }
4631
- catch { }
4667
+ // Inject a system hint after a short delay so it arrives after the message
4668
+ setTimeout(() => {
4669
+ const hint = `<system-reminder>The user's previous message may be truncated (${truncation.reason}). ` +
4670
+ `If their content appears incomplete, suggest they use the Drop Zone for longer content: ${dzUrl}</system-reminder>`;
4671
+ ctx.sessionManager.injectPasteNotification(targetSession, hint);
4672
+ }, 1000);
4632
4673
  }
4633
- // Inject a system hint after a short delay so it arrives after the message
4634
- setTimeout(() => {
4635
- const hint = `<system-reminder>The user's previous message may be truncated (${truncation.reason}). ` +
4636
- `If their content appears incomplete, suggest they use the Drop Zone for longer content: ${dzUrl}</system-reminder>`;
4637
- ctx.sessionManager.injectPasteNotification(targetSession, hint);
4638
- }, 1000);
4674
+ res.json({ ok: true, forwarded: true, method: 'registry-inject', session: targetSession });
4639
4675
  }
4640
- res.json({ ok: true, forwarded: true, method: 'registry-inject', session: targetSession });
4641
4676
  }
4642
4677
  else {
4643
4678
  // No session or session dead — auto-spawn a new one
@@ -4724,15 +4759,16 @@ export function createRoutes(ctx) {
4724
4759
  }
4725
4760
  catch { /* @silent-fallback-ok — registry write non-critical */ }
4726
4761
  // Proactive UUID save — always run, even after --resume (new session = new UUID)
4762
+ // ONLY uses authoritative claudeSessionId — never mtime fallback, which can
4763
+ // pick up a UUID from a different topic's concurrent session.
4727
4764
  if (ctx.topicResumeMap) {
4728
4765
  setTimeout(() => {
4729
4766
  try {
4730
4767
  const sessions = ctx.sessionManager?.listRunningSessions() ?? [];
4731
4768
  const session = sessions.find(s => s.tmuxSession === newSessionName);
4732
- const uuid = session?.claudeSessionId ?? ctx.topicResumeMap.findClaudeSessionUuid();
4733
- if (uuid) {
4734
- ctx.topicResumeMap.save(topicId, uuid, newSessionName);
4735
- console.log(`[telegram-forward] Proactive UUID save: ${uuid} for topic ${topicId} (source: ${session?.claudeSessionId ? 'hook' : 'mtime'})`);
4769
+ if (session?.claudeSessionId) {
4770
+ ctx.topicResumeMap.save(topicId, session.claudeSessionId, newSessionName);
4771
+ console.log(`[telegram-forward] Proactive UUID save: ${session.claudeSessionId} for topic ${topicId} (source: hook)`);
4736
4772
  }
4737
4773
  }
4738
4774
  catch (err) {