# Package Manager Deep Dive Date: 2026-05-05 ## Scope This investigation focused on the local System Platform package manager path that sits below GRAccess and appears to be the missing write path for object-level script body fields and some settings. Tools used: - `TlbImp.exe` against registered COM/type libraries. - .NET reflection over generated interop assemblies. - Registry inspection of `HKCR\TypeLib`. - Binary string extraction from package/runtime DLLs. - `dumpbin.exe` on native package/runtime DLLs. - Existing decompiled IDE wrapper notes under `analysis/ide-edit-investigation`. Ghidra was available at `C:\Users\dohertj2\Desktop\focas\tools\ghidra_12.0.4_PUBLIC\support\analyzeHeadless.bat`, but the registered type libraries and embedded primitive XML exposed the actionable surface without needing a full native decompile. ## Registered components ### Galaxy package server - Type library: `xxGalaxyPackageServer 1.0 Type Library` - TypeLib GUID: `{74B9B2CA-05E6-4BC4-81C3-1CAFF652035D}` - Binary: `C:\Program Files (x86)\ArchestrA\Framework\Bin\xxGalaxyPackageServer.dll` - ProgID: `XxGalaxyPackageServer.GalaxyPackage` - CLSID: `{F6C78E0D-8EA2-48B8-9592-6D9FB507DAD3}` - Threading model: `Apartment` ### Configuration access component - Type library: `ConfigurationAccessComponent 1.0 Type Library` - TypeLib GUID: `{2539619B-EA9B-4035-9AE6-71421DA6C8FD}` - Binary: `C:\Program Files (x86)\ArchestrA\Framework\Bin\ConfigurationAccessComponent.dll` - Main COM server: `ConfigurationAccessComponent.ConfigurationAccessServer` - CLSID from interop: `{55414847-A533-4642-8E92-76B191B24B87}` ### Script package - Type library: `ScriptPackage` - TypeLib GUID: `{8DF25C4D-C021-4080-849D-74A81D97D548}` - Binary: `C:\Program Files (x86)\ArchestrA\Framework\Bin\ScriptPackage.dll` - Package CLSID: `{A261929D-90AB-4217-9234-667A83756FFB}` - Managed compiler helper: `C:\Program Files (x86)\ArchestrA\Framework\Bin\ScriptPackage.Net.dll` ### Script runtime primitive definition The `ScriptExtension` primitive definition is embedded in: - `C:\Program Files (x86)\ArchestrA\Framework\Bin\ScriptRuntime.dll` Important embedded metadata: - `DefaultInternalName`: `ScriptExtension` - `Package_CLSID`: `{A261929D-90AB-4217-9234-667A83756FFB}` - `Runtime_CLSID`: `{2B2616D6-98A0-4e94-ABAD-C75BB022E2D6}` - Default `ExecutionGroup`: `Custom 1` ## Package manager surface The important public COM interfaces are already in the local package server type library. ### `IGalaxyConfiguration` / `IGalaxyConfigurationV30` This is the high-level object lifecycle and package access surface. Important methods: - `GetIDFromObjectName(Namespace nSpace, string objectName) -> int` - `GetGObjectInfoFromName(string name, Namespace nSpace)` - `CheckOutObjects(int[] gObjectIds, int hint, IGObjectOperationStatus callback)` - `CheckinObjects(int[] gObjectIds, string comment, int hint, IGObjectOperationStatus callback)` - `UndoCheckoutObjects(int[] gObjectIds, int hint, bool override, IGObjectOperationStatus callback)` - `GetObject(int objectId, ECODEMODULES codeModules, out object package, out ERRORCODE status, out string message, EPACKAGEPROP prop)` - `GetObjectInternal(int objectId, ECODEMODULES code, bool editCheckRequired, out object package, out ERRORCODE status, out string message, EPACKAGEPROP prop)` - `GetGalaxyConfigurationNet() -> object` - `GetIGalaxy() -> object` ### `IPackageManager` This is broader and includes lower-level attribute APIs. Important methods: - `GetObject(...)` - `GetObjectInternal(...)` - `GetFullObjectByName(string name) -> object` - `GetIDFromName(string name) -> int` - `ReleaseFsObjectEditsession(int fsObjectId)` - `GetObjectAttribute(Namespace, objectName, attributeName, EATTRIBUTEPROPERTY, MxValue, out result)` - `InternalSetObjectAttributesEx(Namespace, objectName, EPACKAGETYPE, string[] attributeNames, EATTRIBUTEPROPERTY[] properties, MxValue[] values, bool saveObjectEvenErrorOccurs, out status, out statusMsg)` - `InternalGetObjectAttributesEx(...)` The `InternalSetObjectAttributesEx` method is a promising direct write path because it accepts object name, package type, attribute names, property ids, and MxValues without needing the IDE configuration access component. ### `IConfigurationEditorSite2` This is the direct package editor site returned by package access calls. Important methods: - `GetAttributeCookie(string attributeFullName) -> int` - `GetAttribute(int cookie, short propertyId, MxValue value)` - `SetAttribute(int cookie, short propertyId, MxValue value) -> bool` - `Validate()` - `Commit(out string errorString) -> EPACKAGEOPERATIONSTATUS` - `IsReadOnly()` - `SetSubscriberInfo(object subscription)` - `AddExtensionPrimitive(...)` - `DeleteExtensionPrimitive(...)` - `RenameExtensionPrimitive(...)` - `AddUDA(...)` - `DeleteUDA(...)` - `RenameUDA(...)` - `UpdateUDA(...)` For normal value writes, property id `10` is `EATTRIBUTEPROPERTY.idxAttribPropValue`. ### `IPrimitivePackageSite7` The script package uses the generic primitive package site contract: - `GetAttributeHandle(string attributeFullName) -> AttributeHandle` - `GetAllCategoryAttributeHandle(string attributeFullName) -> AttributeHandle` - `GetAttribute(AttributeHandle, MxValue)` - `SetAttribute(AttributeHandle, MxValue)` - `GetAttributeHandleEx(...)` - `GetPrimitiveIdByInternalNameEx(...)` - `GetPrimitiveAttributeIds(...)` - dynamic attribute operations. The script package itself exposes: - `CoScriptPackageClass.Initialize(short primitiveId, IPrimitivePackageSite site)` - `SetHandler(ref AttributeHandle, MxValue) -> string` - `Validate() -> EPACKAGESTATUS` There is no script-specific "SetScriptText" API in the script package typelib. It is generic attribute/handler based. ## ScriptExtension attribute facts `ScriptRuntime.dll` embeds the actual script primitive attributes. The important ones: - `ExecuteText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `DeclarationsText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `StartupText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `OnScanText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `OffScanText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `ShutdownText`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `Expression`: `MxBigString`, `PackageOnly_Lockable`, `CfgSethandler=True` - `TriggerType`: `MxCustomEnum`, `Writeable_C_Lockable`, `CfgSethandler=True` - `_TriggerTypeEnum`: values `WhileTrue`, `WhileFalse`, `OnTrue`, `OnFalse`, `DataChange`, `Periodic` - `TriggerPeriod`: `MxElapsedTime`, `Writeable_C_Lockable`, `CfgSethandler=True` - `DataChangeDeadband`: `MxDouble`, `Writeable_UC_Lockable`, `CfgSethandler=True` - `RunsAsync`: `MxBoolean`, `Writeable_C_Lockable`, `CfgSethandler=True` - `ExecuteTimeout.Limit`: `MxInteger`, `Writeable_C_Lockable`, `CfgSethandler=True` - `ScriptExecutionGroup`: `MxCustomEnum`, `PackageOnly_Lockable`, `CfgSethandler=False` - `ScriptOrder`: `MxInteger`, `PackageOnly_Lockable`, `CfgSethandler=False` This confirms the current GRAccess `IAttribute.SetValue` path is not enough for script bodies. The body fields are package-only and cfg-sethandler driven. ## IDE wrapper behavior The decompiled IDE wrapper creates `ConfigurationAccessComponent.ConfigurationAccessServer`, casts it to `IConfigurationEditor`, and initializes it with the object package site: 1. `configurationEditor.Initialize("", inObjectManage, this, readOnly)` 2. `inObjectManage.SetSubscriberInfo(configurationEditor)` 3. `inObjectManage.SetSubscriberInfo(this)` 4. Subscribes to `DConfigurationAccessEvents`. 5. Sets CAS data: - `ww:SupportedLocales` - `ww:IPackageManager` - `ww:Tagname` - `ww:ContainedName` - `ww:DerivedFrom` - `ww:KeepCheckedOut` This is a full IDE editor-host path. It is probably more complete than direct attribute writes, but it requires implementing enough editor-site/event plumbing in the CLI. ## Feasible edit paths ### Path A: direct package editor site Likely flow: 1. Use existing GRAccess login to obtain `IGalaxy`. 2. Call `IGalaxy.GetGalaxyConfiguration()` and cast the returned object to `IGalaxyConfiguration` or `IGalaxyConfigurationV30`. 3. Resolve object id with `GetIDFromObjectName(Namespace.AutomationObject, tagName)`. 4. Check out the object via existing GRAccess or `CheckOutObjects`. 5. Get the editable package with `GetObjectInternal(id, eEditorAndPackageCodeModules, true, out package, ...)` or `GetObject(...)`. 6. Cast the package object to `IConfigurationEditorSite2`. 7. Resolve `scriptName.ExecuteText` with `GetAttributeCookie`. 8. Create `MxValueClass` and call `PutString(newScriptBody)`. 9. Call `SetAttribute(cookie, idxAttribPropValue, mxValue)`. 10. Call `Validate()`. 11. Call `Commit(out error)`. 12. Check in or undo checkout and release edit session on failure. Pros: - Uses typed COM APIs. - Avoids the full IDE configuration access server. - Directly targets the package-only fields. Risks: - Needs live validation that the object returned by `GetObjectInternal` supports `IConfigurationEditorSite2` in this context. - Needs confirmation that `SetAttribute` invokes the script package cfg set handler and recompiles `_Binary`. - Needs correct custom enum MxValue creation for `TriggerType`. ### Path B: package manager internal batch set Likely flow: 1. Get `IPackageManager` from the same object returned by `IGalaxy.GetGalaxyConfiguration()` or via package-manager support. 2. Check out object. 3. Call `InternalSetObjectAttributesEx` with: - `Namespace.AutomationObject` - object tagname - likely `EPACKAGETYPE.eBeingEditedPackage` - attribute names such as `UpdateTestChangingInt.ExecuteText` - property ids `[idxAttribPropValue]` - MxValues for the new data - `saveObjectEvenErrorOccurs=false` initially 4. Check status and status message. 5. Check in or undo checkout. Pros: - Smallest API surface. - No editor host required. - Best candidate for a CLI-first package write helper. Risks: - It is explicitly named `Internal`. - It may require exact package type and checkout state. - Unknown whether it invokes all cfg-sethandler compile side effects for script bodies. ### Path C: configuration access component Likely flow: 1. Get editable object package as `IConfigurationEditorSite2`. 2. Instantiate `ConfigurationAccessComponent.ConfigurationAccessServer`. 3. Implement minimal `IBaseEditorSite` and event sink in the CLI. 4. Call `IConfigurationEditor.Initialize`. 5. Set the IDE wrapper's `ww:*` data entries. 6. Set `Data("ScriptName.ExecuteText", "Value") = body`. 7. Apply/commit through the editor site. Pros: - Closest to the IDE behavior. - Most likely to run all validation/dirty/event plumbing. Risks: - Largest implementation. - Requires COM connection-point/event hosting. - More fragile in a headless CLI. ## Current CLI implication The current `object scripts set` path writes through `IAttribute.SetValue`. That cannot persist the package-only body fields shown above. The current `object scripts settings set --trigger-period-ms` should be more viable because `TriggerPeriod` is `Writeable_C_Lockable`, but it still goes through generic GRAccess `IAttribute.SetValue`. The current `object scripts settings set --trigger-type` is suspicious because `TriggerType` is `MxCustomEnum`; the CLI currently creates an `MxValue` string for non-explicit data types. The package metadata says the valid values are backed by `_TriggerTypeEnum`, so a package-manager implementation should set `TriggerType` as a custom enum or verify that package `SetAttribute` accepts the string form. ## Recommended next implementation Do not add more typelibs first. The useful typelibs already exist locally: - `ArchestrA.GRAccess.dll` - `xxGalaxyPackageServer.dll` - `ConfigurationAccessComponent.dll` - `ScriptPackage.dll` The next improvement should add a small, isolated package-manager interop layer and a probe/edit helper: 1. Add minimal `[ComImport]` declarations for only the needed package-manager interfaces, or add a checked-in interop reference generated from `xxGalaxyPackageServer.dll`. 2. Bridge from `IGalaxy.GetGalaxyConfiguration()` to `IGalaxyConfigurationV30` / `IPackageManager`. 3. Implement a read-only probe first: - object id resolution - `GetObjectInternal` - cast checks for `IConfigurationEditorSite2`, `IObjectManage`, `IPackageManager` - `GetAttributeCookie` for script fields/settings - `GetAttribute` for `idxAttribPropValue` 4. Implement one guarded write path for `ExecuteText`. 5. Verify whether `_Binary`, `_ErrorMessage`, `_ErrorLine`, and `_ErrorColumn` update after commit. If they do not, switch from Path A/B to the CAS path. 6. Only then wire it into `object scripts set` and package-only script settings. ## Live validation blocker Previous live GRAccess validation against the `ZB` galaxy failed because the local license was unavailable: `cmdLicenseUnavailable (105); Feature 'wspdevstudio-iocount'` The package-manager write path needs live validation after license access is restored because static metadata cannot prove whether script cfg-sethandler side effects fire on direct package writes.