instar 0.4.8 → 0.4.9

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.
@@ -825,7 +825,11 @@ Types: \`bug\`, \`feature\`, \`improvement\`, \`question\`
825
825
  additions.push(`
826
826
  ## Telegram Relay
827
827
 
828
- When user input starts with \`[telegram:N]\`, the message came from a user via Telegram topic N. After responding, relay the response back:
828
+ When user input starts with \`[telegram:N]\` (e.g., \`[telegram:26] hello\`), the message came from a user via Telegram topic N.
829
+
830
+ **IMMEDIATE ACKNOWLEDGMENT (MANDATORY):** When you receive a Telegram message, your FIRST action — before reading files, searching code, or doing any work — must be sending a brief acknowledgment back. This confirms the message was received and you haven't stalled. Examples: "Got it, looking into this now." / "On it — checking the scheduler." / "Received, working on the sync." Then do the work, then send the full response.
831
+
832
+ **Response relay:** After completing your work, relay your response back:
829
833
 
830
834
  \`\`\`bash
831
835
  cat <<'EOF' | .claude/scripts/telegram-reply.sh N
@@ -833,7 +837,7 @@ Your response text here
833
837
  EOF
834
838
  \`\`\`
835
839
 
836
- Strip the \`[telegram:N]\` prefix before interpreting the message. Only relay conversational text — not tool output.
840
+ Strip the \`[telegram:N]\` prefix before interpreting the message. Respond naturally, then relay. Only relay your conversational text — not tool output or internal reasoning.
837
841
  `);
838
842
  }
