Files
Joseph Doherty c52d8d0171 graccesscli: correct script-edit docs to TN-537 truth (writes DO persist)
I was wrong. AVEVA Tech Note 537 ("Creating an Application Object Script
Using GRAccess", April 2008) documents the supported pattern:
ConfigurableAttributes[<script>.<field>].SetValue(MxValue) inside a
CheckOut/Save/CheckIn cycle. graccesscli's existing
FindAttributeForMutation already follows this — writes to MxCategoryPackageOnly_Lockable
script-text fields persist correctly.

The earlier "writeback gap" diagnosis was a phantom caused by a reader-side
issue. `object attribute value get` against a script body returns
"Supported: False / Attribute value is not exposed" because
MxValueDetails uses a case-sensitive `ReadProperty(attr, "Value")` lookup
plus an accessor probe (GetBoolean -> GetInteger -> GetFloat -> GetDouble
-> GetString) that can fall through silently for some MxValue shapes. The
COM-side property is exposed as `value` (lowercase), readable as
`attr.value.GetString()` -- which the live probe at
`analysis/ide-edit-investigation/probe_setvalue/` does and confirms the
post-write content matches the marker exactly.

Live verification on $TestMachine.UpdateTestChangingInt.DeclarationsText
and $DelmiaReceiver.ProcessRecipe.{ExecuteText,DeclarationsText}:

  === verdict ===
    marker landed on same-proxy   ConfigurableAttributes: True
    marker landed on same-proxy   Attributes            : True
    marker landed on fresh-proxy  ConfigurableAttributes: True
    marker landed on fresh-proxy  Attributes            : True

The probe also confirmed that two earlier graccesscli `object scripts set`
invocations (which I had wrongly believed failed) had persisted -- the
marker text I wrote previously was still on disk in
ProcessRecipe.{ExecuteText,DeclarationsText} when read directly via
attr.value.GetString(). The probe restored both fields to their original
values.

This commit:

- Updates the misleading [Command(...)] / [CommandOption(...)]
  descriptions in GRAccessSurfaceCommands.cs back to honest versions
  citing TN-537.
- Restores the --file-using examples for `object scripts set` and
  `object scripts create` across script-editing.md, llm-integration.md,
  usage.md, and zb-testmachine.md.
- Removes the test that asserted the (wrong) EnsureMutableViaSetValue
  guard. Re-aims ScriptCommandDescriptions_… at the corrected wording.
- Removes two leftover EnsureMutableViaSetValue calls in the trigger-period
  / trigger-type write paths (both targeted MxCategoryWriteable_C_Lockable
  attributes; would never have fired even if the helper still existed).
- Adds analysis/ide-edit-investigation/REPORT.md (replacing the earlier
  wrong report) plus the probe sources under probe_setvalue/.

The MxValueDetails reader gap (case-sensitive ReadProperty + accessor
probe) is a real follow-up: `object attribute value get` should
case-insensitively read `value` and try GetString first when the
underlying MxValue.DataType is MxString. Out of scope here -- that's a
separate, smaller fix.

Test count delta: 67 -> 66 (-2 wrong tests, +1 corrected description test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:33:51 -04:00

12 KiB

Editing Scripts And Script Libraries

This guide describes how to edit scripts related to a template such as TestMachine.

Read script-parsing.md first so you know whether the target script is a script library, an object-level script-like attribute, an extension primitive, or content that only appears in an exported object package.

Run commands from graccess_cli. Examples assume an active session:

graccess session start --galaxy ZB --node .

Without a session, add --node . to each command.

For LLM-driven script work, read script metadata and validate guarded edits with the LLM envelope:

graccess object scripts list --galaxy ZB --name TestMachine --type template --llm-json
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine --dry-run --llm-json

What The CLI Can Edit Today

Area Current command support
Script library inventory script-library list
Script library export script-library export
Script library import/add script-library import, script-library add, galaxy import-script-library
Object script metadata object scripts list, object scripts get
Object script body read/write object scripts get (package fallback) and object scripts set --file <path> [--field <name>] for body fields like ExecuteText / DeclarationsText / StartupText / ShutdownText / OnScanText / OffScanText / Expression. See AVEVA Tech Note 537.
Object script mutable settings object scripts settings set --trigger-type, --trigger-period-ms
Object script create/delete object scripts create, object scripts delete
Script-like attributes object attribute set, lock, security, buffer
Extension primitives object extension add/delete/rename
Full object package script payloads Use objects export and galaxy import-objects

Export Before Editing

Export script libraries before changing them:

$out = '.\template-snapshots\script-libraries-before'
New-Item -ItemType Directory -Force -Path $out | Out-Null

$libs = graccess script-library list --galaxy ZB --json | ConvertFrom-Json
foreach ($lib in $libs) {
  $name = $lib.Name
  $path = Join-Path $out "$name.aaslib"
  graccess script-library export --galaxy ZB --name $name --output $path --confirm --confirm-target $path
}

Export the template package when object-level scripts may be involved:

$pkg = '.\template-snapshots\TestMachine-before\TestMachine.aaPKG'
graccess objects export --galaxy ZB --type template --name TestMachine --output $pkg --confirm --confirm-target $pkg

Edit Script Libraries

Script library content is edited outside the CLI in the .aaslib file or source toolchain that creates it. Import the updated library after review:

graccess script-library import --galaxy ZB --path '.\scripts\CommonScripts.aaslib' --confirm --confirm-target '.\scripts\CommonScripts.aaslib'

The galaxy-level import command is also available:

graccess galaxy import-script-library --galaxy ZB --path '.\scripts\CommonScripts.aaslib' --confirm --confirm-target '.\scripts\CommonScripts.aaslib'

After import, list libraries again:

graccess script-library list --galaxy ZB --json

Edit Script-Like Attributes

Some templates store expressions, declarations, triggers, or script fragments in attributes. Find candidates:

$attrs = graccess object attributes --galaxy ZB --name TestMachine --type template --json | ConvertFrom-Json
$extended = graccess object extended-attributes --galaxy ZB --name TestMachine --type template --json | ConvertFrom-Json
$scripts = (@($attrs) + @($extended)) | Where-Object {
  $_.Name -match '(?i)script|execute|trigger|expression|declaration|startup|shutdown|scan'
} | Sort-Object Name -Unique

$scripts | Select-Object Name, DataType, Category, Locked

If the script-like setting is a scalar writable attribute, edit it through the normal template edit flow. Script extension attributes are looked up through ConfigurableAttributes first, then Attributes — the pattern AVEVA Tech Note 537 ("Creating an Application Object Script Using GRAccess") prescribes for ScriptExtension text fields. object scripts set, object scripts settings set, and object attribute value set all use that ordering. A bare --script <name> writes to <name>.ExecuteText; pass --field <FieldName> (or include the suffix in --script) to target DeclarationsText, StartupText, ShutdownText, OnScanText, OffScanText, or Expression.

graccess object checkout --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine
graccess object save --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
graccess object checkin --galaxy ZB --name TestMachine --type template --comment 'Update script body' --confirm --confirm-target TestMachine

Reader caveat. object attribute value get against a script text field may report Supported: False ("Attribute value is not exposed by this GRAccess attribute") even when the value is set. The write itself persists; the limitation is in MxValueDetails reading the COM-side value accessor for these field types. Verify post-write content with object scripts get --llm-json (which uses the package-export readback) instead. Round-trip evidence is in analysis/ide-edit-investigation/probe_setvalue/ (commit e4e5425..).

Update periodic script settings and lock the interval for deployment inheritance:

graccess object checkout --galaxy ZB --name '$TestMachine' --type template --confirm --confirm-target '$TestMachine'
graccess object scripts settings set --galaxy ZB --name '$TestMachine' --type template --script UpdateTestChangingInt --trigger-period-ms 500 --lock-trigger-period --confirm --confirm-target '$TestMachine'
graccess object save --galaxy ZB --name '$TestMachine' --type template --confirm --confirm-target '$TestMachine'
graccess object checkin --galaxy ZB --name '$TestMachine' --type template --comment 'Set UpdateTestChangingInt interval to 500ms' --confirm --confirm-target '$TestMachine'

Verify with package-backed readback:

graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json

Edit Extension Primitives

When a script is represented by an extension primitive, use the extension commands for the primitive lifecycle:

graccess object checkout --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
graccess object extension add --galaxy ZB --name TestMachine --type template --extension-type ScriptExtension --primitive OnScan --object-extension --confirm --confirm-target TestMachine
graccess object save --galaxy ZB --name TestMachine --type template --confirm --confirm-target TestMachine
graccess object checkin --galaxy ZB --name TestMachine --type template --comment 'Add script extension primitive' --confirm --confirm-target TestMachine

Rename:

graccess object extension rename --galaxy ZB --name TestMachine --type template --extension-type ScriptExtension --primitive OnScan --new-name OnScan2 --object-extension --confirm --confirm-target TestMachine

Delete:

graccess object extension delete --galaxy ZB --name TestMachine --type template --extension-type ScriptExtension --primitive OnScan2 --object-extension --confirm --confirm-target TestMachine

These commands manage primitive structure. The wrapper below creates the same ScriptExtension primitive and can initialize the body and common settings in the same checkout flow (per AVEVA TN-537: AddExtensionPrimitive → Save → set body/settings via ConfigurableAttributes):

graccess object checkout --galaxy ZB --name '$MyTemplate' --type template --confirm --confirm-target '$MyTemplate'
graccess object scripts create --galaxy ZB --name '$MyTemplate' --type template --script OnScan --file .\OnScan.txt --trigger-type Periodic --trigger-period-ms 1000 --confirm --confirm-target '$MyTemplate'
graccess object save --galaxy ZB --name '$MyTemplate' --type template --confirm --confirm-target '$MyTemplate'
graccess object checkin --galaxy ZB --name '$MyTemplate' --type template --comment 'Add OnScan script' --confirm --confirm-target '$MyTemplate'

After adding a ScriptExtension primitive, set its body with object scripts set --script <primitiveName> (defaults to ExecuteText) or target a different field with --field DeclarationsText / StartupText / etc.

Full-Fidelity Object Script Edits

When script bodies are only available inside the object package, use export/import:

  1. Export the template package.
  2. Edit with the supported vendor tooling or package workflow.
  3. Import the updated package with explicit confirmation.
  4. Re-parse and validate the template.

Export:

$pkg = '.\template-work\TestMachine.aaPKG'
graccess objects export --galaxy ZB --type template --name TestMachine --output $pkg --confirm --confirm-target $pkg

Import:

graccess galaxy import-objects --galaxy ZB --file '.\template-work\TestMachine.aaPKG' --overwrite --confirm --confirm-target '.\template-work\TestMachine.aaPKG'

For conflict-aware import:

graccess galaxy import-objects-ex --galaxy ZB --file '.\template-work\TestMachine.aaPKG' --version-conflict '<E_RESOLVE_VERSION_CONFLICT_ACTION>' --name-conflict '<E_RESOLVE_NAME_CONFLICT_ACTION>' --confirm --confirm-target '.\template-work\TestMachine.aaPKG'

The exact enum values for import conflict handling must match the local GRAccess interop assembly. See graccess_operations.md and graccess_documentation.md.

Validate Script Edits

After import or checkin:

graccess object get --galaxy ZB --name TestMachine --type template --json
graccess object attributes --galaxy ZB --name TestMachine --type template --json
graccess object extended-attributes --galaxy ZB --name TestMachine --type template --json

For runtime validation, instantiate a test object and deploy only that explicitly named test instance:

graccess template instantiate --galaxy ZB --name TestMachine --type template --new-name TestMachine_ScriptTest_001 --create-contained --confirm --confirm-target TestMachine
graccess instance deploy --galaxy ZB --name TestMachine_ScriptTest_001 --type instance --confirm --confirm-target TestMachine_ScriptTest_001

Supported Object Script Command Pattern

graccess object scripts list --galaxy ZB --name TestMachine --type template --json
graccess object scripts get --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --llm-json
graccess object scripts set --galaxy ZB --name TestMachine --type template --script UpdateTestChangingInt --file .\UpdateTestChangingInt.txt --confirm --confirm-target TestMachine --llm-json

The local GRAccess examples sometimes show Template.Scripts[index].ScriptString, but this repository's installed ArchestrA.GRAccess.dll does not expose a public object script collection — it exposes script extension projections as attributes (e.g. UpdateTestChangingInt.ExecuteText). The CLI writes those attributes through the AVEVA TN-537 pattern: IgObject.ConfigurableAttributes[<script>.<field>].SetValue(MxValue), surrounded by CheckOut → Save → CheckIn. Reads use the package-export fallback when the GRAccess attribute-value accessor doesn't surface the field directly.