instar 0.28.17 → 0.28.19
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.
- package/.claude/skills/setup-wizard/SKILL.md +24 -20
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +113 -105
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +5 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/Config.d.ts.map +1 -1
- package/dist/core/Config.js +4 -0
- package/dist/core/Config.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +2 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/Prerequisites.d.ts.map +1 -1
- package/dist/core/Prerequisites.js +50 -1
- package/dist/core/Prerequisites.js.map +1 -1
- package/dist/messaging/slack/SlackAdapter.d.ts +0 -2
- package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
- package/dist/messaging/slack/SlackAdapter.js +1 -17
- package/dist/messaging/slack/SlackAdapter.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +22 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +62 -62
- package/src/templates/hooks/compaction-recovery.sh +18 -0
- package/upgrades/0.28.16.md +27 -3
- package/upgrades/0.28.18.md +12 -0
- package/upgrades/NEXT.md +5 -21
|
@@ -142,25 +142,37 @@ If they type something else → interpret conversationally and route.
|
|
|
142
142
|
|
|
143
143
|
#### If gh_status="auth-needed"
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
**MANDATORY — DO THIS BEFORE ASKING FOR AN AGENT NAME.** The discovery scan ran without GitHub access. The user may already have agents backed up to GitHub from another machine. You MUST offer to sign them in BEFORE proceeding to fresh-install prompts. Skipping this step has caused users to create duplicate agents instead of restoring existing ones.
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
> I need to sign you
|
|
147
|
+
Say:
|
|
148
|
+
> Before we set up a new agent, let me check GitHub for any agents you've backed up from another machine. I need to sign you in — it takes about 30 seconds.
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
gh auth login --web --git-protocol https
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
After auth, re-scan and present results.
|
|
150
|
+
Then follow the **GitHub Device-Code Auth Flow** below. After auth completes, re-run discovery (call `runDiscovery` via the setup CLI or re-invoke the wizard) and present the updated agent list. Only proceed to fresh-install if discovery still shows zero agents.
|
|
155
151
|
|
|
156
152
|
#### If gh_status="unavailable"
|
|
157
153
|
|
|
158
|
-
|
|
159
|
-
> Have you used Instar before on another machine?
|
|
154
|
+
GitHub CLI isn't installed. With instar 0.28.18+ this should be rare — the prerequisite check auto-installs gh. If you somehow get here, ask:
|
|
155
|
+
> Have you used Instar before on another machine? If so, I should install GitHub CLI so I can find your existing agents before we create a new one.
|
|
160
156
|
|
|
161
|
-
If yes:
|
|
157
|
+
If yes: Install gh (brew/apt), then follow the **GitHub Device-Code Auth Flow** below, then re-run discovery.
|
|
162
158
|
If no: Continue to fresh install.
|
|
163
159
|
|
|
160
|
+
#### GitHub Device-Code Auth Flow (use this everywhere `gh auth login` is needed)
|
|
161
|
+
|
|
162
|
+
**DO NOT run `gh auth login` synchronously in Bash** — it blocks waiting for the user to visit a URL and the Bash tool buffer hides the prompt. The user will see a frozen command and have no idea what to do.
|
|
163
|
+
|
|
164
|
+
Instead:
|
|
165
|
+
|
|
166
|
+
1. Start `gh auth login --web --git-protocol https` with `run_in_background: true`.
|
|
167
|
+
2. Poll the background output every 2 seconds (BashOutput tool) until you see a line matching `! First copy your one-time code: XXXX-XXXX` and a line containing `https://github.com/login/device`.
|
|
168
|
+
3. Extract the code and URL, then present them to the user conversationally — NOT as raw Bash output:
|
|
169
|
+
> To sign in, visit **https://github.com/login/device** and enter this code: **XXXX-XXXX**
|
|
170
|
+
> I'll wait here until you're done.
|
|
171
|
+
4. Poll `gh auth status` every 5 seconds (foreground, fast). When it exits 0, the user has finished. Stop polling the background process and let it complete on its own.
|
|
172
|
+
5. Confirm: "You're signed in as <username>. Let me check for your agents now."
|
|
173
|
+
|
|
174
|
+
If 5 minutes pass with no auth completion, ask the user if they want to keep waiting or skip GitHub for now.
|
|
175
|
+
|
|
164
176
|
#### Normal fresh install options
|
|
165
177
|
|
|
166
178
|
**If inside a git repo:**
|
|
@@ -1909,15 +1921,7 @@ Wait for user to install, then re-check.
|
|
|
1909
1921
|
gh auth status 2>&1
|
|
1910
1922
|
```
|
|
1911
1923
|
|
|
1912
|
-
If not authenticated,
|
|
1913
|
-
|
|
1914
|
-
> I need to connect to your GitHub account. This opens your browser for a secure sign-in.
|
|
1915
|
-
|
|
1916
|
-
```bash
|
|
1917
|
-
gh auth login --web --git-protocol https
|
|
1918
|
-
```
|
|
1919
|
-
|
|
1920
|
-
This is an interactive command that opens the browser — run it with `stdio: 'inherit'` so the user sees the auth flow. Wait for it to complete.
|
|
1924
|
+
If not authenticated, use the **GitHub Device-Code Auth Flow** described in Entry Point B (above). DO NOT run `gh auth login` synchronously — it blocks the Bash tool and the user will see a frozen command. Run in background, parse the device code and URL from output, present them conversationally, and poll `gh auth status` until success.
|
|
1921
1925
|
|
|
1922
1926
|
**Step 3: Create private repo**
|
|
1923
1927
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2PH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA6zCD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA2oItE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -568,34 +568,26 @@ function wireTelegramCallbacks(telegram, sessionManager, state, quotaTracker, ac
|
|
|
568
568
|
return sessionManager.isSessionAlive(sessionName);
|
|
569
569
|
};
|
|
570
570
|
// Stall verification — check if session has recent output activity
|
|
571
|
-
|
|
572
|
-
const sessionActivePatterns = [
|
|
573
|
-
/\bRead\b|\bWrite\b|\bEdit\b|\bBash\b|\bGrep\b|\bGlob\b|\bAgent\b|\bSkill\b|\bWebFetch\b|\bWebSearch\b/, // Tool names
|
|
574
|
-
/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏/, // Spinner characters
|
|
575
|
-
/\d+\s*tokens?/i, // Token counts
|
|
576
|
-
/Sent \d+ chars/, // Telegram/Slack reply confirmation
|
|
577
|
-
/Wandering|Thinking|thought for/i, // Claude thinking indicators
|
|
578
|
-
/Searching for \d+ pattern/i, // Search activity
|
|
579
|
-
/ctrl\+[a-z] to/i, // Interactive prompt hints
|
|
580
|
-
/\+ .*\(thought for/, // Tool execution with thinking
|
|
581
|
-
/mcp__/, // MCP tool calls
|
|
582
|
-
/●|○|◉/, // Progress indicators
|
|
583
|
-
];
|
|
584
|
-
/** Check if a session is actively producing output */
|
|
585
|
-
const isSessionActiveCheck = async (sessionName) => {
|
|
571
|
+
telegram.onIsSessionActive = async (sessionName) => {
|
|
586
572
|
const output = sessionManager.captureOutput(sessionName, 20);
|
|
587
573
|
if (!output)
|
|
588
574
|
return false;
|
|
589
575
|
const lines = output.trim().split('\n').slice(-15);
|
|
576
|
+
// Look for signs of Claude Code activity in recent output
|
|
577
|
+
const activePatterns = [
|
|
578
|
+
/\bRead\b|\bWrite\b|\bEdit\b|\bBash\b|\bGrep\b|\bGlob\b/, // Tool names
|
|
579
|
+
/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏/, // Spinner characters
|
|
580
|
+
/\d+\s*tokens?/i, // Token counts
|
|
581
|
+
/Sent \d+ chars/, // Telegram reply confirmation
|
|
582
|
+
];
|
|
590
583
|
for (const line of lines) {
|
|
591
|
-
for (const pattern of
|
|
584
|
+
for (const pattern of activePatterns) {
|
|
592
585
|
if (pattern.test(line))
|
|
593
586
|
return true;
|
|
594
587
|
}
|
|
595
588
|
}
|
|
596
589
|
return false;
|
|
597
590
|
};
|
|
598
|
-
telegram.onIsSessionActive = isSessionActiveCheck;
|
|
599
591
|
// /switch-account — swap active Claude Code account
|
|
600
592
|
if (accountSwitcher) {
|
|
601
593
|
telegram.onSwitchAccountRequest = async (target, replyTopicId) => {
|
|
@@ -2745,31 +2737,6 @@ export async function startServer(options) {
|
|
|
2745
2737
|
slackAdapter.onIsSessionAlive = (tmuxSession) => {
|
|
2746
2738
|
return sessionManager.isSessionAlive(tmuxSession);
|
|
2747
2739
|
};
|
|
2748
|
-
slackAdapter.onIsSessionActive = async (sessionName) => {
|
|
2749
|
-
const output = sessionManager.captureOutput(sessionName, 20);
|
|
2750
|
-
if (!output)
|
|
2751
|
-
return false;
|
|
2752
|
-
const lines = output.trim().split('\n').slice(-15);
|
|
2753
|
-
const activePatterns = [
|
|
2754
|
-
/\bRead\b|\bWrite\b|\bEdit\b|\bBash\b|\bGrep\b|\bGlob\b|\bAgent\b|\bSkill\b|\bWebFetch\b|\bWebSearch\b/,
|
|
2755
|
-
/⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏/,
|
|
2756
|
-
/\d+\s*tokens?/i,
|
|
2757
|
-
/Sent \d+ chars/,
|
|
2758
|
-
/Wandering|Thinking|thought for/i,
|
|
2759
|
-
/Searching for \d+ pattern/i,
|
|
2760
|
-
/ctrl\+[a-z] to/i,
|
|
2761
|
-
/\+ .*\(thought for/,
|
|
2762
|
-
/mcp__/,
|
|
2763
|
-
/●|○|◉/,
|
|
2764
|
-
];
|
|
2765
|
-
for (const line of lines) {
|
|
2766
|
-
for (const pattern of activePatterns) {
|
|
2767
|
-
if (pattern.test(line))
|
|
2768
|
-
return true;
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
return false;
|
|
2772
|
-
};
|
|
2773
2740
|
// Wire prompt response callback — inject button presses into sessions
|
|
2774
2741
|
slackAdapter.onPromptResponse = (channelId, promptId, value) => {
|
|
2775
2742
|
// Look up which session is bound to this channel
|
|
@@ -3760,58 +3727,82 @@ export async function startServer(options) {
|
|
|
3760
3727
|
const { HookEventReceiver } = await import('../monitoring/HookEventReceiver.js');
|
|
3761
3728
|
const hookEventReceiver = new HookEventReceiver({ stateDir: config.stateDir });
|
|
3762
3729
|
console.log(pc.green(' Hook event receiver enabled'));
|
|
3763
|
-
//
|
|
3764
|
-
//
|
|
3765
|
-
//
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3730
|
+
// ── Compaction Resume: unified recovery for one session ──────────────
|
|
3731
|
+
// Robust against subsystem misconfiguration: works with or without
|
|
3732
|
+
// triageOrchestrator. If the orchestrator is available we prefer it
|
|
3733
|
+
// (richer recovery semantics); otherwise we fall back to a direct
|
|
3734
|
+
// tmux re-injection of the unanswered user message.
|
|
3735
|
+
//
|
|
3736
|
+
// Three independent triggers call into this:
|
|
3737
|
+
// 1. PreCompact hook event (Claude Code fires it — unreliable)
|
|
3738
|
+
// 2. SessionWatchdog 'compaction-idle' polling (default-enabled)
|
|
3739
|
+
// 3. POST /internal/compaction-resume (compaction-recovery.sh hook)
|
|
3740
|
+
const recoverCompactedSession = async (sessionName, triggerLabel) => {
|
|
3741
|
+
if (!sessionManager.isSessionAlive(sessionName))
|
|
3742
|
+
return false;
|
|
3743
|
+
// Telegram path
|
|
3744
|
+
if (telegram) {
|
|
3745
|
+
const topicId = telegram.getTopicForSession(sessionName);
|
|
3746
|
+
if (topicId) {
|
|
3747
|
+
const history = telegram.getTopicHistory(topicId, 5);
|
|
3748
|
+
const lastMsg = history[history.length - 1];
|
|
3749
|
+
if (lastMsg?.fromUser) {
|
|
3750
|
+
console.log(`[CompactionResume] (${triggerLabel}) topic ${topicId} session "${sessionName}" has unanswered message — recovering`);
|
|
3751
|
+
if (triageOrchestrator) {
|
|
3752
|
+
try {
|
|
3753
|
+
await triageOrchestrator.activate(topicId, sessionName, 'watchdog', lastMsg.text, Date.now());
|
|
3754
|
+
return true;
|
|
3755
|
+
}
|
|
3756
|
+
catch (err) {
|
|
3757
|
+
console.warn(`[CompactionResume] orchestrator failed, falling back to direct inject:`, err);
|
|
3758
|
+
}
|
|
3783
3759
|
}
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
// don't fire (Claude Code doesn't reliably emit them). The watchdog polls
|
|
3791
|
-
// every 30s and detects sessions that compacted + are idle at a prompt.
|
|
3792
|
-
if (watchdog && triageOrchestrator) {
|
|
3793
|
-
const _triageOrch2 = triageOrchestrator;
|
|
3794
|
-
watchdog.on('compaction-idle', (sessionName) => {
|
|
3795
|
-
// Check Telegram topics
|
|
3796
|
-
if (telegram) {
|
|
3797
|
-
const topicId = telegram.getTopicForSession(sessionName);
|
|
3798
|
-
if (topicId) {
|
|
3799
|
-
const history = telegram.getTopicHistory(topicId, 5);
|
|
3800
|
-
const lastMsg = history[history.length - 1];
|
|
3801
|
-
if (lastMsg?.fromUser) {
|
|
3802
|
-
console.log(`[CompactionResume] Watchdog detected compaction-idle, topic ${topicId} has unanswered message — activating triage`);
|
|
3803
|
-
_triageOrch2.activate(topicId, sessionName, 'watchdog', lastMsg.text, Date.now()).catch(err => {
|
|
3804
|
-
console.warn(`[CompactionResume] Triage activation failed for topic ${topicId}:`, err);
|
|
3805
|
-
});
|
|
3806
|
-
return;
|
|
3760
|
+
// Fallback: direct injection with topic tag so InputGuard accepts it.
|
|
3761
|
+
const tagged = `[telegram:${topicId}] ${lastMsg.text}`;
|
|
3762
|
+
const ok = sessionManager.injectMessage(sessionName, tagged);
|
|
3763
|
+
if (ok) {
|
|
3764
|
+
console.log(`[CompactionResume] (${triggerLabel}) direct re-inject OK for topic ${topicId}`);
|
|
3765
|
+
return true;
|
|
3807
3766
|
}
|
|
3767
|
+
console.warn(`[CompactionResume] (${triggerLabel}) direct re-inject FAILED for topic ${topicId}`);
|
|
3808
3768
|
}
|
|
3809
3769
|
}
|
|
3810
|
-
|
|
3811
|
-
|
|
3770
|
+
}
|
|
3771
|
+
// Slack path — handled in the Slack-aware block below (needs slackChannelToSyntheticId).
|
|
3772
|
+
// We attempt it here lazily via a deferred handler set on globalThis to avoid TDZ.
|
|
3773
|
+
const slackHandler = globalThis.__instarSlackCompactionResume;
|
|
3774
|
+
if (slackHandler) {
|
|
3775
|
+
try {
|
|
3776
|
+
return await slackHandler(sessionName, triggerLabel);
|
|
3777
|
+
}
|
|
3778
|
+
catch { /* fall through */ }
|
|
3779
|
+
}
|
|
3780
|
+
return false;
|
|
3781
|
+
};
|
|
3782
|
+
// Trigger 1: PreCompact hook event — wired unconditionally now.
|
|
3783
|
+
hookEventReceiver.on('PreCompact', () => {
|
|
3784
|
+
// Delay to let compaction + recovery hooks finish
|
|
3785
|
+
setTimeout(() => {
|
|
3786
|
+
if (!telegram)
|
|
3787
|
+
return;
|
|
3788
|
+
const topicSessions = telegram.getAllTopicSessions();
|
|
3789
|
+
for (const [, sessionName] of topicSessions) {
|
|
3790
|
+
recoverCompactedSession(sessionName, 'PreCompact').catch(() => { });
|
|
3791
|
+
}
|
|
3792
|
+
}, 10_000);
|
|
3793
|
+
});
|
|
3794
|
+
console.log(pc.green(' Compaction auto-resume wired (PreCompact hook event)'));
|
|
3795
|
+
// Trigger 2: Watchdog 'compaction-idle' polling — wired unconditionally.
|
|
3796
|
+
if (watchdog) {
|
|
3797
|
+
watchdog.on('compaction-idle', (sessionName) => {
|
|
3798
|
+
recoverCompactedSession(sessionName, 'watchdog-poll').catch(() => { });
|
|
3812
3799
|
});
|
|
3813
|
-
console.log(pc.green(' Compaction auto-resume wired
|
|
3800
|
+
console.log(pc.green(' Compaction auto-resume wired (watchdog poll)'));
|
|
3814
3801
|
}
|
|
3802
|
+
// Trigger 3: stash the recovery function on globalThis so the HTTP route
|
|
3803
|
+
// (registered later in AgentServer) and the compaction-recovery.sh hook
|
|
3804
|
+
// can invoke it via POST /internal/compaction-resume.
|
|
3805
|
+
globalThis.__instarCompactionRecover = recoverCompactedSession;
|
|
3815
3806
|
// Subagent Tracker — monitors subagent lifecycle via hook events
|
|
3816
3807
|
const { SubagentTracker } = await import('../monitoring/SubagentTracker.js');
|
|
3817
3808
|
const subagentTracker = new SubagentTracker({ stateDir: config.stateDir });
|
|
@@ -3946,17 +3937,18 @@ export async function startServer(options) {
|
|
|
3946
3937
|
slackChannelToSyntheticId(channelId);
|
|
3947
3938
|
}
|
|
3948
3939
|
}
|
|
3949
|
-
// Slack compaction-resume wiring —
|
|
3950
|
-
|
|
3951
|
-
|
|
3940
|
+
// Slack compaction-resume wiring — registered as a deferred handler the
|
|
3941
|
+
// unified recoverCompactedSession() helper above will call. Works with or
|
|
3942
|
+
// without triageOrchestrator (falls back to direct sessionManager inject).
|
|
3943
|
+
if (_slackAdapter) {
|
|
3952
3944
|
const _slack = _slackAdapter;
|
|
3953
|
-
|
|
3945
|
+
const slackRecover = async (sessionName, triggerLabel) => {
|
|
3954
3946
|
const channelId = _slack.getChannelForSession(sessionName);
|
|
3955
3947
|
if (!channelId)
|
|
3956
|
-
return;
|
|
3948
|
+
return false;
|
|
3957
3949
|
const syntheticId = slackChannelToSyntheticId(channelId);
|
|
3958
|
-
// Read from the Slack messages JSONL log (local, no API call)
|
|
3959
3950
|
const slackLogPath = path.join(config.stateDir, 'slack-messages.jsonl');
|
|
3951
|
+
let lastUserMsg = null;
|
|
3960
3952
|
try {
|
|
3961
3953
|
const content = fs.readFileSync(slackLogPath, 'utf-8');
|
|
3962
3954
|
const lines = content.trim().split('\n').slice(-10);
|
|
@@ -3964,21 +3956,37 @@ export async function startServer(options) {
|
|
|
3964
3956
|
try {
|
|
3965
3957
|
const msg = JSON.parse(lines[i]);
|
|
3966
3958
|
if (msg.channelId === channelId) {
|
|
3967
|
-
if (msg.fromUser)
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
console.warn(`[CompactionResume] Triage activation failed for Slack channel ${channelId}:`, err);
|
|
3971
|
-
});
|
|
3972
|
-
}
|
|
3973
|
-
break; // Only check the most recent message for this channel
|
|
3959
|
+
if (msg.fromUser)
|
|
3960
|
+
lastUserMsg = msg;
|
|
3961
|
+
break;
|
|
3974
3962
|
}
|
|
3975
3963
|
}
|
|
3976
|
-
catch { /* skip malformed
|
|
3964
|
+
catch { /* skip malformed */ }
|
|
3977
3965
|
}
|
|
3978
3966
|
}
|
|
3979
|
-
catch { /*
|
|
3980
|
-
|
|
3981
|
-
|
|
3967
|
+
catch { /* no log */ }
|
|
3968
|
+
if (!lastUserMsg)
|
|
3969
|
+
return false;
|
|
3970
|
+
const text = lastUserMsg.text || 'message after compaction';
|
|
3971
|
+
console.log(`[CompactionResume] (${triggerLabel}) Slack channel ${channelId} has unanswered message — recovering`);
|
|
3972
|
+
if (triageOrchestrator) {
|
|
3973
|
+
try {
|
|
3974
|
+
await triageOrchestrator.activate(syntheticId, sessionName, 'watchdog', text, Date.now());
|
|
3975
|
+
return true;
|
|
3976
|
+
}
|
|
3977
|
+
catch (err) {
|
|
3978
|
+
console.warn(`[CompactionResume] Slack orchestrator failed, falling back to direct inject:`, err);
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
const ok = sessionManager.injectMessage(sessionName, text);
|
|
3982
|
+
if (ok) {
|
|
3983
|
+
console.log(`[CompactionResume] (${triggerLabel}) Slack direct re-inject OK for channel ${channelId}`);
|
|
3984
|
+
return true;
|
|
3985
|
+
}
|
|
3986
|
+
return false;
|
|
3987
|
+
};
|
|
3988
|
+
globalThis.__instarSlackCompactionResume = slackRecover;
|
|
3989
|
+
console.log(pc.green(' Compaction auto-resume registered (Slack channels)'));
|
|
3982
3990
|
}
|
|
3983
3991
|
let presenceProxy;
|
|
3984
3992
|
if (sharedIntelligence && telegram) {
|