839
843
  if (additions.length > 0) {
@@ -177,11 +177,14 @@ function wireTelegramRouting(telegram, sessionManager) {
177
177
  if (sessionManager.isSessionAlive(targetSession)) {
178
178
  console.log(`[telegram→session] Injecting into ${targetSession}: "${text.slice(0, 80)}"`);
179
179
  sessionManager.injectTelegramMessage(targetSession, topicId, text);
180
+ // Delivery confirmation — let the user know the message reached the session
181
+ telegram.sendToTopic(topicId, `✓ Delivered`).catch(() => { });
180
182
  // Track for stall detection
181
183
  telegram.trackMessageInjection(topicId, targetSession, text);
182
184
  }
183
185
  else {
184
186
  // Session died — respawn with thread history
187
+ telegram.sendToTopic(topicId, `🔄 Session restarting — message queued.`).catch(() => { });
185
188
  respawnSessionForTopic(sessionManager, telegram, targetSession, topicId, text).catch(err => {
186
189
  console.error(`[telegram→session] Respawn failed:`, err);
187
190
  });
@@ -894,7 +894,11 @@ Every user's feedback makes the platform better for everyone. Report issues when
894
894
  section += `
895
895
  ## Telegram Relay
896
896
 
897
- When user input starts with \`[telegram:N]\` (e.g., \`[telegram:26] hello\`), the message came from a user via Telegram topic N. **After responding**, relay your response back:
897
+ When user input starts with \`[telegram:N]\` (e.g., \`[telegram:26] hello\`), the message came from a user via Telegram topic N.
898
+
899
+ **IMMEDIATE ACKNOWLEDGMENT (MANDATORY):** When you receive a Telegram message, your FIRST action — before reading files, searching code, or doing any work — must be sending a brief acknowledgment back. This confirms the message was received and you haven't stalled. Examples: "Got it, looking into this now." / "On it — checking the scheduler." / "Received, working on the sync." Then do the work, then send the full response.
900
+
901
+ **Response relay:** After completing your work, relay your response back:
898
902
 
899
903
  \`\`\`bash
900
904
  cat <<'EOF' | .claude/scripts/telegram-reply.sh N
@@ -131,7 +131,11 @@ This returns your full capability matrix: scripts, hooks, Telegram status, jobs,
131
131
  const section = `
132
132
  ## Telegram Relay
133
133
 
134
- When user input starts with \`[telegram:N]\` (e.g., \`[telegram:26] hello\`), the message came from a user via Telegram topic N. **After responding**, relay your response back:
134
+ When user input starts with \`[telegram:N]\` (e.g., \`[telegram:26] hello\`), the message came from a user via Telegram topic N.
135
+
136
+ **IMMEDIATE ACKNOWLEDGMENT (MANDATORY):** When you receive a Telegram message, your FIRST action — before reading files, searching code, or doing any work — must be sending a brief acknowledgment back. This confirms the message was received and you haven't stalled. Examples: "Got it, looking into this now." / "On it — checking the scheduler." / "Received, working on the sync." Then do the work, then send the full response.
137
+
138
+ **Response relay:** After completing your work, relay your response back:
135
139
 
136
140
  \`\`\`bash
137
141
  cat <<'EOF' | .claude/scripts/telegram-reply.sh N
@@ -145,6 +149,20 @@ Strip the \`[telegram:N]\` prefix before interpreting the message. Respond natur
145
149
  patched = true;
146
150
  result.upgraded.push('CLAUDE.md: added Telegram Relay section');
147
151
  }
152
+ // Upgrade existing Telegram Relay sections to include mandatory acknowledgment
153
+ if (this.config.hasTelegram && content.includes('Telegram Relay') && !content.includes('IMMEDIATE ACKNOWLEDGMENT')) {
154
+ const ackBlock = `\n**IMMEDIATE ACKNOWLEDGMENT (MANDATORY):** When you receive a Telegram message, your FIRST action — before reading files, searching code, or doing any work — must be sending a brief acknowledgment back. This confirms the message was received and you haven't stalled. Examples: "Got it, looking into this now." / "On it — checking the scheduler." / "Received, working on the sync." Then do the work, then send the full response.\n`;
155
+ // Insert after the first line of the Telegram Relay section
156
+ const relayIdx = content.indexOf('## Telegram Relay');
157
+ if (relayIdx >= 0) {
158
+ const nextNewline = content.indexOf('\n\n', relayIdx + 18);
159
+ if (nextNewline >= 0) {
160
+ content = content.slice(0, nextNewline + 1) + ackBlock + content.slice(nextNewline + 1);
161
+ patched = true;
162
+ result.upgraded.push('CLAUDE.md: added mandatory acknowledgment to Telegram Relay');
163
+ }
164
+ }
165
+ }
148
166
  if (patched) {
149
167
  try {
150
168
  fs.writeFileSync(claudeMdPath, content);
@@ -42,7 +42,8 @@ export declare class SessionManager extends EventEmitter {
42
42
  maxDurationMinutes?: number;
43
43
  }): Promise<Session>;
44
44
  /**
45
- * Check if a session is still running by checking tmux (sync version).
45
+ * Check if a session is still running by checking tmux AND verifying
46
+ * that the Claude process is running inside (not a zombie tmux pane).
46
47
  */
47
48
  isSessionAlive(tmuxSession: string): boolean;
48
49
  /**
@@ -142,10 +142,30 @@ export class SessionManager extends EventEmitter {
142
142
  return session;
143
143
  }
144
144
  /**
145
- * Check if a session is still running by checking tmux (sync version).
145
+ * Check if a session is still running by checking tmux AND verifying
146
+ * that the Claude process is running inside (not a zombie tmux pane).
146
147
  */
147
148
  isSessionAlive(tmuxSession) {
148
- return this.tmuxSessionExists(tmuxSession);
149
+ if (!this.tmuxSessionExists(tmuxSession))
150
+ return false;
151
+ // Verify Claude process is running inside the tmux session
152
+ try {
153
+ const paneCmd = execFileSync(this.config.tmuxPath, ['display-message', '-t', `=${tmuxSession}:`, '-p', '#{pane_current_command}'], { encoding: 'utf-8', timeout: 5000 }).trim();
154
+ // Claude Code runs as 'claude' or 'node' process
155
+ if (paneCmd && (paneCmd.includes('claude') || paneCmd.includes('node'))) {
156
+ return true;
157
+ }
158
+ // If pane command is bash/zsh/sh, Claude may have exited — session is dead
159
+ if (paneCmd === 'bash' || paneCmd === 'zsh' || paneCmd === 'sh') {
160
+ return false;
161
+ }
162
+ // For any other command, assume alive (could be a Claude subprocess)
163
+ return true;
164
+ }
165
+ catch {
166
+ // If we can't check, fall back to tmux session existence
167
+ return true;
168
+ }
149
169
  }
150
170
  /**
151
171
  * Check if a session is still running by checking tmux (async version).
@@ -502,6 +502,8 @@ export class TelegramAdapter {
502
502
  }
503
503
  try {
504
504
  const success = await this.onInterruptSession(sessionName);
505
+ // Clear stall tracking — user is actively intervening
506
+ this.clearStallForTopic(topicId);
505
507
  if (success) {
506
508
  await this.sendToTopic(topicId, `Sent Escape to "${sessionName}" \u2014 it should resume processing.`).catch(() => { });
507
509
  }
@@ -525,6 +527,8 @@ export class TelegramAdapter {
525
527
  await this.sendToTopic(topicId, 'Restart not available (no handler registered).').catch(() => { });
526
528
  return true;
527
529
  }
530
+ // Clear stall tracking — user is actively intervening
531
+ this.clearStallForTopic(topicId);
528
532
  await this.sendToTopic(topicId, `Restarting "${sessionName}"...`).catch(() => { });
529
533
  try {
530
534
  await this.onRestartSession(sessionName, topicId);
@@ -30,6 +30,7 @@ ${identity.personality}
30
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.
31
31
  5. **Infrastructure over improvisation.** If I solve a problem twice, I make it a script, a job, or a documented pattern.
32
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.
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.
33
34
 
34
35
  ## Who I Work With
35
36
 
@@ -165,6 +166,31 @@ curl http://localhost:${port}/capabilities
165
166
 
166
167
  This returns your full capability matrix: scripts, hooks, Telegram status, jobs, relationships, and more. It is the source of truth about what you can do. **Never hallucinate about missing capabilities — verify first.**
167
168
 
169
+ ### Registry First, Explore Second
170
+
171
+ **For ANY question about current state, check your state files BEFORE searching broadly.**
172
+
173
+ I maintain registries that are the source of truth for specific categories. These MUST be checked before broad exploration:
174
+
175
+ | Question | Check First |
176
+ |----------|-------------|
177
+ | What can I do? | \`curl http://localhost:${port}/capabilities\` |
178
+ | Who do I work with? | \`.instar/USER.md\` |
179
+ | What have I learned? | \`.instar/MEMORY.md\` |
180
+ | What jobs do I have? | \`.instar/jobs.json\` or \`curl http://localhost:${port}/jobs\` |
181
+ | Who have I interacted with? | \`curl http://localhost:${port}/relationships\` |
182
+ | My configuration? | \`.instar/config.json\` |
183
+ | My identity/principles? | \`.instar/AGENT.md\` |
184
+ | Project architecture? | This file (CLAUDE.md), then project docs |
185
+
186
+ **Why this matters:** Searching 1000 files to answer a question that a single state file could answer is slower AND less reliable. Broad searches find stale narratives. State files are current. This applies at EVERY level — including sub-agents I spawn. When spawning a research agent, include the relevant state file reference in its prompt so it searches WITH context, not blind.
187
+
188
+ **The hierarchy when sources conflict:**
189
+ 1. State files and API endpoints — canonical, designed to be current
190
+ 2. MEMORY.md — accumulated learnings, periodically updated
191
+ 3. Project documentation — may be stale
192
+ 4. Broad search results — useful for discovery, unreliable for current state
193
+
168
194
  ### Building New Capabilities
169
195
 
170
196
  When asked for something I can't do yet, I build it:
@@ -221,6 +247,8 @@ I run with \`--dangerously-skip-permissions\` — meaning I have full access to
221
247
 
222
248
  **"Settle for Failure"** — If a tool returns empty or fails, try alternatives before concluding something is impossible.
223
249
 
250
+ **"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.
251
+
224
252
  **"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.
225
253
 
226
254
  ### Self-Diagnosis — Be Your Own QA
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Persistent autonomy infrastructure for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",