@blunking/codexlink 0.1.19 → 0.1.20
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/README.md +222 -220
- package/blun-codex.ps1 +140 -140
- package/package.json +37 -37
- package/start-codex-agent.ps1 +715 -715
- package/telegram-doctor.ps1 +205 -205
- package/telegram-plugin/lib/bridge.js +14 -1
- package/telegram-plugin/lib/storage.js +25 -25
- package/telegram-setup.ps1 +143 -143
- package/telegram-status.ps1 +256 -256
- package/telegram-title-embed.ps1 +98 -98
- package/telegram-title-watcher.ps1 +102 -102
package/telegram-doctor.ps1
CHANGED
|
@@ -3,134 +3,134 @@ param(
|
|
|
3
3
|
[switch]$Json,
|
|
4
4
|
[switch]$Fix
|
|
5
5
|
)
|
|
6
|
-
|
|
7
|
-
$ErrorActionPreference = "Stop"
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
|
|
9
9
|
function Read-DotEnvFile {
|
|
10
|
-
param([string]$Path)
|
|
11
|
-
$values = @{}
|
|
12
|
-
if (-not (Test-Path $Path)) { return $values }
|
|
13
|
-
foreach ($line in (Get-Content -Path $Path)) {
|
|
14
|
-
if (-not $line) { continue }
|
|
15
|
-
if ($line.Trim().StartsWith("#")) { continue }
|
|
16
|
-
$parts = $line -split "=", 2
|
|
17
|
-
if ($parts.Count -ne 2) { continue }
|
|
18
|
-
$values[$parts[0].Trim()] = $parts[1]
|
|
19
|
-
}
|
|
20
|
-
return $values
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function Add-Check {
|
|
24
|
-
param(
|
|
25
|
-
[System.Collections.Generic.List[object]]$List,
|
|
26
|
-
[string]$Name,
|
|
27
|
-
[string]$Status,
|
|
28
|
-
[string]$Detail
|
|
29
|
-
)
|
|
30
|
-
$List.Add([pscustomobject]@{
|
|
31
|
-
name = $Name
|
|
32
|
-
status = $Status
|
|
33
|
-
detail = $Detail
|
|
34
|
-
}) | Out-Null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function Test-TelegramTokenFormat {
|
|
38
|
-
param([string]$Value)
|
|
39
|
-
if (-not $Value) { return $false }
|
|
40
|
-
return $Value -match '^\d{6,}:[A-Za-z0-9_-]{20,}$'
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function Test-AllowedChatIdsFormat {
|
|
44
|
-
param([string]$Value)
|
|
45
|
-
if (-not $Value) { return $false }
|
|
46
|
-
$parts = @($Value -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
|
47
|
-
if ($parts.Count -eq 0) { return $false }
|
|
48
|
-
foreach ($part in $parts) {
|
|
49
|
-
if ($part -notmatch '^-?\d+$') {
|
|
50
|
-
return $false
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return $true
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function Get-OverallStatus {
|
|
57
|
-
param([System.Collections.Generic.List[object]]$Checks)
|
|
58
|
-
if (@($Checks | Where-Object { $_.status -eq "fail" }).Count -gt 0) {
|
|
59
|
-
return "fail"
|
|
60
|
-
}
|
|
61
|
-
if (@($Checks | Where-Object { $_.status -eq "warn" }).Count -gt 0) {
|
|
62
|
-
return "warn"
|
|
63
|
-
}
|
|
64
|
-
return "ok"
|
|
65
|
-
}
|
|
66
|
-
|
|
10
|
+
param([string]$Path)
|
|
11
|
+
$values = @{}
|
|
12
|
+
if (-not (Test-Path $Path)) { return $values }
|
|
13
|
+
foreach ($line in (Get-Content -Path $Path)) {
|
|
14
|
+
if (-not $line) { continue }
|
|
15
|
+
if ($line.Trim().StartsWith("#")) { continue }
|
|
16
|
+
$parts = $line -split "=", 2
|
|
17
|
+
if ($parts.Count -ne 2) { continue }
|
|
18
|
+
$values[$parts[0].Trim()] = $parts[1]
|
|
19
|
+
}
|
|
20
|
+
return $values
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Add-Check {
|
|
24
|
+
param(
|
|
25
|
+
[System.Collections.Generic.List[object]]$List,
|
|
26
|
+
[string]$Name,
|
|
27
|
+
[string]$Status,
|
|
28
|
+
[string]$Detail
|
|
29
|
+
)
|
|
30
|
+
$List.Add([pscustomobject]@{
|
|
31
|
+
name = $Name
|
|
32
|
+
status = $Status
|
|
33
|
+
detail = $Detail
|
|
34
|
+
}) | Out-Null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function Test-TelegramTokenFormat {
|
|
38
|
+
param([string]$Value)
|
|
39
|
+
if (-not $Value) { return $false }
|
|
40
|
+
return $Value -match '^\d{6,}:[A-Za-z0-9_-]{20,}$'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function Test-AllowedChatIdsFormat {
|
|
44
|
+
param([string]$Value)
|
|
45
|
+
if (-not $Value) { return $false }
|
|
46
|
+
$parts = @($Value -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
|
47
|
+
if ($parts.Count -eq 0) { return $false }
|
|
48
|
+
foreach ($part in $parts) {
|
|
49
|
+
if ($part -notmatch '^-?\d+$') {
|
|
50
|
+
return $false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return $true
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function Get-OverallStatus {
|
|
57
|
+
param([System.Collections.Generic.List[object]]$Checks)
|
|
58
|
+
if (@($Checks | Where-Object { $_.status -eq "fail" }).Count -gt 0) {
|
|
59
|
+
return "fail"
|
|
60
|
+
}
|
|
61
|
+
if (@($Checks | Where-Object { $_.status -eq "warn" }).Count -gt 0) {
|
|
62
|
+
return "warn"
|
|
63
|
+
}
|
|
64
|
+
return "ok"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
67
|
function Write-DoctorReport {
|
|
68
|
-
param(
|
|
69
|
-
[object]$Result,
|
|
70
|
-
[string]$TokenSource,
|
|
71
|
-
[string]$AllowedChatSource
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
$emoji = switch ($Result.overall) {
|
|
75
|
-
"ok" { "[OK]" }
|
|
76
|
-
"warn" { "[WARN]" }
|
|
77
|
-
default { "[FAIL]" }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
Write-Host ""
|
|
81
|
-
Write-Host "CodexLink Telegram Doctor $emoji" -ForegroundColor Cyan
|
|
82
|
-
Write-Host "Profil: $($Result.profile)"
|
|
83
|
-
Write-Host "State-Ordner: $($Result.state_dir)"
|
|
84
|
-
Write-Host ""
|
|
85
|
-
|
|
86
|
-
foreach ($check in $Result.checks) {
|
|
87
|
-
$prefix = switch ($check.status) {
|
|
88
|
-
"ok" { "[OK]" }
|
|
89
|
-
"warn" { "[WARN]" }
|
|
90
|
-
default { "[FAIL]" }
|
|
91
|
-
}
|
|
92
|
-
$color = switch ($check.status) {
|
|
93
|
-
"ok" { "Green" }
|
|
94
|
-
"warn" { "Yellow" }
|
|
95
|
-
default { "Red" }
|
|
96
|
-
}
|
|
97
|
-
Write-Host "$prefix $($check.name): $($check.detail)" -ForegroundColor $color
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
Write-Host ""
|
|
101
|
-
if ($TokenSource) {
|
|
102
|
-
Write-Host "Bot-Token gefunden aus: $TokenSource" -ForegroundColor DarkGray
|
|
103
|
-
}
|
|
104
|
-
if ($AllowedChatSource) {
|
|
105
|
-
Write-Host "Erlaubte Chat-ID(s) gefunden aus: $AllowedChatSource" -ForegroundColor DarkGray
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
$failed = @($Result.checks | Where-Object { $_.status -eq "fail" })
|
|
109
|
-
if ($failed.Count -gt 0) {
|
|
110
|
-
Write-Host ""
|
|
111
|
-
Write-Host "Was jetzt fehlt:" -ForegroundColor Yellow
|
|
112
|
-
foreach ($item in $failed) {
|
|
113
|
-
switch ($item.name) {
|
|
114
|
-
"bot_token" { Write-Host " - Telegram Bot Token fehlt. Starte: blun-codex --profile $($Result.profile) telegram-setup" }
|
|
68
|
+
param(
|
|
69
|
+
[object]$Result,
|
|
70
|
+
[string]$TokenSource,
|
|
71
|
+
[string]$AllowedChatSource
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
$emoji = switch ($Result.overall) {
|
|
75
|
+
"ok" { "[OK]" }
|
|
76
|
+
"warn" { "[WARN]" }
|
|
77
|
+
default { "[FAIL]" }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
Write-Host ""
|
|
81
|
+
Write-Host "CodexLink Telegram Doctor $emoji" -ForegroundColor Cyan
|
|
82
|
+
Write-Host "Profil: $($Result.profile)"
|
|
83
|
+
Write-Host "State-Ordner: $($Result.state_dir)"
|
|
84
|
+
Write-Host ""
|
|
85
|
+
|
|
86
|
+
foreach ($check in $Result.checks) {
|
|
87
|
+
$prefix = switch ($check.status) {
|
|
88
|
+
"ok" { "[OK]" }
|
|
89
|
+
"warn" { "[WARN]" }
|
|
90
|
+
default { "[FAIL]" }
|
|
91
|
+
}
|
|
92
|
+
$color = switch ($check.status) {
|
|
93
|
+
"ok" { "Green" }
|
|
94
|
+
"warn" { "Yellow" }
|
|
95
|
+
default { "Red" }
|
|
96
|
+
}
|
|
97
|
+
Write-Host "$prefix $($check.name): $($check.detail)" -ForegroundColor $color
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Write-Host ""
|
|
101
|
+
if ($TokenSource) {
|
|
102
|
+
Write-Host "Bot-Token gefunden aus: $TokenSource" -ForegroundColor DarkGray
|
|
103
|
+
}
|
|
104
|
+
if ($AllowedChatSource) {
|
|
105
|
+
Write-Host "Erlaubte Chat-ID(s) gefunden aus: $AllowedChatSource" -ForegroundColor DarkGray
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
$failed = @($Result.checks | Where-Object { $_.status -eq "fail" })
|
|
109
|
+
if ($failed.Count -gt 0) {
|
|
110
|
+
Write-Host ""
|
|
111
|
+
Write-Host "Was jetzt fehlt:" -ForegroundColor Yellow
|
|
112
|
+
foreach ($item in $failed) {
|
|
113
|
+
switch ($item.name) {
|
|
114
|
+
"bot_token" { Write-Host " - Telegram Bot Token fehlt. Starte: blun-codex --profile $($Result.profile) telegram-setup" }
|
|
115
115
|
"allowed_chat_ids" { Write-Host " - Chat-ID ist optional. Zum automatischen Koppeln: blun-codex --profile $($Result.profile) telegram-setup" }
|
|
116
|
-
"state_dir" { Write-Host " - Der lokale Telegram-State-Ordner fehlt noch. Ein Setup-Lauf legt ihn automatisch an." }
|
|
117
|
-
"profile_file" { Write-Host " - Das angegebene Profil existiert nicht." }
|
|
118
|
-
"node" { Write-Host " - Node.js fehlt in PATH." }
|
|
119
|
-
"codex" { Write-Host " - Der lokale codex-Befehl fehlt in PATH." }
|
|
120
|
-
"telegram_plugin_root" { Write-Host " - Der Telegram-Plugin-Ordner konnte nicht gefunden werden." }
|
|
121
|
-
default { Write-Host " - $($item.detail)" }
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if ($Result.overall -eq "ok") {
|
|
127
|
-
Write-Host ""
|
|
128
|
-
Write-Host "Telegram ist sauber eingerichtet." -ForegroundColor Green
|
|
129
|
-
Write-Host "Starten: blun-codex --profile $($Result.profile) telegram-plugin"
|
|
130
|
-
} elseif ($Result.overall -eq "warn") {
|
|
131
|
-
Write-Host ""
|
|
132
|
-
Write-Host "Die Grundkonfiguration steht, aber es gibt noch Laufzeit-Hinweise." -ForegroundColor Yellow
|
|
133
|
-
Write-Host "Das ist oft normal, wenn Telegram noch nicht aktiv gestartet wurde oder noch keine Nachricht durchlief."
|
|
116
|
+
"state_dir" { Write-Host " - Der lokale Telegram-State-Ordner fehlt noch. Ein Setup-Lauf legt ihn automatisch an." }
|
|
117
|
+
"profile_file" { Write-Host " - Das angegebene Profil existiert nicht." }
|
|
118
|
+
"node" { Write-Host " - Node.js fehlt in PATH." }
|
|
119
|
+
"codex" { Write-Host " - Der lokale codex-Befehl fehlt in PATH." }
|
|
120
|
+
"telegram_plugin_root" { Write-Host " - Der Telegram-Plugin-Ordner konnte nicht gefunden werden." }
|
|
121
|
+
default { Write-Host " - $($item.detail)" }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ($Result.overall -eq "ok") {
|
|
127
|
+
Write-Host ""
|
|
128
|
+
Write-Host "Telegram ist sauber eingerichtet." -ForegroundColor Green
|
|
129
|
+
Write-Host "Starten: blun-codex --profile $($Result.profile) telegram-plugin"
|
|
130
|
+
} elseif ($Result.overall -eq "warn") {
|
|
131
|
+
Write-Host ""
|
|
132
|
+
Write-Host "Die Grundkonfiguration steht, aber es gibt noch Laufzeit-Hinweise." -ForegroundColor Yellow
|
|
133
|
+
Write-Host "Das ist oft normal, wenn Telegram noch nicht aktiv gestartet wurde oder noch keine Nachricht durchlief."
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -251,40 +251,40 @@ function Get-ProfilePath {
|
|
|
251
251
|
$runtimeRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
252
252
|
$profilePath = Get-ProfilePath -RuntimeRoot $runtimeRoot -ProfileName $Profile
|
|
253
253
|
$checks = New-Object 'System.Collections.Generic.List[object]'
|
|
254
|
-
|
|
255
|
-
if (Test-Path $profilePath) {
|
|
256
|
-
Add-Check -List $checks -Name "profile_file" -Status "ok" -Detail $profilePath
|
|
257
|
-
} else {
|
|
258
|
-
Add-Check -List $checks -Name "profile_file" -Status "fail" -Detail ("Missing profile: " + $profilePath)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
$statusRaw = & powershell -ExecutionPolicy Bypass -File (Join-Path $runtimeRoot "telegram-status.ps1") -Profile $Profile
|
|
262
|
-
$status = $statusRaw | ConvertFrom-Json
|
|
263
|
-
|
|
264
|
-
$nodeCommand = Get-Command node -ErrorAction SilentlyContinue
|
|
265
|
-
$codexCommand = Get-Command codex -ErrorAction SilentlyContinue
|
|
266
|
-
Add-Check -List $checks -Name "node" -Status $(if ($nodeCommand) { "ok" } else { "fail" }) -Detail $(if ($nodeCommand) { $nodeCommand.Source } else { "node not found in PATH" })
|
|
267
|
-
Add-Check -List $checks -Name "codex" -Status $(if ($codexCommand) { "ok" } else { "fail" }) -Detail $(if ($codexCommand) { $codexCommand.Source } else { "codex not found in PATH" })
|
|
268
|
-
|
|
269
|
-
if ($status.plugin_root) {
|
|
270
|
-
Add-Check -List $checks -Name "telegram_plugin_root" -Status "ok" -Detail $status.plugin_root
|
|
271
|
-
} else {
|
|
272
|
-
Add-Check -List $checks -Name "telegram_plugin_root" -Status "fail" -Detail "Telegram plugin root could not be resolved."
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if ($status.state_dir -and (Test-Path $status.state_dir)) {
|
|
276
|
-
Add-Check -List $checks -Name "state_dir" -Status "ok" -Detail $status.state_dir
|
|
277
|
-
} else {
|
|
278
|
-
Add-Check -List $checks -Name "state_dir" -Status "fail" -Detail ("Missing state dir: " + $status.state_dir)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
$activeEnvPath = Join-Path $status.state_dir ".env"
|
|
282
|
-
$activeEnv = Read-DotEnvFile -Path $activeEnvPath
|
|
283
|
-
$legacyEnvPath = Join-Path $env:USERPROFILE ".codex\channels\codexlink-telegram\.env"
|
|
284
|
-
$legacyEnv = Read-DotEnvFile -Path $legacyEnvPath
|
|
285
|
-
|
|
286
|
-
$tokenValue = ""
|
|
287
|
-
$tokenSource = ""
|
|
254
|
+
|
|
255
|
+
if (Test-Path $profilePath) {
|
|
256
|
+
Add-Check -List $checks -Name "profile_file" -Status "ok" -Detail $profilePath
|
|
257
|
+
} else {
|
|
258
|
+
Add-Check -List $checks -Name "profile_file" -Status "fail" -Detail ("Missing profile: " + $profilePath)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
$statusRaw = & powershell -ExecutionPolicy Bypass -File (Join-Path $runtimeRoot "telegram-status.ps1") -Profile $Profile
|
|
262
|
+
$status = $statusRaw | ConvertFrom-Json
|
|
263
|
+
|
|
264
|
+
$nodeCommand = Get-Command node -ErrorAction SilentlyContinue
|
|
265
|
+
$codexCommand = Get-Command codex -ErrorAction SilentlyContinue
|
|
266
|
+
Add-Check -List $checks -Name "node" -Status $(if ($nodeCommand) { "ok" } else { "fail" }) -Detail $(if ($nodeCommand) { $nodeCommand.Source } else { "node not found in PATH" })
|
|
267
|
+
Add-Check -List $checks -Name "codex" -Status $(if ($codexCommand) { "ok" } else { "fail" }) -Detail $(if ($codexCommand) { $codexCommand.Source } else { "codex not found in PATH" })
|
|
268
|
+
|
|
269
|
+
if ($status.plugin_root) {
|
|
270
|
+
Add-Check -List $checks -Name "telegram_plugin_root" -Status "ok" -Detail $status.plugin_root
|
|
271
|
+
} else {
|
|
272
|
+
Add-Check -List $checks -Name "telegram_plugin_root" -Status "fail" -Detail "Telegram plugin root could not be resolved."
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if ($status.state_dir -and (Test-Path $status.state_dir)) {
|
|
276
|
+
Add-Check -List $checks -Name "state_dir" -Status "ok" -Detail $status.state_dir
|
|
277
|
+
} else {
|
|
278
|
+
Add-Check -List $checks -Name "state_dir" -Status "fail" -Detail ("Missing state dir: " + $status.state_dir)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
$activeEnvPath = Join-Path $status.state_dir ".env"
|
|
282
|
+
$activeEnv = Read-DotEnvFile -Path $activeEnvPath
|
|
283
|
+
$legacyEnvPath = Join-Path $env:USERPROFILE ".codex\channels\codexlink-telegram\.env"
|
|
284
|
+
$legacyEnv = Read-DotEnvFile -Path $legacyEnvPath
|
|
285
|
+
|
|
286
|
+
$tokenValue = ""
|
|
287
|
+
$tokenSource = ""
|
|
288
288
|
if (Test-TelegramTokenFormat -Value $activeEnv["BLUN_TELEGRAM_BOT_TOKEN"]) {
|
|
289
289
|
$tokenValue = [string]$activeEnv["BLUN_TELEGRAM_BOT_TOKEN"]
|
|
290
290
|
$tokenSource = "state env"
|
|
@@ -298,10 +298,10 @@ if (Test-TelegramTokenFormat -Value $activeEnv["BLUN_TELEGRAM_BOT_TOKEN"]) {
|
|
|
298
298
|
$tokenValue = [string]$legacyEnv["TELEGRAM_BOT_TOKEN"]
|
|
299
299
|
$tokenSource = "legacy env fallback legacy key"
|
|
300
300
|
}
|
|
301
|
-
Add-Check -List $checks -Name "bot_token" -Status $(if ($tokenValue) { "ok" } else { "fail" }) -Detail $(if ($tokenValue) { $tokenSource } else { "No valid BLUN_TELEGRAM_BOT_TOKEN found." })
|
|
302
|
-
|
|
303
|
-
$allowedChatIds = ""
|
|
304
|
-
$allowedChatSource = ""
|
|
301
|
+
Add-Check -List $checks -Name "bot_token" -Status $(if ($tokenValue) { "ok" } else { "fail" }) -Detail $(if ($tokenValue) { $tokenSource } else { "No valid BLUN_TELEGRAM_BOT_TOKEN found." })
|
|
302
|
+
|
|
303
|
+
$allowedChatIds = ""
|
|
304
|
+
$allowedChatSource = ""
|
|
305
305
|
if (Test-AllowedChatIdsFormat -Value $activeEnv["BLUN_TELEGRAM_ALLOWED_CHAT_ID"]) {
|
|
306
306
|
$allowedChatIds = [string]$activeEnv["BLUN_TELEGRAM_ALLOWED_CHAT_ID"]
|
|
307
307
|
$allowedChatSource = "state env"
|
|
@@ -316,7 +316,7 @@ if (Test-AllowedChatIdsFormat -Value $activeEnv["BLUN_TELEGRAM_ALLOWED_CHAT_ID"]
|
|
|
316
316
|
$allowedChatSource = "legacy env fallback legacy key"
|
|
317
317
|
}
|
|
318
318
|
Add-Check -List $checks -Name "allowed_chat_ids" -Status $(if ($allowedChatIds) { "ok" } else { "warn" }) -Detail $(if ($allowedChatIds) { $allowedChatIds } else { "No allowlist set. Telegram currently accepts any chat the bot can see." })
|
|
319
|
-
|
|
319
|
+
|
|
320
320
|
Add-Check -List $checks -Name "app_server_ws" -Status $(if ($status.active_ws) { "ok" } else { "warn" }) -Detail $(if ($status.active_ws) { $status.active_ws } else { "No active websocket recorded." })
|
|
321
321
|
Add-Check -List $checks -Name "dispatch_mode" -Status $(if ($status.dispatch_mode -eq "deferred") { "ok" } else { "warn" }) -Detail ("mode=" + [string]$status.dispatch_mode + " cooldown_ms=" + [string]$status.idle_cooldown_ms + " pending_reply_timeout_ms=" + [string]$status.pending_reply_timeout_ms)
|
|
322
322
|
Add-Check -List $checks -Name "bound_thread" -Status $(if ($status.active_thread_id) { "ok" } else { "warn" }) -Detail $(if ($status.active_thread_id) { $status.active_thread_id } else { "No active thread bound yet." })
|
|
@@ -336,42 +336,42 @@ Add-Check -List $checks -Name "queue_notifier" -Status $(if (($null -eq $status.
|
|
|
336
336
|
Add-Check -List $checks -Name "poller" -Status $(if ($status.poller_alive) { "ok" } else { "warn" }) -Detail ("pid=" + [string]$status.poller_pid + " alive=" + [string]$status.poller_alive)
|
|
337
337
|
Add-Check -List $checks -Name "dispatcher" -Status $(if ($status.dispatcher_alive) { "ok" } else { "warn" }) -Detail ("pid=" + [string]$status.dispatcher_pid + " alive=" + [string]$status.dispatcher_alive)
|
|
338
338
|
Add-Check -List $checks -Name "responder" -Status $(if ($status.responder_alive) { "ok" } else { "warn" }) -Detail ("pid=" + [string]$status.responder_pid + " alive=" + [string]$status.responder_alive)
|
|
339
|
-
|
|
340
|
-
if ($status.last_inbound) {
|
|
341
|
-
$lastInboundSummary = [string]::Format(
|
|
342
|
-
"chat={0} message={1} type={2} thread={3}",
|
|
343
|
-
$status.last_inbound.chatId,
|
|
344
|
-
$status.last_inbound.messageId,
|
|
345
|
-
$status.last_inbound.chatType,
|
|
346
|
-
$(if ($status.last_inbound.telegramThreadId) { $status.last_inbound.telegramThreadId } else { "-" })
|
|
347
|
-
)
|
|
348
|
-
Add-Check -List $checks -Name "last_inbound" -Status "ok" -Detail $lastInboundSummary
|
|
349
|
-
} else {
|
|
350
|
-
Add-Check -List $checks -Name "last_inbound" -Status "warn" -Detail "No inbound Telegram message recorded yet."
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
if ($status.last_outbound) {
|
|
354
|
-
$lastOutboundSummary = [string]::Format(
|
|
355
|
-
"chat={0} message={1} reply_to={2} thread={3}",
|
|
356
|
-
$status.last_outbound.chatId,
|
|
357
|
-
$status.last_outbound.messageId,
|
|
358
|
-
$(if ($status.last_outbound.replyToMessageId) { $status.last_outbound.replyToMessageId } else { "-" }),
|
|
359
|
-
$(if ($status.last_outbound.telegramThreadId) { $status.last_outbound.telegramThreadId } else { "-" })
|
|
360
|
-
)
|
|
361
|
-
Add-Check -List $checks -Name "last_outbound" -Status "ok" -Detail $lastOutboundSummary
|
|
362
|
-
} else {
|
|
363
|
-
Add-Check -List $checks -Name "last_outbound" -Status "warn" -Detail "No outbound Telegram message recorded yet."
|
|
364
|
-
}
|
|
365
|
-
|
|
339
|
+
|
|
340
|
+
if ($status.last_inbound) {
|
|
341
|
+
$lastInboundSummary = [string]::Format(
|
|
342
|
+
"chat={0} message={1} type={2} thread={3}",
|
|
343
|
+
$status.last_inbound.chatId,
|
|
344
|
+
$status.last_inbound.messageId,
|
|
345
|
+
$status.last_inbound.chatType,
|
|
346
|
+
$(if ($status.last_inbound.telegramThreadId) { $status.last_inbound.telegramThreadId } else { "-" })
|
|
347
|
+
)
|
|
348
|
+
Add-Check -List $checks -Name "last_inbound" -Status "ok" -Detail $lastInboundSummary
|
|
349
|
+
} else {
|
|
350
|
+
Add-Check -List $checks -Name "last_inbound" -Status "warn" -Detail "No inbound Telegram message recorded yet."
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if ($status.last_outbound) {
|
|
354
|
+
$lastOutboundSummary = [string]::Format(
|
|
355
|
+
"chat={0} message={1} reply_to={2} thread={3}",
|
|
356
|
+
$status.last_outbound.chatId,
|
|
357
|
+
$status.last_outbound.messageId,
|
|
358
|
+
$(if ($status.last_outbound.replyToMessageId) { $status.last_outbound.replyToMessageId } else { "-" }),
|
|
359
|
+
$(if ($status.last_outbound.telegramThreadId) { $status.last_outbound.telegramThreadId } else { "-" })
|
|
360
|
+
)
|
|
361
|
+
Add-Check -List $checks -Name "last_outbound" -Status "ok" -Detail $lastOutboundSummary
|
|
362
|
+
} else {
|
|
363
|
+
Add-Check -List $checks -Name "last_outbound" -Status "warn" -Detail "No outbound Telegram message recorded yet."
|
|
364
|
+
}
|
|
365
|
+
|
|
366
366
|
Add-Check -List $checks -Name "queue" -Status $(if (([int]$status.queue_depth -eq 0) -and ([int]$status.pending_reply_depth -eq 0)) { "ok" } else { "warn" }) -Detail ("queued=" + $status.queue_depth + " ambient=" + $status.ambient_queue_depth + " parked=" + $status.parked_queue_depth + " submitted=" + $status.submitted_depth + " pending_replies=" + $status.pending_reply_depth + " expired_pending_replies=" + $status.expired_pending_reply_depth)
|
|
367
|
-
|
|
367
|
+
|
|
368
368
|
$result = [ordered]@{
|
|
369
|
-
profile = $status.profile
|
|
370
|
-
overall = Get-OverallStatus -Checks $checks
|
|
371
|
-
runtime_root = $runtimeRoot
|
|
372
|
-
state_dir = $status.state_dir
|
|
373
|
-
plugin_root = $status.plugin_root
|
|
374
|
-
checks = $checks
|
|
369
|
+
profile = $status.profile
|
|
370
|
+
overall = Get-OverallStatus -Checks $checks
|
|
371
|
+
runtime_root = $runtimeRoot
|
|
372
|
+
state_dir = $status.state_dir
|
|
373
|
+
plugin_root = $status.plugin_root
|
|
374
|
+
checks = $checks
|
|
375
375
|
status = $status
|
|
376
376
|
}
|
|
377
377
|
|
|
@@ -390,10 +390,10 @@ if ($Fix) {
|
|
|
390
390
|
}
|
|
391
391
|
exit 0
|
|
392
392
|
}
|
|
393
|
-
|
|
394
|
-
if ($Json) {
|
|
395
|
-
$result | ConvertTo-Json -Depth 8
|
|
396
|
-
exit 0
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
Write-DoctorReport -Result $result -TokenSource $tokenSource -AllowedChatSource $allowedChatSource
|
|
393
|
+
|
|
394
|
+
if ($Json) {
|
|
395
|
+
$result | ConvertTo-Json -Depth 8
|
|
396
|
+
exit 0
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
Write-DoctorReport -Result $result -TokenSource $tokenSource -AllowedChatSource $allowedChatSource
|
|
@@ -79,6 +79,10 @@ function containsToken(text, token) {
|
|
|
79
79
|
return new RegExp(`(^|[^a-z0-9_])${escaped}([^a-z0-9_]|$)`, "i").test(String(text || ""));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function shouldAckOnlyAddressPing() {
|
|
83
|
+
return String(process.env.BLUN_TELEGRAM_PING_ACK_ONLY || "").trim() === "1";
|
|
84
|
+
}
|
|
85
|
+
|
|
82
86
|
function looksLikeEscalation(text) {
|
|
83
87
|
const value = foldTriggerText(text);
|
|
84
88
|
if (!value) {
|
|
@@ -445,6 +449,10 @@ function isAgentAddressed(config, text) {
|
|
|
445
449
|
if (workDirective) {
|
|
446
450
|
return true;
|
|
447
451
|
}
|
|
452
|
+
|
|
453
|
+
if (containsToken(normalized, name)) {
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
448
456
|
}
|
|
449
457
|
|
|
450
458
|
return false;
|
|
@@ -2270,6 +2278,11 @@ function isRealtimeAppServerEntry(entry) {
|
|
|
2270
2278
|
return chatType === "private" || relevance === "direct" || relevance === "lane";
|
|
2271
2279
|
}
|
|
2272
2280
|
|
|
2281
|
+
function isGroupChatEntry(entry) {
|
|
2282
|
+
const chatType = String(entry?.chatType || "").trim().toLowerCase();
|
|
2283
|
+
return chatType === "group" || chatType === "supergroup";
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2273
2286
|
export async function injectNext(threadId, options = {}) {
|
|
2274
2287
|
const config = loadConfig();
|
|
2275
2288
|
const state = loadState(config);
|
|
@@ -2313,7 +2326,7 @@ export async function injectNext(threadId, options = {}) {
|
|
|
2313
2326
|
};
|
|
2314
2327
|
}
|
|
2315
2328
|
|
|
2316
|
-
if (isAddressOnlyPing(config, next.text) && !looksLikeBotSender(next)) {
|
|
2329
|
+
if (shouldAckOnlyAddressPing() && isAddressOnlyPing(config, next.text) && !looksLikeBotSender(next) && !isGroupChatEntry(next)) {
|
|
2317
2330
|
next.status = "delivered";
|
|
2318
2331
|
next.deliveredAt = nowIso();
|
|
2319
2332
|
next.threadId = null;
|
|
@@ -55,31 +55,31 @@ export function saveJson(path, value) {
|
|
|
55
55
|
|
|
56
56
|
throw lastError || new Error(`Failed to save JSON file: ${path}`);
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
export function appendJsonl(path, value) {
|
|
60
|
-
appendFileSync(path, `${JSON.stringify(value)}\n`, "utf8");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function appendLog(path, message) {
|
|
64
|
-
appendFileSync(path, `${nowIso()} ${message}\n`, "utf8");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function readTail(path, lines = 20) {
|
|
68
|
-
if (!existsSync(path)) {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
const text = readFileSync(path, "utf8");
|
|
72
|
-
return text.split(/\r?\n/).filter(Boolean).slice(-lines);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function defaultState() {
|
|
76
|
-
return {
|
|
77
|
-
offset: 0,
|
|
78
|
-
currentThreadId: "",
|
|
79
|
-
queue: [],
|
|
80
|
-
pendingReplies: [],
|
|
81
|
-
replyOffsets: {},
|
|
82
|
-
replyBuffers: {},
|
|
58
|
+
|
|
59
|
+
export function appendJsonl(path, value) {
|
|
60
|
+
appendFileSync(path, `${JSON.stringify(value)}\n`, "utf8");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function appendLog(path, message) {
|
|
64
|
+
appendFileSync(path, `${nowIso()} ${message}\n`, "utf8");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function readTail(path, lines = 20) {
|
|
68
|
+
if (!existsSync(path)) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const text = readFileSync(path, "utf8");
|
|
72
|
+
return text.split(/\r?\n/).filter(Boolean).slice(-lines);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function defaultState() {
|
|
76
|
+
return {
|
|
77
|
+
offset: 0,
|
|
78
|
+
currentThreadId: "",
|
|
79
|
+
queue: [],
|
|
80
|
+
pendingReplies: [],
|
|
81
|
+
replyOffsets: {},
|
|
82
|
+
replyBuffers: {},
|
|
83
83
|
lastInbound: null,
|
|
84
84
|
lastOutbound: null,
|
|
85
85
|
lastUiNotice: null,
|