@blunking/codexlink 0.1.18 → 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.
@@ -7,7 +7,7 @@ param(
7
7
 
8
8
  [string]$LogFile = ""
9
9
  )
10
-
10
+
11
11
  $ErrorActionPreference = "SilentlyContinue"
12
12
 
13
13
  function Stop-EmbeddedQueueTitleWatcher {
@@ -35,9 +35,9 @@ Stop-EmbeddedQueueTitleWatcher -TypeName "BlunEmbeddedQueueTitleWatcherQueueOnly
35
35
  if (-not ("BlunEmbeddedQueueTitleWatcherQueueOnlyV2" -as [type])) {
36
36
  Add-Type -ReferencedAssemblies "System.Web.Extensions" -TypeDefinition @"
37
37
  using System;
38
- using System.Collections;
39
- using System.Collections.Generic;
40
- using System.IO;
38
+ using System.Collections;
39
+ using System.Collections.Generic;
40
+ using System.IO;
41
41
  using System.Threading;
42
42
  using System.Web.Script.Serialization;
43
43
 
@@ -74,14 +74,14 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
74
74
  TrySetTitle(_baseTitle);
75
75
  if (_timer != null)
76
76
  {
77
- _timer.Dispose();
78
- }
79
- _timer = new Timer(_ => Tick(), null, 0, 900);
80
- }
81
- }
82
-
83
- private static void Tick()
84
- {
77
+ _timer.Dispose();
78
+ }
79
+ _timer = new Timer(_ => Tick(), null, 0, 900);
80
+ }
81
+ }
82
+
83
+ private static void Tick()
84
+ {
85
85
  try
86
86
  {
87
87
  string title;
@@ -117,15 +117,15 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
117
117
  WriteLog("TITLE_ERROR");
118
118
  }
119
119
  }
120
-
121
- private static void TryWriteNotice(string notice)
122
- {
123
- var normalized = notice ?? "";
124
- if (string.Equals(normalized, _lastNotice, StringComparison.Ordinal))
125
- {
126
- return;
127
- }
128
-
120
+
121
+ private static void TryWriteNotice(string notice)
122
+ {
123
+ var normalized = notice ?? "";
124
+ if (string.Equals(normalized, _lastNotice, StringComparison.Ordinal))
125
+ {
126
+ return;
127
+ }
128
+
129
129
  try
130
130
  {
131
131
  // Do not write background queue notices into the interactive Codex
@@ -275,13 +275,13 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
275
275
  {
276
276
  return;
277
277
  }
278
-
279
- var raw = File.ReadAllText(_stateFile);
280
- if (string.IsNullOrWhiteSpace(raw))
281
- {
282
- return;
283
- }
284
-
278
+
279
+ var raw = File.ReadAllText(_stateFile);
280
+ if (string.IsNullOrWhiteSpace(raw))
281
+ {
282
+ return;
283
+ }
284
+
285
285
  var serializer = new JavaScriptSerializer();
286
286
  var root = serializer.DeserializeObject(raw) as Dictionary<string, object>;
287
287
  if (root == null || !root.ContainsKey("queue"))
@@ -311,20 +311,20 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
311
311
  var entry = item as Dictionary<string, object>;
312
312
  if (entry == null)
313
313
  {
314
- continue;
315
- }
316
-
317
- var status = GetString(entry, "status");
318
- if (!string.Equals(status, "queued", StringComparison.OrdinalIgnoreCase))
319
- {
320
- continue;
321
- }
322
-
323
- var relevance = GetString(entry, "relevance");
324
- if (string.Equals(relevance, "ambient", StringComparison.OrdinalIgnoreCase) && IsOlderThan(entry, _ambientTtlMs))
325
- {
326
- continue;
327
- }
314
+ continue;
315
+ }
316
+
317
+ var status = GetString(entry, "status");
318
+ if (!string.Equals(status, "queued", StringComparison.OrdinalIgnoreCase))
319
+ {
320
+ continue;
321
+ }
322
+
323
+ var relevance = GetString(entry, "relevance");
324
+ if (string.Equals(relevance, "ambient", StringComparison.OrdinalIgnoreCase) && IsOlderThan(entry, _ambientTtlMs))
325
+ {
326
+ continue;
327
+ }
328
328
 
329
329
  total += 1;
330
330
  CountRelevance(entry, ref direct, ref ambient, ref escalation);
@@ -337,8 +337,8 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
337
337
 
338
338
  if (total == 0)
339
339
  {
340
- return;
341
- }
340
+ return;
341
+ }
342
342
 
343
343
  var parts = new List<string> { "Q:" + total.ToString() };
344
344
  if (direct > 0) parts.Add("D:" + direct.ToString());
@@ -351,15 +351,15 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
351
351
  if (direct > 0) noticeParts.Add("direct " + direct.ToString());
352
352
  if (ambient > 0) noticeParts.Add("group " + ambient.ToString());
353
353
  if (escalation > 0) noticeParts.Add("escalation " + escalation.ToString());
354
- notice = string.Join(" | ", noticeParts.ToArray());
355
- if (string.IsNullOrWhiteSpace(preview))
356
- {
357
- return;
358
- }
354
+ notice = string.Join(" | ", noticeParts.ToArray());
355
+ if (string.IsNullOrWhiteSpace(preview))
356
+ {
357
+ return;
358
+ }
359
359
  title = title + " | " + preview;
360
360
  notice = notice + " | " + preview;
361
- }
362
-
361
+ }
362
+
363
363
  private static object[] AsObjects(object value)
