13 KiB
Add skills and PowerShell script
given the flow described in "User Workflow" secion of the document, and considering the whole document for a more detailed description, I want you to:
- add appropriate skills
- create a Powershell script that does what is described
15 previous messages
I’ll inspect the workspace instructions and locate the document’s “User Workflow” section first. Then I’ll translate the full specification into the appropriate Codex skills and a PowerShell implementation, with runnable verification.
Ran a command
- Ran
Get-ChildItem -Force | Select-Object Mode,Length,LastWriteTime,Name; rg --files -g 'AGENTS.md' -g '*.md' -g '*.txt' -g '*.docx' -g '*.pdf'The request includes creating reusable skills, so I’m applying the
skill-creatorguidance before making changes. I found the specification insave-metadata-schema-automatic.md; I’ll read it in full, including its workflow and validation requirements.Ran 3 commands
- Ran
Get-Content -Raw 'C:\Users\pierp\.codex\skills\.system\skill-creator\SKILL.md'; Get-Content -Raw '.\save-metadata-schema-automatic.md'- Ran
$lines = Get-Content '.\save-metadata-schema-automatic.md'; "LINES=$($lines.Count)"; rg -n '^#{1,4} ' '.\save-metadata-schema-automatic.md'- Ran
$lines = Get-Content '.\save-metadata-schema-automatic.md'; $lines[0..493]The specification is precise about request construction, but the save payload is the fragile part. I’m checking the supplied HAR structurally—without printing session cookies—to reproduce the real multipart field format, headers, and response behavior instead of guessing from prose.
Ran a command
- Ran
$har = Get-Content -Raw '.\save-metadata-schema.har' | ConvertFrom-Json -Depth 100; $entries = @($har.log.entries | Where-Object { $_.request.url -match '/AJSRV/metadata/(list|search|save)' }); foreach ($entry in $entries) { $request = $entry.request; $safeHeaders = @($request.headers | Where-Object { $_.name -notmatch '^(Cookie|Authorization)$' } | Select-Object name,value); [pscustomobject]@{ Method=$request.method; Url=$request.url; Headers=$safeHeaders; PostMime=$request.postData.mimeType; Params=$request.postData.params; Text=$request.postData.text; Status=$entry.response.status; ResponseMime=$entry.response.content.mimeType } | ConvertTo-Json -Depth 20 }The HAR reveals one important correction to the prose: save field names use the row’s generic-schema/data ID (the second search column, e.g.
81825), not the firstID_OBJECTvalue. I’ll encode that verified invariant in both the script and the reusable skill. The script will also preserve column order, fetch every result page, back up all search responses before any write, require an explicit destructive confirmation, and summarize per-row outcomes.Ran 3 commands
- Ran
Get-Content -Raw 'C:\Users\pierp\.codex\skills\.system\skill-creator\references\openai_yaml.md'; git status --short- Ran
python 'C:\Users\pierp\.codex\skills\.system\skill-creator\scripts\init_skill.py' elixforms-schema-bulk-updater --path '.\.agents\skills' --resources scripts,references --interface 'display_name=ElixForms Metadata Bulk Update' --interface 'short_description=Safely update one metadata field in bulk' --interface 'default_prompt=Use $elixforms-schema-bulk-updater to prepare or run a guarded ElixForms metadata bulk update.'- Ran
Get-Content -Raw '.\.agents\skills\elixforms-schema-bulk-updater\SKILL.md'; Get-Content -Raw '.\.agents\skills\elixforms-schema-bulk-updater\agents\openai.yaml'; Get-ChildItem -Recurse '.\.agents\skills\elixforms-schema-bulk-updater' | Select-Object FullNameI’ve finished the design pass. The skill will be repository-local and self-contained under
.agents/skills, with the full PowerShell implementation packaged as its deterministic helper plus a short root launcher. No credentials will be persisted; backups contain search data and filters but never the cookie.The initial patch hit a patch-tool constraint while replacing the generated scaffold; no implementation files were partially written. I’m splitting the change into smaller atomic patches and continuing.
Created 3 files, edited a file, ran a command
- Wrote
./.agents/skills/elixforms-schema-bulk-updater/SKILL.md(+20 -6)- Wrote
./.agents/skills/elixforms-schema-bulk-updater/references/protocol.md(+37 -0)- Wrote
./Invoke-ElixFormsMetadataBulkUpdate.ps1(+1 -0)- Ran
Get-Content -Raw '.\.agents\skills\elixforms-schema-bulk-updater\SKILL.md'; Test-Path '.\.agents\skills\elixforms-schema-bulk-updater\references\protocol.md'; Test-Path '.\Invoke-ElixFormsMetadataBulkUpdate.ps1'- Wrote
./.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsMetadataBulkUpdate.ps1(+653 -0)The implementation is now in place. I’m at the verification stage: parsing it with PowerShell’s AST parser, exercising URI encoding and multipart byte construction against the documented examples, checking the root launcher, and validating the skill package for unfinished scaffold content or metadata errors.
Ran 4 commands
- Ran
$scriptPath = Resolve-Path '.\.agents\skills\elixforms-schema-bulk-updater\scripts\Invoke-ElixFormsMetadataBulkUpdate.ps1'; $tokens = $null; $parseErrors = $null; $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptPath, [ref]$tokens, [ref]$parseErrors); if ($parseErrors.Count -gt 0) { $parseErrors | Format-List; exit 1 }; 'PowerShell parse: OK'; . $scriptPath; $query = [ordered]@{'SEARCH_IN[]'=616; 'S_616_NEW_COL0014'='antani tapioca'; PAGE=1; AJL='it'; PAGESIZE=80; SECURE='true'}; $uri = New-ElixFormsUri -BaseUri 'https://console-unipr.elixforms.it/AJSRV/metadata' -Route 'search' -Query $query; "URI=$uri"; if ($uri.AbsoluteUri -notmatch 'SEARCH_IN%5B%5D=616' -or $uri.AbsoluteUri -notmatch 'antani%20tapioca') { throw 'Query encoding test failed.' }; $multipart = New-MultipartFieldBody -Name 'S_616_81825_COL0014' -Value ''; $multipartText = [Text.Encoding]::UTF8.GetString($multipart.Bytes); if ($multipartText -notmatch 'name="S_616_81825_COL0014"' -or -not $multipartText.EndsWith("--`r`n")) { throw 'Multipart test failed.' }; "Multipart bytes=$($multipart.Bytes.Length) content-type=$($multipart.ContentType)"; 'Helper tests: OK'; python 'C:\Users\pierp\.codex\skills\.system\skill-creator\scripts\quick_validate.py' '.\.agents\skills\elixforms-schema-bulk-updater'; rg -n '\[TODO|TODO:' '.\.agents\skills\elixforms-schema-bulk-updater' '.\Invoke-ElixFormsMetadataBulkUpdate.ps1'- Ran
$scriptPath = Resolve-Path '.\.agents\skills\elixforms-schema-bulk-updater\scripts\Invoke-ElixFormsMetadataBulkUpdate.ps1'; $search = Get-Content -Raw '.\search-schema-results.json' | ConvertFrom-Json; "Fixture columns=$(@($search.columns).Count) rows=$(@($search.data).Count) total=$($search.totalRecords) pages=$($search.numPages)"; $genericKey = 'S_616_ID_GENERICSCHEMA'; $genericIndex = [Array]::IndexOf([object[]]@($search.columns.key), $genericKey); $objectIndex = [Array]::IndexOf([object[]]@($search.columns.key), 'ID_OBJECT'); "Fixture ID indexes: object=$objectIndex generic-data=$genericIndex"; if ($genericIndex -lt 0 -or $objectIndex -lt 0) { throw 'Fixture identifier columns missing.' }; $firstRow = @($search.data)[0]; "First save-name example=S_616_$($firstRow[$genericIndex])_COL0014 (object $($firstRow[$objectIndex]))"; if (Get-Command Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) { Invoke-ScriptAnalyzer -Path $scriptPath -Severity Warning,Error | Format-Table -AutoSize } else { 'PSScriptAnalyzer not installed; skipped.' }; if (Get-Command powershell.exe -ErrorAction SilentlyContinue) { powershell.exe -NoProfile -Command "`$tokens=`$null; `$errors=`$null; [System.Management.Automation.Language.Parser]::ParseFile('$($scriptPath.Path.Replace("'", "''"))',[ref]`$tokens,[ref]`$errors) > `$null; if (`$errors.Count) { `$errors | Out-String; exit 1 }; 'Windows PowerShell parse: OK'" }- Ran
$failed = $false; Get-ChildItem -Recurse -Filter '*.ps1' | ForEach-Object { $tokens=$null; $errors=$null; [System.Management.Automation.Language.Parser]::ParseFile($_.FullName,[ref]$tokens,[ref]$errors) > $null; if ($errors.Count) { $failed=$true; $errors | ForEach-Object { "PARSE ERROR $($_.Extent.File):$($_.Extent.StartLineNumber): $($_.Message)" } } else { "PARSE OK $($_.FullName)" } }; if ($failed) { exit 1 }; Get-ChildItem -Recurse '.\.agents\skills\elixforms-schema-bulk-updater' | Select-Object FullName,Length; Get-Content -Raw '.\.agents\skills\elixforms-schema-bulk-updater\agents\openai.yaml'- Ran
try { throw 'Value {0}' -f 42 } catch { "THROW_TEST=$($_.Exception.Message)" }; . '.\.agents\skills\elixforms-schema-bulk-updater\scripts\Invoke-ElixFormsMetadataBulkUpdate.ps1'; $sample = Get-Content -Raw '.\search-schema-results.json' | ConvertFrom-Json; $columns = @($sample.columns); $rows = @($sample.data); "RowsRuntimeType=$($rows.GetType().FullName) FirstRowType=$($rows[0].GetType().FullName) FirstRowCount=$(@($rows[0]).Count)"; $objectIndex = Get-ColumnIndex -Columns $columns -Key 'ID_OBJECT'; $genericIndex = Get-ColumnIndex -Columns $columns -Key 'S_616_ID_GENERICSCHEMA'; "FunctionIndexes=$objectIndex,$genericIndex"; $schemaFixture = [pscustomobject]@{ sections = @([pscustomobject]@{key='SEC_B'; title='B'; orderKey='ORD002'; fields=@([pscustomobject]@{key='COL_B';title='B';type='STRING';orderKey='ORD001'})},[pscustomobject]@{key='SEC_A';title='A';orderKey='ORD001';fields=@([pscustomobject]@{key='COL_A2';title='A2';type='STRING';orderKey='ORD002'},[pscustomobject]@{key='COL_A1';title='A1';type='STRING';orderKey='ORD001'})})}; $ordered = @(Get-OrderedSchemaFields -Schema $schemaFixture); "OrderedFields=$($ordered.Key -join ',')"; if (($ordered.Key -join ',') -ne 'COL_A1,COL_A2,COL_B') { throw 'Field ordering test failed.' }The verification checks are clean in both PowerShell 7 and Windows PowerShell 5.1, and the supplied 56-row fixture maps identifiers as expected. I’m making one final hardening pass on backup naming and inline help, then I’ll hand over the exact run command and the HAR-derived identifier caveat.
Edited 2 files, ran a command
- Wrote
./.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsMetadataBulkUpdate.ps1(+25 -1)- Wrote
./Invoke-ElixFormsMetadataBulkUpdate.ps1(+5 -0)- Ran
$allGood = $true; Get-ChildItem -Recurse -Filter '*.ps1' | ForEach-Object { $tokens=$null; $errors=$null; [System.Management.Automation.Language.Parser]::ParseFile($_.FullName,[ref]$tokens,[ref]$errors) > $null; if ($errors.Count) { $allGood=$false; $errors | Format-List } }; if (-not $allGood) { exit 1 }; . '.\.agents\skills\elixforms-schema-bulk-updater\scripts\Invoke-ElixFormsMetadataBulkUpdate.ps1'; $query=[ordered]@{'SEARCH_IN[]'=616;'S_616_NEW_COL0014'='antani tapioca';PAGE=1;AJL='it';PAGESIZE=80;SECURE='true'}; $uri=New-ElixFormsUri -BaseUri 'https://console-unipr.elixforms.it/AJSRV/metadata' -Route 'search' -Query $query; if ($uri.AbsoluteUri -notmatch 'SEARCH_IN%5B%5D=616' -or $uri.AbsoluteUri -notmatch 'antani%20tapioca') { throw 'URI test failed' }; $part=New-MultipartFieldBody -Name 'S_616_81825_COL0014' -Value ''; if ($part.Bytes.Length -le 0 -or $part.ContentType -notmatch '^multipart/form-data; boundary=') { throw 'Multipart test failed' }; python 'C:\Users\pierp\.codex\skills\.system\skill-creator\scripts\quick_validate.py' '.\.agents\skills\elixforms-schema-bulk-updater'; 'Final validation: OK'; rg -n '^function (Get-ElixFormsSearchResult|Save-SearchBackup|Invoke-ElixFormsMetadataBulkUpdate)|generic-schema/data ID|^Use `scripts' '.\.agents\skills\elixforms-schema-bulk-updater\SKILL.md' '.\.agents\skills\elixforms-schema-bulk-updater\references\protocol.md' '.\.agents\skills\elixforms-schema-bulk-updater\scripts\Invoke-ElixFormsMetadataBulkUpdate.ps1'; Get-ChildItem -Recurse -File '.\.agents\skills\elixforms-schema-bulk-updater','Invoke-ElixFormsMetadataBulkUpdate.ps1' | Select-Object FullName,Length
Implemented the complete workflow.
- Added the repository-local skill: SKILL.md
- Created the executable launcher: Invoke-ElixFormsMetadataBulkUpdate.ps1
- Added protocol documentation, including the HAR-confirmed requirement to use
ID_GENERICSCHEMA/dataIdrather thanID_OBJECTwhen constructing save field names.
Run it with:
.\Invoke-ElixFormsMetadataBulkUpdate.ps1
The script includes hidden cookie input, schema validation, ordered filters, pagination, result preview, two confirmations, timestamped JSON backups, multipart saves with byte-accurate Content-Length, failure-safe stopping, summaries, and optional verification.
Validated with PowerShell 7 and Windows PowerShell 5.1 parsing, fixture-based identifier checks, URI/multipart tests, and the Codex skill validator. The live API was not called because that requires your authenticated cookie and would modify production data.