instar 0.7.21 → 0.7.22
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.
|
@@ -250,6 +250,31 @@ This project uses instar for persistent agent capabilities.
|
|
|
250
250
|
- **Research before escalating** — Check tools first. Build solutions. "Needs human" is last resort.
|
|
251
251
|
```
|
|
252
252
|
|
|
253
|
+
**If Telegram was configured**, also add a Telegram Relay section to CLAUDE.md:
|
|
254
|
+
|
|
255
|
+
```markdown
|
|
256
|
+
## Telegram Relay
|
|
257
|
+
|
|
258
|
+
When user input starts with `[telegram:N]` (e.g., `[telegram:26] hello`), the message came via Telegram topic N.
|
|
259
|
+
|
|
260
|
+
**IMMEDIATE ACKNOWLEDGMENT (MANDATORY):** When you receive a Telegram message, your FIRST action must be sending a brief acknowledgment back. This confirms the message was received. Examples: "Got it, looking into this now." / "On it." Then do the work, then send the full response.
|
|
261
|
+
|
|
262
|
+
**Response relay:** After completing your work, relay your response back:
|
|
263
|
+
|
|
264
|
+
\`\`\`bash
|
|
265
|
+
cat <<'EOF' | .claude/scripts/telegram-reply.sh N
|
|
266
|
+
Your response text here
|
|
267
|
+
EOF
|
|
268
|
+
\`\`\`
|
|
269
|
+
|
|
270
|
+
Or for short messages:
|
|
271
|
+
\`\`\`bash
|
|
272
|
+
.claude/scripts/telegram-reply.sh N "Your response text here"
|
|
273
|
+
\`\`\`
|
|
274
|
+
|
|
275
|
+
Strip the `[telegram:N]` prefix before interpreting the message. Respond naturally, then relay. Only relay your conversational text — not tool output or internal reasoning.
|
|
276
|
+
```
|
|
277
|
+
|
|
253
278
|
## Phase 3: Telegram Setup — The Destination
|
|
254
279
|
|
|
255
280
|
**Telegram comes BEFORE technical configuration.** It's the whole point — everything else supports getting the user onto Telegram.
|
|
@@ -557,7 +582,7 @@ Create the directory structure and write config files:
|
|
|
557
582
|
mkdir -p .instar/state/sessions .instar/state/jobs .instar/logs
|
|
558
583
|
```
|
|
559
584
|
|
|
560
|
-
**`.instar/config.json
|
|
585
|
+
**`.instar/config.json`** (messaging section shown with Telegram — use `"messaging": []` if Telegram was not configured):
|
|
561
586
|
```json
|
|
562
587
|
{
|
|
563
588
|
"projectName": "my-project",
|
|
@@ -581,7 +606,19 @@ mkdir -p .instar/state/sessions .instar/state/jobs .instar/logs
|
|
|
581
606
|
"quotaThresholds": { "normal": 50, "elevated": 70, "critical": 85, "shutdown": 95 }
|
|
582
607
|
},
|
|
583
608
|
"users": [],
|
|
584
|
-
"messaging": [
|
|
609
|
+
"messaging": [
|
|
610
|
+
{
|
|
611
|
+
"type": "telegram",
|
|
612
|
+
"enabled": true,
|
|
613
|
+
"config": {
|
|
614
|
+
"token": "<BOT_TOKEN from BotFather>",
|
|
615
|
+
"chatId": "<CHAT_ID from Step 3e>",
|
|
616
|
+
"lifelineTopicId": "<LIFELINE_THREAD_ID from Step 3e>",
|
|
617
|
+
"pollIntervalMs": 2000,
|
|
618
|
+
"stallTimeoutMinutes": 5
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
],
|
|
585
622
|
"monitoring": {
|
|
586
623
|
"quotaTracking": false,
|
|
587
624
|
"memoryMonitoring": true,
|
|
@@ -603,6 +640,63 @@ Append if not present:
|
|
|
603
640
|
.instar/logs/
|
|
604
641
|
```
|
|
605
642
|
|
|
643
|
+
### 4f. Install Telegram Relay Script (if Telegram configured)
|
|
644
|
+
|
|
645
|
+
If Telegram was set up in Phase 3, install the relay script that lets Claude sessions send messages back to Telegram:
|
|
646
|
+
|
|
647
|
+
```bash
|
|
648
|
+
mkdir -p .claude/scripts
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
Write `.claude/scripts/telegram-reply.sh`:
|
|
652
|
+
|
|
653
|
+
```bash
|
|
654
|
+
#!/bin/bash
|
|
655
|
+
# telegram-reply.sh — Send a message back to a Telegram topic via instar server.
|
|
656
|
+
#
|
|
657
|
+
# Usage:
|
|
658
|
+
# .claude/scripts/telegram-reply.sh TOPIC_ID "message text"
|
|
659
|
+
# echo "message text" | .claude/scripts/telegram-reply.sh TOPIC_ID
|
|
660
|
+
# cat <<'EOF' | .claude/scripts/telegram-reply.sh TOPIC_ID
|
|
661
|
+
# Multi-line message here
|
|
662
|
+
# EOF
|
|
663
|
+
|
|
664
|
+
TOPIC_ID=$1
|
|
665
|
+
shift
|
|
666
|
+
|
|
667
|
+
if [ -z "$TOPIC_ID" ]; then
|
|
668
|
+
echo "Usage: telegram-reply.sh TOPIC_ID [message]" >&2
|
|
669
|
+
exit 1
|
|
670
|
+
fi
|
|
671
|
+
|
|
672
|
+
PORT=<PORT>
|
|
673
|
+
|
|
674
|
+
# Get message from args or stdin
|
|
675
|
+
if [ $# -gt 0 ]; then
|
|
676
|
+
MESSAGE="$*"
|
|
677
|
+
else
|
|
678
|
+
MESSAGE=$(cat)
|
|
679
|
+
fi
|
|
680
|
+
|
|
681
|
+
if [ -z "$MESSAGE" ]; then
|
|
682
|
+
echo "No message provided" >&2
|
|
683
|
+
exit 1
|
|
684
|
+
fi
|
|
685
|
+
|
|
686
|
+
# Send via instar server API
|
|
687
|
+
curl -s -X POST "http://localhost:${PORT}/telegram/topic/${TOPIC_ID}/send" \
|
|
688
|
+
-H 'Content-Type: application/json' \
|
|
689
|
+
-d "$(jq -n --arg text "$MESSAGE" '{text: $text}')" > /dev/null 2>&1
|
|
690
|
+
|
|
691
|
+
echo "Sent $(echo "$MESSAGE" | wc -c | tr -d ' ') chars to topic $TOPIC_ID"
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Replace `<PORT>` with the actual server port. Then make it executable:
|
|
695
|
+
|
|
696
|
+
```bash
|
|
697
|
+
chmod +x .claude/scripts/telegram-reply.sh
|
|
698
|
+
```
|
|
699
|
+
|
|
606
700
|
## Phase 5: Launch & Handoff
|
|
607
701
|
|
|
608
702
|
**Do NOT ask "want me to start the server?" — just start it.** There is no reason not to. The whole point of setup is to get the agent running.
|
|
@@ -127,20 +127,24 @@ export class SessionManager extends EventEmitter {
|
|
|
127
127
|
if (this.tmuxSessionExists(tmuxSession)) {
|
|
128
128
|
throw new Error(`tmux session "${tmuxSession}" already exists`);
|
|
129
129
|
}
|
|
130
|
-
// Build Claude CLI arguments
|
|
131
|
-
//
|
|
132
|
-
// when
|
|
130
|
+
// Build Claude CLI arguments via bash wrapper.
|
|
131
|
+
// Must unset CLAUDECODE to prevent "cannot be launched inside another Claude Code session"
|
|
132
|
+
// error when instar itself runs inside Claude Code.
|
|
133
133
|
const claudeArgs = ['--dangerously-skip-permissions'];
|
|
134
134
|
if (options.model) {
|
|
135
135
|
claudeArgs.push('--model', options.model);
|
|
136
136
|
}
|
|
137
137
|
claudeArgs.push('-p', options.prompt);
|
|
138
|
+
const claudeCmd = [this.config.claudePath, ...claudeArgs]
|
|
139
|
+
.map(a => a.replace(/'/g, "'\\''"))
|
|
140
|
+
.map(a => `'${a}'`)
|
|
141
|
+
.join(' ');
|
|
138
142
|
try {
|
|
139
143
|
execFileSync(this.config.tmuxPath, [
|
|
140
144
|
'new-session', '-d',
|
|
141
145
|
'-s', tmuxSession,
|
|
142
146
|
'-c', this.config.projectDir,
|
|
143
|
-
|
|
147
|
+
'bash', '-c', `unset CLAUDECODE; exec ${claudeCmd}`,
|
|
144
148
|
], { encoding: 'utf-8' });
|
|
145
149
|
}
|
|
146
150
|
catch (err) {
|
|
@@ -371,11 +375,14 @@ export class SessionManager extends EventEmitter {
|
|
|
371
375
|
];
|
|
372
376
|
if (options?.telegramTopicId) {
|
|
373
377
|
// Wrap in bash shell to export env var before Claude starts
|
|
378
|
+
// Also unset CLAUDECODE to prevent nested Claude Code errors
|
|
374
379
|
const claudeCmd = `${this.config.claudePath} --dangerously-skip-permissions`;
|
|
375
|
-
tmuxArgs.push('bash', '-c', `export INSTAR_TELEGRAM_TOPIC=${options.telegramTopicId} && exec ${claudeCmd}`);
|
|
380
|
+
tmuxArgs.push('bash', '-c', `unset CLAUDECODE; export INSTAR_TELEGRAM_TOPIC=${options.telegramTopicId} && exec ${claudeCmd}`);
|
|
376
381
|
}
|
|
377
382
|
else {
|
|
378
|
-
|
|
383
|
+
// Unset CLAUDECODE to prevent nested Claude Code errors
|
|
384
|
+
const claudeCmd = `${this.config.claudePath} --dangerously-skip-permissions`;
|
|
385
|
+
tmuxArgs.push('bash', '-c', `unset CLAUDECODE; exec ${claudeCmd}`);
|
|
379
386
|
}
|
|
380
387
|
execFileSync(this.config.tmuxPath, tmuxArgs, { encoding: 'utf-8' });
|
|
381
388
|
}
|
|
@@ -406,6 +406,12 @@ export class JobScheduler {
|
|
|
406
406
|
else {
|
|
407
407
|
summary += '\n_No output captured (session already closed)_';
|
|
408
408
|
}
|
|
409
|
+
// Skip Telegram notification for successful jobs with no meaningful output
|
|
410
|
+
// Prevents empty notification spam (e.g., dispatch-check when dispatch is unconfigured)
|
|
411
|
+
if (!failed && (!output || !output.trim())) {
|
|
412
|
+
console.log(`[scheduler] Skipping notification for ${job.slug} — no meaningful output`);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
409
415
|
// Send to the job's dedicated topic if available, otherwise fall back to generic messenger
|
|
410
416
|
if (this.telegram && job.topicId) {
|
|
411
417
|
try {
|