Automate with pb-diff-cli
Everything the desktop application opens is a window for a person.
When there must not be one, as in a build step, a CI job, a pre-commit
hook or an AI coding agent, use pb-diff-cli.exe, installed
beside pb-diff.exe. It never creates a window, never
prompts and never reads standard input, writes its result to standard
output, and reports the outcome as an exit code. It needs no
PowerBuilder and reads no machine settings, so the same command line
gives the same bytes on every machine.
pb-diff-cli list ui.pbl --format json
pb-diff-cli export "ui.pbl!*.srw" --out-dir .\windows
pb-diff-cli compare old\w_main.srw new\w_main.srw --format json
pb-diff-cli compare-lib old.pbl new.pbl --changed-only --format json
pb-diff-cli merge3 mine.srw base.srw theirs.srw --output merged.srw --format json
pb-diff-cli report changes old\w_main.srw new\w_main.srw --output review.html --format json
pb-diff-cli check src\ws_objects --format json
On a build machine, use pb-diff-ci.exe instead: it needs
no licence and no network, and has the commands that stay at the level
of the object. See Run pb-diff in
CI.
Two rules
Pass --format json to every command.
Text output is prose for a person and may be reworded between releases;
the JSON payloads, their schemaVersion and the published
schemas are the contract. --format json is the machine form
of every command, report included.
--report-format makes a different choice: the rendition a
reader gets, which can be PDF, HTML, CSV, JSON, RTF or Markdown.
Read the exit code before the payload. The outcome is one of six codes, and a caller has to branch on the one it receives. Treating any non-zero code as a failure turns the requested answer, "these two releases differ", into a broken build.
| Code | Meaning |
|---|---|
| 0 | Success; for compares, no differences; for check, nothing noticed |
| 1 | Compares: differences found. Validate: warnings only. Check: findings |
| 2 | Invalid input, missing file or entry, or bad arguments |
| 3 | Three-way merge left conflicts |
| 4 | Internal error |
| 5 | No valid licence |
Code 3 is what merge3 returns when conflicts are left,
and in that case no merged file is written. Code 4 is a bug in pb-diff
and is worth reporting. Code 5 means the machine running the command has
no valid licence: every command but help,
schema and license needs one. A CI job uses
pb-diff-ci, which needs none, and a build server that needs
pb-diff-cli activates its service account (see Run it on a
build server or in CI).
A first gate
Run from the docs\examples\order-desk folder of the
installation, this PowerShell gate lists what changed between the two
library releases of the Order Desk
examples, and fails only when the input was unusable. It reads the
exit code first, because exit code 2 leaves standard output empty and
puts the error on standard error:
$raw = pb-diff-cli compare-lib libraries/release-1.4/orders.pbl libraries/release-1.5/orders.pbl --changed-only --format json | Out-String
switch ($LASTEXITCODE) {
0 { 'No object changed.' }
1 { ($raw | ConvertFrom-Json).entries | ForEach-Object { '{0,-9} {1}' -f $_.status, $_.name } }
default { throw "Comparing the libraries failed with exit code $LASTEXITCODE." }
}
It prints eleven lines, one per changed object, such as
modified d_order_lines.srd. The examples folder also
holds, under results, the JSON of every command this Help
runs, so a script or an agent can see a real payload before it reads one
of its own.
A merge without the window
pb-diff-cli merge3 applies every change only one side
made and reports the rest:
pb-diff-cli merge3 mine/n_pricing.sru base/n_pricing.sru theirs/n_pricing.sru --output merged/n_pricing.sru --format json
Exit code 0 means the merge was clean and
merged/n_pricing.sru was written; exit code 3 means
conflicts remain, in which case nothing is written and the JSON lists
each conflict with its node, the base line range and the text each side
wanted. --force-partial writes anyway, taking the Base for
every conflict. The merged file is exactly what Save
writes in the desktop application: UTF-16LE with a byte-order mark and
CRLF, or UTF-8 when the Base is a PowerBuilder 2025 Solution source. The
JSON on standard output follows its own contract and is UTF-8 without a
mark.
When a hook cannot show a window
Some source-control hooks and pipelines cannot show a window at all. Use the CLI there:
pb-diff-cli compare old\w_main.srw new\w_main.srw --format json
Exit code 0 means no differences, 1 means differences were found, 2
means the input was unusable. A pre-commit hook or a CI gate can branch
on it directly. pb-diff.exe, by contrast, is the desktop
application: a build script that calls it waits for a window nobody will
close.
Agents
An AI coding agent should call pb-diff-cli.exe and
follow the two rules above. The first part of the Command-Line Tool
Reference, Using
pb-diff-cli from a script or an AI agent, is the authoritative
reference for inventorying a library, comparing two releases, gating a
build with compare-lib --changed-only, and resolving and
verifying a three-way merge. For instructions an agent can load
directly, use skills\pb-diff\SKILL.md in the installation
folder. The same limits apply to an agent as to a person: libraries
remain read-only, compiled entries are not decompiled, renames must be
declared, and pb-diff does not compile the object an agent writes.
The full reference
Help ▸ Command-Line Tool Reference opens the Command-Line Tool Reference: every
command, its options, the addressing syntax, the payloads and the exit
codes. pb-diff-cli help --format json gives the same
catalogue as data, and pb-diff-cli schema prints the
published schemas. pb-diff-cli help holds to the same
contract as the commands it describes: an unknown command or an unknown
option exits 2 and says so, whichever format was asked for, and
pb-diff-cli <command> --help shows the help without
running anything.