fix(skills): усечение эха в сообщении о разборе JSON не маскируется под данные

Эхо полученного значения обрезалось многоточием, и обрыв читался как обрыв самих данных:
агент шёл дописывать «неполный» файл, хотя ошибка была на 57-й строке. Плюс усечение спорило
с позицией от парсера — два сигнала об одном месте, которые не сходятся.

Теперь усечение называет себя: got (first 60 chars, whitespace collapsed). Число символов
не печатаем — после схлопывания пробелов оно не сходилось со смещением из сообщения парсера.
На коротком входе, ради которого эхо и заводилось (съеденные оболочкой кавычки дают
{group:X,commands:[Y]} — 22 символа), усечения нет вовсе.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-21 15:40:40 +03:00
co-authored by Claude Opus 5
parent a44a29a7d8
commit 0770889e47
24 changed files with 84 additions and 48 deletions
+3 -2
View File
@@ -23,8 +23,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
+4 -2
View File
@@ -31,9 +31,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -27,8 +27,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -32,9 +32,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -23,8 +23,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -29,8 +29,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -364,9 +364,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -22,8 +22,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -40,9 +40,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -44,8 +44,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -22,8 +22,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -22,8 +22,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -21,8 +21,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -29,9 +29,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -22,8 +22,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -26,9 +26,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -22,8 +22,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)
@@ -23,8 +23,9 @@ function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected
} catch { } catch {
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" } $what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
$got = ($text -replace '\s+', ' ').Trim() $got = ($text -replace '\s+', ' ').Trim()
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' } $label = 'got'
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))") if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
exit 1 exit 1
} }
Write-Output -NoEnumerate $parsed Write-Output -NoEnumerate $parsed
@@ -30,9 +30,11 @@ def parse_json_input(text, source, expected=None):
except ValueError as exc: except ValueError as exc:
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
got = " ".join(str(text).split()) got = " ".join(str(text).split())
label = "got"
if len(got) > 60: if len(got) > 60:
got = got[:60] + "..." label = "got (first 60 chars, whitespace collapsed)"
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr) got = got[:60]
print("[ERROR] %s, %s: %s (%s)" % (what, label, got, exc), file=_psys.stderr)
_psys.exit(1) _psys.exit(1)