364
364
  {
365
365
  var arr = value as object[];
@@ -372,16 +372,16 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
372
372
  {
373
373
  return list.ToArray();
374
374
  }
375
- return new object[0];
376
- }
377
-
375
+ return new object[0];
376
+ }
377
+
378
378
  private static string GetString(Dictionary<string, object> entry, string key)
379
379
  {
380
- if (!entry.ContainsKey(key) || entry[key] == null)
381
- {
382
- return "";
383
- }
384
- return Convert.ToString(entry[key]) ?? "";
380
+ if (!entry.ContainsKey(key) || entry[key] == null)
381
+ {
382
+ return "";
383
+ }
384
+ return Convert.ToString(entry[key]) ?? "";
385
385
  }
386
386
 
387
387
  private static void CountRelevance(Dictionary<string, object> entry, ref int direct, ref int ambient, ref int escalation)
@@ -436,7 +436,7 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
436
436
  }
437
437
  return state + text;
438
438
  }
439
-
439
+
440
440
  private static string Normalize(string value, int maxLength)
441
441
  {
442
442
  if (string.IsNullOrWhiteSpace(value))
@@ -449,11 +449,11 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
449
449
  {
450
450
  compact = compact.Replace(" ", " ");
451
451
  }
452
-
453
- if (compact.Length <= maxLength)
454
- {
455
- return compact;
456
- }
452
+
453
+ if (compact.Length <= maxLength)
454
+ {
455
+ return compact;
456
+ }
457
457
 
458
458
  return compact.Substring(0, Math.Max(0, maxLength - 3)).TrimEnd() + "...";
459
459
  }
@@ -483,21 +483,21 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
483
483
  .Replace("ü", "ü")
484
484
  .Replace("ß", "ß");
485
485
  }
486
-
486
+
487
487
  private static bool IsOlderThan(Dictionary<string, object> entry, long ttlMs)
488
488
  {
489
- if (!entry.ContainsKey("ts") || entry["ts"] == null)
490
- {
491
- return true;
492
- }
493
- try
494
- {
495
- var parsed = DateTimeOffset.Parse(Convert.ToString(entry["ts"]) ?? "");
496
- return (DateTimeOffset.UtcNow - parsed.ToUniversalTime()).TotalMilliseconds >= ttlMs;
497
- }
498
- catch
499
- {
500
- return true;
489
+ if (!entry.ContainsKey("ts") || entry["ts"] == null)
490
+ {
491
+ return true;
492
+ }
493
+ try
494
+ {
495
+ var parsed = DateTimeOffset.Parse(Convert.ToString(entry["ts"]) ?? "");
496
+ return (DateTimeOffset.UtcNow - parsed.ToUniversalTime()).TotalMilliseconds >= ttlMs;
497
+ }
498
+ catch
499
+ {
500
+ return true;
501
501
  }
502
502
  }
503
503
 
@@ -518,24 +518,24 @@ public static class BlunEmbeddedQueueTitleWatcherQueueOnlyV2
518
518
  }
519
519
  "@
520
520
  }
