Files
llm/scripts/build_1c_saved_state_object_report.ps1
T

326 lines
13 KiB
PowerShell

param(
[string]$Server = $env:ONEC_SQL_SERVER,
[string]$Database = $env:ONEC_SQL_DATABASE,
[string]$User = $env:ONEC_SQL_USER,
[string]$Password = $env:ONEC_SQL_PASSWORD,
[string]$OutputDir = "reports\1c-sql\saved-state-object-report",
[string]$BaseMetadataDir = "reports\1c-sql\upo\structured-metadata-all-kinds",
[string]$ExtensionGuidIndex = "reports\1c-sql\upo\xml-guid-index-extensions.json",
[string]$ExtensionManifestSummary = "reports\1c-sql\upo\extension-manifest-xml-part-summary.json",
[string]$ConfigCASAllDir = "reports\1c-sql\upo\ConfigCAS-all",
[string]$Python = "python",
[string]$MarkdownOutput = "",
[int]$MarkdownMaxDiffLines = 80,
[switch]$SkipMarkdown
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
if (-not $Server) { throw "Server is required. Use -Server or ONEC_SQL_SERVER." }
if (-not $Database) { throw "Database is required. Use -Database or ONEC_SQL_DATABASE." }
if (-not $User) { throw "User is required. Use -User or ONEC_SQL_USER." }
if (-not $Password) { throw "Password is required. Use -Password or ONEC_SQL_PASSWORD." }
$repoRoot = (Resolve-Path ".").ProviderPath
$resolvedOutput = [System.IO.Path]::GetFullPath($OutputDir)
New-Item -ItemType Directory -Force -Path $resolvedOutput | Out-Null
$comparisonPath = Join-Path $resolvedOutput "saved-state-object-comparison.json"
$detailPath = Join-Path $resolvedOutput "saved-state-object-details.json"
$checkPath = Join-Path $resolvedOutput "saved-state-object-report-check.json"
$configSaveDir = Join-Path $resolvedOutput "ConfigSave"
$configCASSaveDir = Join-Path $resolvedOutput "ConfigCASSave"
$activeConfigDir = Join-Path $resolvedOutput "ActiveConfig"
$activeConfigCASDir = Join-Path $resolvedOutput "ActiveConfigCAS"
foreach ($dir in @($configSaveDir, $configCASSaveDir, $activeConfigDir, $activeConfigCASDir)) {
New-Item -ItemType Directory -Force -Path $dir | Out-Null
}
function Invoke-Step {
param(
[string]$Name,
[scriptblock]$Script
)
$started = Get-Date
& $Script
[pscustomobject]@{
name = $Name
started_at = $started.ToString("o")
finished_at = (Get-Date).ToString("o")
passed = $true
}
}
function Read-JsonFile {
param([string]$Path)
return Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
}
function Export-TableFiles {
param(
[string]$Table,
[string]$TargetDir,
[string[]]$FileName
)
$args = @(
"-NoProfile", "-ExecutionPolicy", "Bypass",
"-File", "scripts\export_1c_sql_files.ps1",
"-Server", $Server,
"-Database", $Database,
"-User", $User,
"-Password", $Password,
"-Table", $Table,
"-OutputPath", $TargetDir
)
[object[]]$normalizedFileName = @($FileName)
if (($normalizedFileName | Measure-Object).Count -gt 0) {
$args += "-FileName"
$args += $normalizedFileName
}
$json = & powershell @args
if ($LASTEXITCODE -ne 0) {
throw "Export failed for $Table."
}
return ($json | Out-String | ConvertFrom-Json)
}
function Get-JsonProperty {
param(
[object]$Object,
[string]$Name,
[object]$Default = $null
)
if ($null -eq $Object) { return $Default }
if ($Object.PSObject.Properties.Name -contains $Name) {
return $Object.$Name
}
return $Default
}
function Join-LimitedValues {
param(
[object[]]$Values,
[int]$Limit = 12
)
$items = @($Values | Where-Object { $null -ne $_ -and [string]$_ -ne "" } | Select-Object -First $Limit)
return ,$items
}
function New-AgentSummary {
param(
[object]$Comparison,
[object]$Detail
)
$detailByName = @{}
foreach ($item in @($Detail.object_details)) {
$fullName = [string](Get-JsonProperty -Object $item -Name "full_name" -Default "")
if ($fullName) { $detailByName[$fullName] = $item }
}
$objects = @()
foreach ($change in @($Comparison.object_changes)) {
$fullName = [string](Get-JsonProperty -Object $change -Name "full_name" -Default (Get-JsonProperty -Object $change -Name "name" -Default ""))
$item = $null
if ($fullName -and $detailByName.ContainsKey($fullName)) {
$item = $detailByName[$fullName]
}
$parts = @()
$addedTerms = @()
$removedTerms = @()
$textDiffParts = 0
$activeMissingParts = 0
foreach ($part in @((Get-JsonProperty -Object $item -Name "details" -Default @()))) {
$payload = Get-JsonProperty -Object $part -Name "payload" -Default $null
$diff = Get-JsonProperty -Object $payload -Name "text_diff" -Default $null
$semanticHints = Get-JsonProperty -Object $payload -Name "semantic_hints" -Default $null
$activeExists = Get-JsonProperty -Object $part -Name "active_exists" -Default $null
if ($activeExists -eq $false) { $activeMissingParts += 1 }
if ($null -ne $diff) {
$textDiffParts += 1
$addedTerms += @(Get-JsonProperty -Object $semanticHints -Name "added_terms" -Default @())
$removedTerms += @(Get-JsonProperty -Object $semanticHints -Name "removed_terms" -Default @())
}
$parts += [pscustomobject]@{
file_name = Get-JsonProperty -Object $part -Name "file_name" -Default $null
payload_role = Get-JsonProperty -Object $part -Name "payload_role" -Default $null
saved_table = Get-JsonProperty -Object $part -Name "saved_table" -Default $null
active_table = Get-JsonProperty -Object $part -Name "active_table" -Default $null
active_exists = $activeExists
text_comparable = Get-JsonProperty -Object $payload -Name "text_comparable" -Default $null
summary = Get-JsonProperty -Object $payload -Name "summary" -Default $null
delta_chars = Get-JsonProperty -Object $diff -Name "delta_chars" -Default $null
}
}
$objects += [pscustomobject]@{
full_name = $fullName
layer = Get-JsonProperty -Object $change -Name "layer" -Default $null
extension = Get-JsonProperty -Object $change -Name "extension" -Default $null
kind = Get-JsonProperty -Object $change -Name "kind" -Default $null
kind_ru = Get-JsonProperty -Object $change -Name "kind_ru" -Default $null
name = Get-JsonProperty -Object $change -Name "name" -Default $null
synonym = Get-JsonProperty -Object $change -Name "synonym" -Default $null
change_state = Get-JsonProperty -Object $change -Name "change_state" -Default $null
parts_count = ($parts | Measure-Object).Count
text_diff_parts = $textDiffParts
active_missing_parts = $activeMissingParts
added_terms = Join-LimitedValues -Values ($addedTerms | Sort-Object -Unique) -Limit 12
removed_terms = Join-LimitedValues -Values ($removedTerms | Sort-Object -Unique) -Limit 12
parts = $parts
}
}
$systemChanges = @()
foreach ($change in @($Comparison.system_changes)) {
$systemChanges += [pscustomobject]@{
name = Get-JsonProperty -Object $change -Name "name" -Default $null
layer = Get-JsonProperty -Object $change -Name "layer" -Default $null
extension = Get-JsonProperty -Object $change -Name "extension" -Default $null
}
}
return [pscustomobject]@{
purpose = "Compact agent-facing summary of saved-but-not-applied changes in 1C terms."
default_next_action = "Inspect object details before generating or applying any code changes."
object_changes = $objects
system_changes = $systemChanges
object_names = @($objects | ForEach-Object { $_.full_name })
system_change_names = @($systemChanges | ForEach-Object { $_.name })
}
}
$steps = @()
$steps += Invoke-Step "compare_saved_state_objects" {
& powershell -NoProfile -ExecutionPolicy Bypass -File scripts\compare_1c_saved_state_objects.ps1 `
-Server $Server `
-Database $Database `
-User $User `
-Password $Password `
-BaseMetadataDir $BaseMetadataDir `
-ExtensionGuidIndex $ExtensionGuidIndex `
-Output $comparisonPath | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Saved-state object comparison failed." }
}
$comparison = Read-JsonFile $comparisonPath
$steps += Invoke-Step "export_config_save" {
$null = Export-TableFiles -Table "ConfigSave" -TargetDir $configSaveDir
}
$steps += Invoke-Step "export_config_cas_save" {
$null = Export-TableFiles -Table "ConfigCASSave" -TargetDir $configCASSaveDir
}
$activeConfigFiles = @(
$comparison.object_changes |
ForEach-Object { $_.storage } |
Where-Object { $_.active_table -eq "Config" } |
ForEach-Object { [string]$_.file_name } |
Sort-Object -Unique
)
$activeConfigCASFiles = @(
$comparison.object_changes |
ForEach-Object { $_.storage } |
Where-Object { $_.active_table -eq "ConfigCAS" -and $_.active_exists } |
ForEach-Object { [string]$_.file_name } |
Sort-Object -Unique
)
$steps += Invoke-Step "export_active_config_payloads" {
if (($activeConfigFiles | Measure-Object).Count -gt 0) {
$null = Export-TableFiles -Table "Config" -TargetDir $activeConfigDir -FileName $activeConfigFiles
}
}
$steps += Invoke-Step "export_active_config_cas_payloads" {
if (($activeConfigCASFiles | Measure-Object).Count -gt 0) {
$null = Export-TableFiles -Table "ConfigCAS" -TargetDir $activeConfigCASDir -FileName $activeConfigCASFiles
}
}
$steps += Invoke-Step "analyze_saved_state_object_details" {
& $Python scripts\analyze_1c_saved_state_object_details.py `
--comparison $comparisonPath `
--config-save-dir $configSaveDir `
--config-dir $activeConfigDir `
--config-cas-save-dir $configCASSaveDir `
--config-cas-dir $activeConfigCASDir `
--extension-manifest-summary $ExtensionManifestSummary `
--config-cas-all-dir $ConfigCASAllDir `
--output $detailPath | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Saved-state detail analysis failed." }
}
$detail = Read-JsonFile $detailPath
$agentSummary = New-AgentSummary -Comparison $comparison -Detail $detail
$reportPath = Join-Path $resolvedOutput "saved-state-object-report.json"
if (-not $MarkdownOutput) {
$MarkdownOutput = Join-Path $resolvedOutput "saved-state-object-report.md"
} else {
$MarkdownOutput = [System.IO.Path]::GetFullPath($MarkdownOutput)
}
$result = [pscustomobject]@{
schema = "onec_saved_state_object_report.v1"
server = $Server
database = $Database
report = $reportPath
markdown = if ($SkipMarkdown) { $null } else { $MarkdownOutput }
check = $checkPath
output_dir = $resolvedOutput
comparison = $comparisonPath
detail = $detailPath
agent_summary = $agentSummary
payload_dirs = [pscustomobject]@{
config_save = $configSaveDir
config_cas_save = $configCASSaveDir
active_config = $activeConfigDir
active_config_cas = $activeConfigCASDir
active_config_cas_all = $ConfigCASAllDir
}
counts = [pscustomobject]@{
object_changes = $comparison.counts.object_changes
system_changes = $comparison.counts.system_changes
detail_objects = $detail.counts.objects
detail_parts = $detail.counts.details
}
steps = $steps
safety = [pscustomobject]@{
read_only = $true
sql_write_performed = $false
public_terms_are_1c_objects = $true
secrets_in_report = $false
}
}
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
if (-not $SkipMarkdown) {
$steps += Invoke-Step "render_saved_state_markdown" {
& $Python scripts\render_1c_saved_state_object_report_markdown.py `
--report $reportPath `
--output $MarkdownOutput `
--max-diff-lines $MarkdownMaxDiffLines | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Saved-state Markdown rendering failed." }
}
$result.steps = $steps
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
}
$steps += Invoke-Step "check_saved_state_report" {
& $Python scripts\check_1c_saved_state_object_report.py `
--report $reportPath `
--output $checkPath | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Saved-state report check failed." }
}
$result.steps = $steps
$result | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $reportPath -Encoding UTF8
$result | ConvertTo-Json -Depth 12