521
-
522
- $ambientTtlMs = 600000
523
- try {
524
- $stateDir = Split-Path -Parent $StateFile
525
- $envPath = Join-Path $stateDir ".env"
526
- if (Test-Path $envPath) {
527
- foreach ($line in (Get-Content -Path $envPath)) {
528
- if (-not $line) { continue }
529
- if ($line.Trim().StartsWith("#")) { continue }
530
- $parts = $line -split "=", 2
531
- if ($parts.Count -ne 2) { continue }
532
- if ($parts[0].Trim() -eq "BLUN_TELEGRAM_AMBIENT_QUEUE_TTL_MS") {
533
- $ambientTtlMs = [int64]$parts[1].Trim()
534
- }
535
- }
536
- }
537
- } catch {
538
- $ambientTtlMs = 600000
539
- }
540
-
521
+
522
+ $ambientTtlMs = 600000
523
+ try {
524
+ $stateDir = Split-Path -Parent $StateFile
525
+ $envPath = Join-Path $stateDir ".env"
526
+ if (Test-Path $envPath) {
527
+ foreach ($line in (Get-Content -Path $envPath)) {
528
+ if (-not $line) { continue }
529
+ if ($line.Trim().StartsWith("#")) { continue }
530
+ $parts = $line -split "=", 2
531
+ if ($parts.Count -ne 2) { continue }
532
+ if ($parts[0].Trim() -eq "BLUN_TELEGRAM_AMBIENT_QUEUE_TTL_MS") {
533
+ $ambientTtlMs = [int64]$parts[1].Trim()
534
+ }
535
+ }
536
+ }
537
+ } catch {
538
+ $ambientTtlMs = 600000
539
+ }
540
+
541
541
  [BlunEmbeddedQueueTitleWatcherQueueOnlyV2]::Start($StateFile, $BaseTitle, $ambientTtlMs, $LogFile)
@@ -6,18 +6,18 @@ param(
6
6
 
7
7
  [Parameter(Mandatory = $true)]
8
8
  [string]$RuntimeFile,
9
-
10
- [Parameter(Mandatory = $true)]
11
- [string]$StateFile,
12
-
13
- [Parameter(Mandatory = $true)]
14
- [string]$BaseTitle,
15
-
16
- [string]$LogFile = ""
17
- )
18
-
19
- $ErrorActionPreference = "SilentlyContinue"
20
-
9
+
10
+ [Parameter(Mandatory = $true)]
11
+ [string]$StateFile,
12
+
13
+ [Parameter(Mandatory = $true)]
14
+ [string]$BaseTitle,
15
+
16
+ [string]$LogFile = ""
17
+ )
18
+
19
+ $ErrorActionPreference = "SilentlyContinue"
20
+
21
21
  if (-not ("CodexLink.NativeMethods" -as [type])) {
22
22
  Add-Type -TypeDefinition @"
23
23
  using System;
@@ -45,28 +45,28 @@ namespace CodexLink
45
45
  }
46
46
  "@
47
47
  }
48
-
49
- function Try-ReadJson {
50
- param([string]$Path)
51
- if (-not (Test-Path $Path)) { return $null }
52
- try {
53
- $raw = Get-Content -Raw -Path $Path
54
- if ($null -eq $raw) { return $null }
55
- return ($raw -replace "^\uFEFF", "") | ConvertFrom-Json
56
- } catch {
57
- return $null
58
- }
59
- }
60
-
61
- function Write-WatcherLog {
62
- param([string]$Message)
63
- if (-not $LogFile) { return }
64
- try {
65
- Add-Content -Path $LogFile -Value (((Get-Date).ToUniversalTime().ToString("o")) + " " + $Message) -Encoding UTF8
66
- } catch {
67
- }
68
- }
69
-
48
+
49
+ function Try-ReadJson {
50
+ param([string]$Path)
51
+ if (-not (Test-Path $Path)) { return $null }
52
+ try {
53
+ $raw = Get-Content -Raw -Path $Path
54
+ if ($null -eq $raw) { return $null }
55
+ return ($raw -replace "^\uFEFF", "") | ConvertFrom-Json
56
+ } catch {
57
+ return $null
58
+ }
59
+ }
60
+
61
+ function Write-WatcherLog {
62
+ param([string]$Message)
63
+ if (-not $LogFile) { return }
64
+ try {
65
+ Add-Content -Path $LogFile -Value (((Get-Date).ToUniversalTime().ToString("o")) + " " + $Message) -Encoding UTF8
66
+ } catch {
67
+ }
68
+ }
69
+
70
70
  function Test-PidAlive {
71
71
  param([int]$ProcId)
72
72
  if ($ProcId -le 0) { return $false }
@@ -103,14 +103,14 @@ function Get-EffectiveAttachPid {
103
103
 
104
104
  return 0
105
105
  }
106
-
106
+
107
107
  function Normalize-Preview {
108
108
  param([string]$Value, [int]$MaxLength = 44)
109
- $text = [string]$Value
110
- $text = $text -replace "\s+", " "
111
- $text = $text.Trim()
112
- if (-not $text) { return "" }
113
- if ($text.Length -le $MaxLength) { return $text }
109
+ $text = [string]$Value
110
+ $text = $text -replace "\s+", " "
111
+ $text = $text.Trim()
112
+ if (-not $text) { return "" }
113
+ if ($text.Length -le $MaxLength) { return $text }
114
114
  return ($text.Substring(0, [Math]::Max(0, $MaxLength - 3)).TrimEnd() + "...")
115
115
  }
116
116
 
@@ -178,18 +178,18 @@ function Format-QueuePreview {
178
178
  }
179
179
  return "${prefix}${text}"
180
180
  }
181
-
181
+
182
182
  function Get-QueueTitle {
183
183
  param(
184
184
  [object]$State,
185
185
  [string]$FallbackTitle,
186
186
  [int]$IdleCooldownMs = 15000
187
187
  )
188
-
189
- if ($null -eq $State -or $null -eq $State.queue) {
190
- return $FallbackTitle
191
- }
192
-
188
+
189
+ if ($null -eq $State -or $null -eq $State.queue) {
190
+ return $FallbackTitle
191
+ }
192
+
193
193
  $queued = @($State.queue | Where-Object { $_.status -eq "queued" })
194
194
  if ($queued.Count -eq 0) {
195
195
  return $FallbackTitle
@@ -208,7 +208,7 @@ function Get-QueueTitle {
208
208
  if ($directCount -gt 0) { $parts += "D:$directCount" }
209
209
  if ($ambientCount -gt 0) { $parts += "G:$ambientCount" }
210
210
  if ($escalationCount -gt 0) { $parts += "E:$escalationCount" }
211
-
211
+
212
212
  $summary = ($parts -join " ")
213
213
  $waitReason = Get-QueueWaitReason -State $State -IdleCooldownMs $IdleCooldownMs
214
214
  if ($preview) {
@@ -216,7 +216,7 @@ function Get-QueueTitle {
216
216
  }
217
217
  return "$FallbackTitle | $summary | $waitReason"
218
218
  }
219
-
219
+
220
220
  function Update-ConsoleTitle {
221
221
  param([string]$Title)
222
222
  try {
@@ -230,11 +230,11 @@ function Update-ConsoleTitle {
230
230
  $updated = [CodexLink.NativeMethods]::SetConsoleTitle($Title)
231
231
  [void][CodexLink.NativeMethods]::FreeConsole()
232
232
  return $updated
233
- } catch {
234
- return $false
235
- }
236
- }
237
-
233
+ } catch {
234
+ return $false
235
+ }
236
+ }
237
+
238
238
  function Write-ConsoleNotice {
239
239
  param([string]$Notice)
240
240
  if ($env:BLUN_TELEGRAM_CONSOLE_NOTICES -ne "1") {
@@ -248,15 +248,15 @@ function Write-ConsoleNotice {
248
248
  Write-WatcherLog ("WAIT attach_console_failed_notice target=" + $targetPid)
249
249
  return $false
250
250
  }
251
- $handle = [CodexLink.NativeMethods]::GetStdHandle(-11)
252
- if ($handle -eq [IntPtr]::Zero -or $handle -eq [IntPtr](-1)) {
253
- [void][CodexLink.NativeMethods]::FreeConsole()
254
- return $false
255
- }
256
- $line = "[CodexLink Queue] $Notice`r`n"
257
- [uint32]$written = 0
258
- $ok = [CodexLink.NativeMethods]::WriteConsole($handle, $line, [uint32]$line.Length, [ref]$written, [IntPtr]::Zero)
259
- [void][CodexLink.NativeMethods]::FreeConsole()
251
+ $handle = [CodexLink.NativeMethods]::GetStdHandle(-11)
252
+ if ($handle -eq [IntPtr]::Zero -or $handle -eq [IntPtr](-1)) {
253
+ [void][CodexLink.NativeMethods]::FreeConsole()
254
+ return $false
255
+ }
256
+ $line = "[CodexLink Queue] $Notice`r`n"
257
+ [uint32]$written = 0
258
+ $ok = [CodexLink.NativeMethods]::WriteConsole($handle, $line, [uint32]$line.Length, [ref]$written, [IntPtr]::Zero)
259
+ [void][CodexLink.NativeMethods]::FreeConsole()
260
260
  return $ok
261
261
  } catch {
262
262
  return $false
@@ -320,17 +320,17 @@ function Get-UiNoticeSnapshot {
320
320
  text = $text
321
321
  }
322
322
  }
323
-
323
+
324
324
  function Get-QueueNotice {
325
325
  param(
326
326
  [object]$State,
327
327
  [int]$IdleCooldownMs = 15000
328
328
  )
329
-
330
- if ($null -eq $State -or $null -eq $State.queue) {
331
- return ""
332
- }
333
-
329
+
330
+ if ($null -eq $State -or $null -eq $State.queue) {
331
+ return ""
332
+ }
333
+
334
334
  $queued = @($State.queue | Where-Object { $_.status -eq "queued" })
335
335
  if ($queued.Count -eq 0) {
336
336
  return ""
@@ -357,7 +357,7 @@ function Get-QueueNotice {
357
357
  $parts += $preview
358
358
  }
359
359
  }
360
-
360
+
361
361
  return ($parts -join " | ")
362
362
  }
363
363
 
@@ -388,48 +388,48 @@ $lastNotice = ""
388
388
  $lastUiKind = ""
389
389
  $lastUiNotice = ""
390
390
  Write-WatcherLog "START"
391
-
392
- while ($true) {
393
- if (-not (Test-PidAlive -ProcId $FrontendPid)) {
394
- Write-WatcherLog "EXIT frontend_dead"
395
- break
396
- }
397
-
398
- $runtime = Try-ReadJson -Path $RuntimeFile
399
- if ($null -eq $runtime) {
400
- Write-WatcherLog "WAIT runtime_missing"
401
- Start-Sleep -Milliseconds 300
402
- continue
403
- }
404
-
405
- $runtimeOwnerPid = 0
406
- try { $runtimeOwnerPid = [int]$runtime.frontend_host_pid } catch { $runtimeOwnerPid = 0 }
407
- if ($runtimeOwnerPid -ne $FrontendPid) {
408
- Write-WatcherLog ("EXIT owner_changed owner=" + $runtimeOwnerPid)
409
- break
410
- }
411
-
391
+
392
+ while ($true) {
393
+ if (-not (Test-PidAlive -ProcId $FrontendPid)) {
394
+ Write-WatcherLog "EXIT frontend_dead"
395
+ break
396
+ }
397
+
398
+ $runtime = Try-ReadJson -Path $RuntimeFile
399
+ if ($null -eq $runtime) {
400
+ Write-WatcherLog "WAIT runtime_missing"
401
+ Start-Sleep -Milliseconds 300
402
+ continue
403
+ }
404
+
405
+ $runtimeOwnerPid = 0
406
+ try { $runtimeOwnerPid = [int]$runtime.frontend_host_pid } catch { $runtimeOwnerPid = 0 }
407
+ if ($runtimeOwnerPid -ne $FrontendPid) {
408
+ Write-WatcherLog ("EXIT owner_changed owner=" + $runtimeOwnerPid)
409
+ break
410
+ }
411
+
412
412
  $state = Try-ReadJson -Path $StateFile
413
413
  if ($null -eq $state) {
414
414
  Write-WatcherLog "WAIT state_missing"
415
- Start-Sleep -Milliseconds 700
416
- continue
417
- }
418
-
415
+ Start-Sleep -Milliseconds 700
416
+ continue
417
+ }
418
+
419
419
  $title = Get-QueueTitle -State $state -FallbackTitle $BaseTitle -IdleCooldownMs $idleCooldownMs
420
420
  $notice = Get-QueueNotice -State $state -IdleCooldownMs $idleCooldownMs
421
421
  $ui = Get-UiNoticeSnapshot -State $state
422
422
  if ($title -ne $lastTitle) {
423
423
  $updated = Update-ConsoleTitle -Title $title
424
424
  Write-WatcherLog ("TITLE updated=" + $updated + " text=" + $title)
425
- $lastTitle = $title
426
- }
427
- if ($notice -ne $lastNotice) {
428
- if ($notice) {
429
- $noticeUpdated = Write-ConsoleNotice -Notice $notice
430
- Write-WatcherLog ("NOTICE updated=" + $noticeUpdated + " text=" + $notice)
431
- } else {
432
- Write-WatcherLog "NOTICE clear"
425
+ $lastTitle = $title
426
+ }
427
+ if ($notice -ne $lastNotice) {
428
+ if ($notice) {
429
+ $noticeUpdated = Write-ConsoleNotice -Notice $notice
430
+ Write-WatcherLog ("NOTICE updated=" + $noticeUpdated + " text=" + $notice)
431
+ } else {
432
+ Write-WatcherLog "NOTICE clear"
433
433
  }
434
434
  $lastNotice = $notice
435
435
  }