trxa-tool 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/.claude/skills/replay-trxa-testplan/SKILL.md +627 -0
  2. package/LICENSE +120 -0
  3. package/MANUAL.md +556 -0
  4. package/README.md +91 -3
  5. package/SETUP.md +401 -0
  6. package/STUDIO.md +427 -0
  7. package/dist/analyze.d.ts +58 -0
  8. package/dist/analyze.js +122 -0
  9. package/dist/bpm.d.ts +40 -0
  10. package/dist/bpm.js +60 -0
  11. package/dist/build-test-script.d.ts +24 -0
  12. package/dist/build-test-script.js +40 -0
  13. package/dist/csv.d.ts +1 -0
  14. package/dist/csv.js +11 -0
  15. package/dist/extract.d.ts +14 -0
  16. package/dist/extract.js +34 -0
  17. package/dist/fixture-schema.d.ts +52 -0
  18. package/dist/fixture-schema.js +112 -0
  19. package/dist/fixture-store.d.ts +37 -0
  20. package/dist/fixture-store.js +75 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +850 -0
  23. package/dist/library-archive.d.ts +37 -0
  24. package/dist/library-archive.js +106 -0
  25. package/dist/mapping.d.ts +25 -0
  26. package/dist/mapping.js +393 -0
  27. package/dist/mcp-bridge.d.ts +52 -0
  28. package/dist/mcp-bridge.js +290 -0
  29. package/dist/normalize.d.ts +21 -0
  30. package/dist/normalize.js +43 -0
  31. package/dist/parse.d.ts +3 -0
  32. package/dist/parse.js +233 -0
  33. package/dist/plan-runner.d.ts +27 -0
  34. package/dist/plan-runner.js +36 -0
  35. package/dist/plan-schema.d.ts +27 -0
  36. package/dist/plan-schema.js +45 -0
  37. package/dist/planrun-schema.d.ts +53 -0
  38. package/dist/planrun-schema.js +111 -0
  39. package/dist/planrun.d.ts +20 -0
  40. package/dist/planrun.js +46 -0
  41. package/dist/report-schema.d.ts +92 -0
  42. package/dist/report-schema.js +115 -0
  43. package/dist/report.d.ts +45 -0
  44. package/dist/report.js +77 -0
  45. package/dist/schema.d.ts +96 -0
  46. package/dist/schema.js +10 -0
  47. package/dist/scrub.d.ts +44 -0
  48. package/dist/scrub.js +166 -0
  49. package/dist/suggest-inputs.d.ts +19 -0
  50. package/dist/suggest-inputs.js +92 -0
  51. package/dist/suite-runner.d.ts +59 -0
  52. package/dist/suite-runner.js +204 -0
  53. package/dist/suite-schema.d.ts +59 -0
  54. package/dist/suite-schema.js +95 -0
  55. package/dist/testcase-schema.d.ts +102 -0
  56. package/dist/testcase-schema.js +132 -0
  57. package/dist/token-usage.d.ts +38 -0
  58. package/dist/token-usage.js +95 -0
  59. package/media/studio/fixtures-test-cases.png +0 -0
  60. package/media/studio/plans-editor.png +0 -0
  61. package/media/studio/recordings-create-test-case.png +0 -0
  62. package/media/studio/run-dialog.png +0 -0
  63. package/media/studio/settings-agent-runs.png +0 -0
  64. package/media/studio/settings-working-folder.png +0 -0
  65. package/media/studio/studio-recordings.png +0 -0
  66. package/media/studio/suites-canvas.png +0 -0
  67. package/media/studio/suites-inspector.png +0 -0
  68. package/media/studio/testcases-expectations.png +0 -0
  69. package/media/studio/testcases-outputs.png +0 -0
  70. package/media/studio/testrun-details.png +0 -0
  71. package/media/studio/testruns-list.png +0 -0
  72. package/package.json +62 -6
  73. package/studio/client-dist/assets/CreatePanel-C5bb5OIs.js +6 -0
  74. package/studio/client-dist/assets/FactTile-G1pURLys.js +1 -0
  75. package/studio/client-dist/assets/FieldLabel-DPmIEQ08.js +1 -0
  76. package/studio/client-dist/assets/FixtureNamePicker-137AAgwZ.js +1 -0
  77. package/studio/client-dist/assets/Fixtures-D0t-soph.js +1 -0
  78. package/studio/client-dist/assets/GeneralSection-CWkTeSX2.js +1 -0
  79. package/studio/client-dist/assets/ListPaneHeader-DXKqX36N.js +1 -0
  80. package/studio/client-dist/assets/Plans-C70evkGc.js +1 -0
  81. package/studio/client-dist/assets/Recordings-BT0dyVLs.js +1 -0
  82. package/studio/client-dist/assets/Settings-k-J3u5lH.js +1 -0
  83. package/studio/client-dist/assets/Suites-DLioOiRN.css +1 -0
  84. package/studio/client-dist/assets/Suites-DQhhMxjT.js +7 -0
  85. package/studio/client-dist/assets/TestCases-BdiopVGI.js +1 -0
  86. package/studio/client-dist/assets/TestRuns-CylAe-3t.js +9 -0
  87. package/studio/client-dist/assets/api-DJZ703_F.js +24 -0
  88. package/studio/client-dist/assets/bucket-18-viuwGcaj.js +1 -0
  89. package/studio/client-dist/assets/fixtureName-CTZT_jKu.js +1 -0
  90. package/studio/client-dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  91. package/studio/client-dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  92. package/studio/client-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  93. package/studio/client-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  94. package/studio/client-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  95. package/studio/client-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  96. package/studio/client-dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  97. package/studio/client-dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  98. package/studio/client-dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  99. package/studio/client-dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  100. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-300-normal-LoaTnByX.woff +0 -0
  101. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-300-normal-RhT0Ayi3.woff2 +0 -0
  102. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-400-italic-Bf1n82Tb.woff +0 -0
  103. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-400-italic-D9J6q4_O.woff2 +0 -0
  104. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-400-normal-BTotfTJu.woff +0 -0
  105. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-400-normal-DZqxrq2p.woff2 +0 -0
  106. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-600-normal-71GNu3SW.woff2 +0 -0
  107. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-600-normal-BGq0mW3O.woff +0 -0
  108. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-300-normal-Bbd5v1xK.woff +0 -0
  109. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-300-normal-DqmgDkIN.woff2 +0 -0
  110. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-400-italic-BELOEI8R.woff2 +0 -0
  111. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-400-italic-CfSXsIbO.woff +0 -0
  112. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-Dsrv2Tcn.woff +0 -0
  113. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-400-normal-g30qAdWV.woff2 +0 -0
  114. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-Bz0x94Yp.woff +0 -0
  115. package/studio/client-dist/assets/ibm-plex-sans-cyrillic-ext-600-normal-DUMzJB7m.woff2 +0 -0
  116. package/studio/client-dist/assets/ibm-plex-sans-greek-300-normal-J-CBqZoJ.woff2 +0 -0
  117. package/studio/client-dist/assets/ibm-plex-sans-greek-300-normal-STc8XiDr.woff +0 -0
  118. package/studio/client-dist/assets/ibm-plex-sans-greek-400-italic-BEZwmy7D.woff2 +0 -0
  119. package/studio/client-dist/assets/ibm-plex-sans-greek-400-italic-CTYLy0lX.woff +0 -0
  120. package/studio/client-dist/assets/ibm-plex-sans-greek-400-normal-D9ESIMu3.woff +0 -0
  121. package/studio/client-dist/assets/ibm-plex-sans-greek-400-normal-_efipK4i.woff2 +0 -0
  122. package/studio/client-dist/assets/ibm-plex-sans-greek-600-normal-D-CqTdkO.woff +0 -0
  123. package/studio/client-dist/assets/ibm-plex-sans-greek-600-normal-DzTrcv_p.woff2 +0 -0
  124. package/studio/client-dist/assets/ibm-plex-sans-latin-300-normal-C9Of02-5.woff +0 -0
  125. package/studio/client-dist/assets/ibm-plex-sans-latin-300-normal-b4i7YzLG.woff2 +0 -0
  126. package/studio/client-dist/assets/ibm-plex-sans-latin-400-italic-CZTNEAuW.woff2 +0 -0
  127. package/studio/client-dist/assets/ibm-plex-sans-latin-400-italic-CsGl1sm0.woff +0 -0
  128. package/studio/client-dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  129. package/studio/client-dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  130. package/studio/client-dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  131. package/studio/client-dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  132. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-300-normal-B8Zgwjh3.woff +0 -0
  133. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-300-normal-BLFuR0P1.woff2 +0 -0
  134. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-400-italic-Du9zzoL2.woff2 +0 -0
  135. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-400-italic-V_9i1P_m.woff +0 -0
  136. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-400-normal-C5H60-Va.woff2 +0 -0
  137. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-400-normal-RBey6euL.woff +0 -0
  138. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-600-normal-DIrixKbi.woff +0 -0
  139. package/studio/client-dist/assets/ibm-plex-sans-latin-ext-600-normal-DOrvGEcy.woff2 +0 -0
  140. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-300-normal-CkYRZD2a.woff +0 -0
  141. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-300-normal-SDfX6ktj.woff2 +0 -0
  142. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-400-italic-78jqtfZH.woff +0 -0
  143. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-400-italic-BbRnwouv.woff2 +0 -0
  144. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-400-normal-DG4YqDda.woff2 +0 -0
  145. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-400-normal-fK1oJ5dG.woff +0 -0
  146. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-600-normal-DgdngZtN.woff +0 -0
  147. package/studio/client-dist/assets/ibm-plex-sans-vietnamese-600-normal-DpPYBSTl.woff2 +0 -0
  148. package/studio/client-dist/assets/index-cxBc2iRv.js +10 -0
  149. package/studio/client-dist/assets/index-wjWuVHXN.css +1 -0
  150. package/studio/client-dist/assets/status-DUGxC7G7.js +1 -0
  151. package/studio/client-dist/assets/testCaseTree-Cl1-bc5O.js +1 -0
  152. package/studio/client-dist/axtr-icon.svg +2 -0
  153. package/studio/client-dist/favicon.svg +2 -0
  154. package/studio/client-dist/index.html +15 -0
  155. package/studio/server/dist/index.js +3176 -0
package/MANUAL.md ADDED
@@ -0,0 +1,556 @@
1
+ # TRXA-TOOL manual
2
+
3
+ This manual explains how to use the `trxa` command line to turn Dynamics 365 Finance and Supply
4
+ Chain Management Task Recorder recordings (`.axtr` files) into automated, data-driven tests, and
5
+ how an AI agent runs those tests against an environment through the Dynamics 365 ERP MCP server.
6
+ It also documents every file format that TRXA-TOOL reads and writes.
7
+
8
+ If you prefer a visual workspace, [TRXA Studio](STUDIO.md) does everything in this manual without
9
+ editing files by hand. Studio and the command line use the same files, so you can switch between
10
+ them at any time.
11
+
12
+ ## How TRXA-TOOL works
13
+
14
+ TRXA-TOOL works with seven kinds of files. Each one builds on the one before it.
15
+
16
+ ```text
17
+ .axtr recording A Task Recorder file, recorded in Dynamics 365 or exported
18
+ | from a Business Process Modeler library in Lifecycle Services.
19
+ | trxa parse
20
+ v
21
+ Test script The recording's ordered steps, each with a suggested MCP tool call.
22
+ (testscripts/*.json) Generic: it never hard-codes a business value.
23
+ |
24
+ | trxa suggest-inputs (optional: drafts a starting point)
25
+ v
26
+ Test case One pass/fail scenario. You define its inputs, the values it
27
+ (testcases/*.json) captures (outputs), and what a passing run looks like (expectations).
28
+ |
29
+ v
30
+ Fixture A named set of test data, such as one company or one scenario,
31
+ (testdata/*.json) with input values for every test case it covers.
32
+ |
33
+ | a suite combines test cases with a fixture and defines their order
34
+ v
35
+ Test suite Which test cases run, in what order, and where each input
36
+ (suites/*.json) gets its value: a fixture, a literal, or an earlier test case's output.
37
+ |
38
+ | optional: group related suites for combined reporting
39
+ v
40
+ Test plan A list of suites that run and report together, such as every
41
+ (plans/*.json) suite for Accounts receivable. Suites in a plan don't share data.
42
+ |
43
+ | trxa init-run
44
+ v
45
+ Test run Pass or fail per test case, captured outputs, and the result of
46
+ (testruns/*.json) each check. Every run is kept, never overwritten.
47
+ ```
48
+
49
+ TRXA-TOOL handles everything that has a fixed answer: reading recordings, ordering test cases,
50
+ detecting dependency loops, resolving input values and rolling up plan results. An AI agent, using
51
+ the `replay-trxa-testplan` skill, does everything that needs a live Dynamics 365 session. It asks
52
+ `trxa resolve-next` which test case to run, replays that test case's test script through the
53
+ `d365-erp-mcp` server, checks its expectations, and calls `trxa record-result` to save the outcome.
54
+
55
+ ## Prerequisites
56
+
57
+ Before you run a suite against an environment, make sure that you have:
58
+
59
+ - **Node.js** 18.19 or later. To check, run `node --version`.
60
+ - **An AI agent that can use MCP tools**, such as GitHub Copilot CLI, Claude Code, Claude Cowork or
61
+ Codex.
62
+ - **The `d365-erp-mcp` MCP server**, connected to the environment that you want to test and
63
+ available to your agent. For setup instructions, including the `trxa mcp-bridge` connector, see
64
+ [Set up TRXA Studio for agent runs](SETUP.md).
65
+ - **One or more `.axtr` recordings.** Record them in Dynamics 365 with Task recorder, or export
66
+ them from a Business Process Modeler library in Lifecycle Services.
67
+
68
+ ## Install TRXA-TOOL
69
+
70
+ 1. Install the package globally. This puts the `trxa` command on your `PATH`. Every command in
71
+ this manual uses it.
72
+
73
+ ```sh
74
+ npm install -g trxa-tool
75
+ ```
76
+
77
+ 1. Confirm the installation. The command lists every `trxa` command.
78
+
79
+ ```sh
80
+ trxa help
81
+ ```
82
+
83
+ 1. In your project folder, where your recordings, test cases and suites will be, install the
84
+ replay skill:
85
+
86
+ ```sh
87
+ trxa init-skill
88
+ ```
89
+
90
+ Agents find project skills in their own folders, not inside an installed package. `init-skill`
91
+ copies the `replay-trxa-testplan` skill into `.claude/skills` (used by Claude Code and GitHub
92
+ Copilot CLI) and `.agents/skills` (used by Codex). Run it once per project.
93
+
94
+ TRXA Studio is included in the package. To start it, run `trxa studio`.
95
+
96
+ ## Project folders
97
+
98
+ TRXA-TOOL expects these folders in your project. To decide which of them to commit to source
99
+ control, see [Data hygiene](#data-hygiene).
100
+
101
+ | Folder | Contents |
102
+ |---|---|
103
+ | `recordings` | Task Recorder recordings (`.axtr`) |
104
+ | `testscripts` | Test scripts, created by `trxa parse` |
105
+ | `testcases` | Test cases: your reusable test library |
106
+ | `testdata` | Fixtures: test data values |
107
+ | `suites` | Test suites: run order and data flow |
108
+ | `plans` | Test plans: groups of suites for combined reporting |
109
+ | `runs` | Plan run records, created by `trxa init-plan-run` |
110
+ | `testruns` | Test run results, one file per suite run |
111
+
112
+ ## Data hygiene
113
+
114
+ Read this section before you add a library of real recordings. A recording captures whatever the
115
+ user worked with when it was made, such as real account numbers, journal entries, amounts and
116
+ customer names. Test scripts carry the same data forward, and the `example` values that
117
+ `suggest-inputs` drafts are copied directly from the recording.
118
+
119
+ If you keep your project in source control, consider these practices:
120
+
121
+ - **Ignore `recordings` and `testdata` by default** in `.gitignore`. Allow only files that you
122
+ reviewed and know are safe to share, such as recordings made with standard demo data.
123
+ - **Ignore `testscripts` and `testruns` entirely.** You can regenerate test scripts from the
124
+ recordings with `trxa parse`, and test runs are output.
125
+ - **Review the `example` fields** of every test case before you commit it, and replace real
126
+ business data with placeholders.
127
+ - **Keep the `analysis` folder local.** The `library-report.json` file that `analyze-library`
128
+ writes replaces every recorded value with a token, so it's safe to share with a cloud AI service.
129
+ The `scrubbed-values.csv` file maps those tokens back to the real values, so never open it where
130
+ an AI service can read it.
131
+
132
+ ## Command reference
133
+
134
+ Run each command as `trxa <command>`. To see a command's options, run it with no arguments.
135
+
136
+ | Command | Description |
137
+ |---|---|
138
+ | `parse <file.axtr> [-o out.testscript.json]` | Reads a recording and writes its test script. |
139
+ | `suggest-inputs <file.axtr> [-o draft.json]` | Drafts candidate test case inputs from a recording. |
140
+ | `validate-testcase <testcase.json>` | Checks a test case file. |
141
+ | `validate-fixture <fixture.json>` | Checks a fixture file. |
142
+ | `migrate-fixtures <testdata-dir> [--dry-run]` | Merges fixture files in the old one-test-case format into one file per fixture. See [Create a fixture](#step-4-create-a-fixture). |
143
+ | `validate-suite <suite.json>` | Checks a suite file, including dependency loops and unknown test case IDs. |
144
+ | `plan-suite <suite.json>` | Prints the order that a suite's test cases run in. |
145
+ | `validate-plan <plan.json>` | Checks a plan file, and that every suite it refers to exists and is valid. |
146
+ | `init-skill [--force]` | Copies the `replay-trxa-testplan` skill into the project's `.claude/skills` and `.agents/skills` folders. Doesn't overwrite an existing copy unless you add `--force`. |
147
+ | `mcp-bridge` | Connects an agent to an environment's Dynamics 365 ERP MCP server. The agent starts it; you don't run it yourself. See [Step 5](SETUP.md#step-5-connect-the-agent-to-dynamics-365) of the setup article. |
148
+ | `init-plan-run <plan.json> -o runs/ [--name "<run name>"]` | Creates a plan run record with a generated ID. Run it once per plan run, before you run any of its suites. `--name` labels the run, for example `"AP regression, PQU 10.0.48"`. |
149
+ | `init-run <suite.json> -o testruns/<suiteId>-<runId>.json [--name "<run name>"]` | Creates a test run with every test case set to `pending`. `--name` labels the run. |
150
+ | `resolve-next <suite.json> <testrun.json> --testcases-dir <dir> [--fixtures-dir <dir>]` | Returns the next test case to run, with its inputs resolved, or reports `blocked`, `waiting` or `complete`. |
151
+ | `record-result <testrun.json> <testCaseId> --status passed\|failed\|blocked --outputs '{...}' [--assertions '[...]']` | Saves a test case's outcome. Each JSON option has a file form: `--outputs-file`, `--assertions-file`, `--inputs-file` and `--messages-file`. See [Pass JSON through files in Windows PowerShell](#pass-json-through-files-in-windows-powershell). |
152
+ | `measure-tokens --since <isoTimestamp> --until <isoTimestamp> [--transcript <path>]` | Adds up the tokens that Claude Code used in a time window. `record-result` already does this. See [Token and cost reporting](#token-and-cost-reporting). |
153
+ | `plan-status <plan.json> <run.json> --testruns-dir <dir>` | Rolls up pass and fail across every suite in a plan for one plan run. |
154
+ | `analyze-library <recordingsDir> [--report ...] [--csv ...]` | Reports coverage and gaps across a whole recordings library without exposing recorded values. See [Data hygiene](#data-hygiene). |
155
+ | `studio` | Starts TRXA Studio in the background and opens `http://127.0.0.1:4321` in your browser. See [Use TRXA Studio](STUDIO.md). |
156
+ | `studio stop` | Stops TRXA Studio. |
157
+ | `export -o <backup.zip>` | Bundles the `recordings`, `testcases`, `testdata`, `testscripts`, `suites`, `plans` and `testruns` folders into one zip file. |
158
+ | `import <backup.zip> [--force]` | Restores a library backup. Stops if a file already exists, unless you add `--force`. |
159
+
160
+ If an input is invalid, every command prints a specific error and exits with a nonzero code.
161
+
162
+ ### Pass JSON through files in Windows PowerShell
163
+
164
+ Windows PowerShell 5.1 can corrupt JSON that you pass directly as a command-line argument, before
165
+ `trxa` receives it. It removes the double quotes from JSON without spaces, and splits JSON with
166
+ spaces into several arguments. Either way, `record-result` fails with a JSON syntax error even
167
+ though the command looks correct.
168
+
169
+ Instead, use the file form of each JSON option. Write the JSON to a file, and then pass the file's
170
+ path:
171
+
172
+ ```powershell
173
+ [IO.File]::WriteAllText("$PWD\outputs.json", '{"PurchId":"PO-0001"}')
174
+ trxa record-result testruns/my-run.json create-order --status passed --outputs-file outputs.json
175
+ ```
176
+
177
+ Write the file without a byte order mark, as in this example. In PowerShell 5.1,
178
+ `Set-Content -Encoding utf8` and `Out-File` add one, and the JSON then fails to parse.
179
+
180
+ The file form works the same in every shell, so it's a safe default anywhere. The replay skill
181
+ already uses it.
182
+
183
+ ## Tutorial: Build and run your first suite
184
+
185
+ This tutorial builds a suite of two test cases: one creates a sales order, and the next posts its
186
+ packing slip. The names are generic, so the steps apply to any scenario.
187
+
188
+ ### Step 1: Parse your recording
189
+
190
+ ```sh
191
+ trxa parse recordings/my-recording.axtr -o testscripts/my-recording.testscript.json
192
+ ```
193
+
194
+ Open the output and review `steps`. Each step has a `hint`, the suggested `d365-erp-mcp` tool call,
195
+ with a `confidence` of `high`, `medium` or `low`. Low-confidence steps are almost always steps that
196
+ find and select a record. The recording captured only a position on the screen, not a business
197
+ key, so those steps need to become test case inputs.
198
+
199
+ ### Step 2: Draft candidate inputs
200
+
201
+ ```sh
202
+ trxa suggest-inputs recordings/my-recording.axtr -o testcases/my-recording.draft.json
203
+ ```
204
+
205
+ The command proposes one candidate input for each value typed in the recording
206
+ (`PropertyUserAction`) and one for each low-confidence record selection. Each candidate has a
207
+ `bindTo` that names the step and control it applies to and, for typed values, the recorded
208
+ `example`. Review the examples and remove any real business data before you share them. The draft
209
+ isn't a valid test case yet. It's the `inputs` array that you copy into one.
210
+
211
+ ### Step 3: Create the test case
212
+
213
+ Create `testcases/<your-id>.json`:
214
+
215
+ ```jsonc
216
+ {
217
+ "id": "create-order", // unique within a suite
218
+ "name": "Select customer and open their sales order",
219
+ "description": "...",
220
+ "testScriptPath": "../testscripts/my-recording.testscript.json", // relative to this file
221
+ "inputs": [
222
+ {
223
+ "name": "customerAccount", // referenced by suite inputBindings
224
+ "description": "...",
225
+ "example": "US-001", // optional, from suggest-inputs
226
+ "required": true,
227
+ "bindTo": {
228
+ "kind": "grid-row-selector", // or "kind": "control" + "controlName"
229
+ "stepSequence": 21,
230
+ "note": "In the list, find and select the desired record."
231
+ }
232
+ }
233
+ ],
234
+ "outputs": [
235
+ {
236
+ "name": "salesOrderId",
237
+ "kind": "odata", // preferred when a reliable business key exists
238
+ "entitySet": "SalesOrderHeadersV2",
239
+ "filter": "CustomerAccount eq '{{customerAccount}}'", // {{name}} = resolved input value
240
+ "field": "SalesOrderNumber"
241
+ }
242
+ // Alternative for a value that's only on screen, such as a number assigned by the system.
243
+ // No extra query is needed at replay time:
244
+ // { "name": "...", "kind": "uiField", "afterStepSequence": N, "controlName": "..." }
245
+ // If you don't know the control name yet, use "hint" (plain English). The agent finds the
246
+ // control during the run and writes its exact controlName back for later runs:
247
+ // { "name": "...", "kind": "uiField", "afterStepSequence": N, "hint": "..." }
248
+ ],
249
+ "expectations": [
250
+ {
251
+ "description": "No error dialog appeared",
252
+ "checkAfterStepSequence": 46,
253
+ "kind": "uiMessage", // use when there's no entity to query
254
+ "severity": "Error",
255
+ "pattern": "", // plain text match; empty = any message of this severity
256
+ "shouldExist": false
257
+ }
258
+ // Preferred alternative:
259
+ // { "description": "...", "checkAfterStepSequence": N, "kind": "odata", "entitySet": "...",
260
+ // "filter": "...", "expectedField": "...", "expectedValue": "...", "comparator": "equals" }
261
+ ]
262
+ }
263
+ ```
264
+
265
+ The following table describes the fields.
266
+
267
+ | Field | Type | Description |
268
+ |---|---|---|
269
+ | `id`, `name`, `description` | `string` | `id` must be unique within every suite that uses the test case. |
270
+ | `testScriptPath` | `string` | The path to the test script, relative to the test case file. |
271
+ | `inputs[].bindTo.kind` | `"control"` or `"grid-row-selector"` | `"control"` needs `controlName`. `"grid-row-selector"` needs a `note` that says what to search for. |
272
+ | `outputs[].kind` | `"odata"` or `"uiField"` | `"odata"` needs `entitySet`, `filter` and `field`. `"uiField"` needs `afterStepSequence` and at least one of `controlName` (exact, no query needed) or `hint` (plain English, for when you don't know the control name; the agent writes the control name back after it finds it). |
273
+ | `expectations[].kind` | `"odata"` or `"uiMessage"` | `"odata"` needs `entitySet`, `filter`, `expectedField`, `expectedValue` and `comparator` (`equals`, `notEquals`, `contains`, `greaterThan` or `lessThan`). `"uiMessage"` needs `severity` (`Info`, `Warning` or `Error`), `pattern` (plain text that the message contains, not a regular expression; empty matches any message of that severity) and `shouldExist` (whether a matching message must appear). |
274
+
275
+ `filter` and `expectedValue` can contain `{{inputName}}` placeholders. The agent replaces each one
276
+ with the resolved input value before it runs the query. The replacement is plain text, not a
277
+ template language.
278
+
279
+ Check the file as you work:
280
+
281
+ ```sh
282
+ trxa validate-testcase testcases/create-order.json
283
+ ```
284
+
285
+ ### Step 4: Create a fixture
286
+
287
+ A fixture is one set of test data, such as one company or one scenario, with values for every test
288
+ case it covers. Create `testdata/<fixture-name>.json`:
289
+
290
+ ```json
291
+ {
292
+ "name": "basic",
293
+ "description": "US company, standard customer",
294
+ "testCases": {
295
+ "create-order": { "customerAccount": "US-001" },
296
+ "post-packing-slip": { "warehouse": "11" }
297
+ }
298
+ }
299
+ ```
300
+
301
+ Suites refer to the fixture by `name`, which must match the file name. A name can contain letters,
302
+ digits, spaces, periods, underscores and hyphens, and fixture names must be unique, ignoring case.
303
+ A test case can have values in several fixtures, such as `basic` and `eu-company`. The suite
304
+ chooses which fixture to use (see [Step 5](#step-5-create-the-suite)), so the same test case can
305
+ run with different data.
306
+
307
+ ```sh
308
+ trxa validate-fixture testdata/basic.json
309
+ ```
310
+
311
+ > [!NOTE]
312
+ > Earlier versions stored one test case's values per fixture file
313
+ > (`testdata/<test-case-id>.<fixture-name>.json`, with `testCaseId` and `values`). Those files
314
+ > still work, because `resolve-next` merges files with the same `name`. To convert them to the
315
+ > current format, run `trxa migrate-fixtures testdata --dry-run` to preview the changes, and then
316
+ > run it again without `--dry-run`. The command checks everything before it writes. If two files
317
+ > hold values for the same test case under the same fixture name, it changes nothing and names
318
+ > both files.
319
+
320
+ ### Step 5: Create the suite
321
+
322
+ Create `suites/<your-id>.json`:
323
+
324
+ ```json
325
+ {
326
+ "id": "packing-slip-flow",
327
+ "name": "Create order then post its packing slip",
328
+ "entries": [
329
+ {
330
+ "testCaseId": "create-order",
331
+ "dependsOn": [],
332
+ "inputBindings": {
333
+ "customerAccount": { "kind": "fixture", "fixtureName": "basic", "param": "customerAccount" }
334
+ }
335
+ },
336
+ {
337
+ "testCaseId": "post-packing-slip",
338
+ "dependsOn": ["create-order"],
339
+ "inputBindings": {
340
+ "salesOrderId": { "kind": "testCaseOutput", "testCaseId": "create-order", "outputName": "salesOrderId" }
341
+ }
342
+ }
343
+ ]
344
+ }
345
+ ```
346
+
347
+ Each input binding has one of these kinds:
348
+
349
+ | `kind` | Fields | The value comes from |
350
+ |---|---|---|
351
+ | `"fixture"` | `fixtureName`, `param` | The named fixture's values for this test case. |
352
+ | `"testCaseOutput"` | `testCaseId`, `outputName` | An output captured by an upstream test case that already passed. This is how data flows through a suite. |
353
+ | `"literal"` | `value` | A value written in the suite file. Use it for constants, not for real business data. |
354
+ | `"autogenerated"` | None | The agent. `resolve-next` lists the input in `autogeneratedParams`, with its `description` and `example` as guidance, and the agent invents a value during the run. Use it for values that only need to be unique, such as a new business key. |
355
+
356
+ An entry can also have a `runIf` condition that skips it. For example, add this to
357
+ `post-packing-slip`:
358
+
359
+ ```json
360
+ "runIf": { "testCaseId": "create-order", "outputName": "currency", "comparator": "equals", "value": "USD" }
361
+ ```
362
+
363
+ `testCaseId` must be one of the entry's own `dependsOn` test cases. When `runIf` is evaluated, that
364
+ dependency has already passed, so the condition compares one of its outputs, not its status. If
365
+ the condition is false, the entry is recorded as `skipped` instead of running. A skipped entry is
366
+ neither a pass nor a failure. Entries that depend on a skipped entry are reported as `blocked`.
367
+
368
+ Check the suite, and print its run order:
369
+
370
+ ```sh
371
+ trxa validate-suite suites/packing-slip-flow.json
372
+ trxa plan-suite suites/packing-slip-flow.json
373
+ ```
374
+
375
+ `validate-suite` immediately reports a dependency loop, or a `dependsOn` that names a test case
376
+ that isn't in the suite.
377
+
378
+ > [!NOTE]
379
+ > `plan-suite` prints a suite's execution plan. The name predates test plans and isn't related to
380
+ > them. For test plans, see [Group suites into a test plan](#group-suites-into-a-test-plan).
381
+
382
+ ### Step 6: Start a run
383
+
384
+ ```sh
385
+ trxa init-run suites/packing-slip-flow.json -o testruns/packing-slip-flow-$(date +%s).json
386
+ ```
387
+
388
+ ### Step 7: Ask your agent to run the suite
389
+
390
+ Open a session in your agent, with `d365-erp-mcp` connected, and ask it to run the suite. The agent
391
+ uses the `replay-trxa-testplan` skill. To be explicit, name the skill, for example: *"Use the
392
+ replay-trxa-testplan skill to run suites/packing-slip-flow.json against
393
+ testruns/packing-slip-flow-....json."*
394
+
395
+ For each test case, the agent repeats these steps. The skill's "Running as part of a Test Suite"
396
+ section is the authoritative version.
397
+
398
+ 1. Runs `resolve-next` to get the next test case, with its inputs resolved, or a `blocked`,
399
+ `waiting` or `complete` status.
400
+ 1. Replays the test case's test script, using the resolved value for each input instead of the
401
+ recorded one.
402
+ 1. Checks the `expectations`. It prefers OData queries and falls back to messages on the form.
403
+ 1. Captures the `outputs`.
404
+ 1. Runs `record-result` with the status, the outputs and the result of each check.
405
+ 1. Stops when `resolve-next` reports `complete`.
406
+
407
+ ### Step 8: Read the results
408
+
409
+ Open the test run file, for example:
410
+
411
+ ```sh
412
+ cat testruns/packing-slip-flow-....json
413
+ ```
414
+
415
+ For each test case, `results[testCaseId].status` is one of these values:
416
+
417
+ | Status | Meaning |
418
+ |---|---|
419
+ | `passed` | Every expectation held. |
420
+ | `failed` | At least one expectation didn't hold, or a step couldn't be performed. |
421
+ | `blocked` | An upstream test case failed or was skipped, so this one didn't run. |
422
+ | `skipped` | The test case's own `runIf` condition was false. See [Step 5](#step-5-create-the-suite). |
423
+
424
+ `outputs` shows the captured values. `assertionResults` shows the value that the agent observed for
425
+ each expectation, so you have a record of expected and actual values that doesn't depend on a chat
426
+ transcript.
427
+
428
+ To review results visually, open **Test Runs** in [TRXA Studio](STUDIO.md#review-test-runs).
429
+
430
+ ### Token and cost reporting
431
+
432
+ Each result can include `tokensUsed`, a token count, and `costUsd`, a cost in US dollars. The CLI
433
+ never talks to an AI model, so it doesn't calculate either value itself.
434
+
435
+ - **`tokensUsed`** is measured automatically. Unless you pass `--tokens`, `record-result` runs
436
+ `measure-tokens` for the time between the test case's start and the `record-result` call. It
437
+ reads the usage data that Claude Code writes to its session log in
438
+ `~/.claude/projects/.../<session>.jsonl`.
439
+
440
+ Treat this value as a rough estimate. In a test with two suites running in parallel, the reported
441
+ totals were 24% to 98% higher than each session's own usage totals. The measurement reads the
442
+ most recently changed session log, so when more than one Claude Code session works in the same
443
+ project folder at the same time, it can count another session's usage. That situation is common,
444
+ for example with suites running in parallel, or a desktop session left open during a background
445
+ run. For an exact number, run Claude Code with `claude -p --output-format json`, which reports
446
+ `total_cost_usd` and `usage` for that run only.
447
+
448
+ If no session log is found, `tokensUsed` is left empty. The value is available only with Claude
449
+ Code. Other agents, and Claude Cowork, which runs in the cloud, leave it empty. Pass or fail and
450
+ captured outputs never depend on it.
451
+
452
+ - **`costUsd`** is left empty when an agent runs tests interactively, because a reliable cost needs
453
+ a current pricing table that this CLI doesn't maintain. The field is for a future mode, such as
454
+ `claude -p --output-format json`, that reports its own cost.
455
+
456
+ When at least one result has these values, TRXA Studio shows them for each test case and as totals
457
+ for the run.
458
+
459
+ ## Group suites into a test plan
460
+
461
+ When you have several suites for one business area, such as customer onboarding, order to cash and
462
+ collections for Accounts receivable, a test plan groups them so that you can run and report on them
463
+ together. A plan doesn't add dependencies between suites. If two suites need to share data, put
464
+ their test cases in one suite.
465
+
466
+ 1. Create `plans/<your-id>.json`:
467
+
468
+ ```json
469
+ {
470
+ "id": "accounts-receivable",
471
+ "name": "Accounts Receivable regression pack",
472
+ "description": "...",
473
+ "suites": [
474
+ { "suiteId": "packing-slip-flow", "suitePath": "../suites/packing-slip-flow.json" }
475
+ ]
476
+ }
477
+ ```
478
+
479
+ `suitePath` is relative to the plan file, the same as a test case's `testScriptPath`. The order
480
+ of `suites` is the suggested run order. Plans have no `dependsOn`.
481
+
482
+ 1. Check the plan. The command also checks every suite that the plan refers to, so it catches a
483
+ wrong path or a broken suite right away.
484
+
485
+ ```sh
486
+ trxa validate-plan plans/accounts-receivable.json
487
+ ```
488
+
489
+ ### Run a plan
490
+
491
+ A plan run starts with one `init-plan-run` call. Its result has an `id` that ties every suite's
492
+ test run together. Then run each suite as in
493
+ [Step 7](#step-7-ask-your-agent-to-run-the-suite), using that same ID:
494
+
495
+ ```sh
496
+ trxa init-plan-run plans/accounts-receivable.json -o runs/
497
+ # prints the new plan run, for example { "id": "2026-08-25T14-30-00.000Z", "planId": "accounts-receivable", ... }
498
+ runId=2026-08-25T14-30-00.000Z
499
+ trxa init-run suites/packing-slip-flow.json -o testruns/packing-slip-flow-$runId.json
500
+ # ... run that suite to completion with the skill, as in step 7 ...
501
+ # ... repeat init-run and the skill for each other suite in the plan, with the same $runId ...
502
+ trxa plan-status plans/accounts-receivable.json runs/$runId.json --testruns-dir testruns
503
+ ```
504
+
505
+ `plan-status` reads `testruns/<suiteId>-<runId>.json` for every suite in the plan and reports a
506
+ per-suite breakdown and an `overall` status:
507
+
508
+ | `overall` | Meaning |
509
+ |---|---|
510
+ | `all-passed` | Every suite passed. |
511
+ | `has-failures` | At least one suite has a failed or blocked test case. |
512
+ | `incomplete` | At least one suite is still running. |
513
+ | `missing-runs` | At least one suite hasn't run yet in this plan run. |
514
+
515
+ `plan-status` only reads files, so you can run it as often as you like while suites are still
516
+ running.
517
+
518
+ ## Troubleshoot
519
+
520
+ | Symptom | Cause | Solution |
521
+ |---|---|---|
522
+ | `validate-suite` reports `has a dependency cycle involving: ...` | Two entries depend on each other, directly or through other entries. | Fix `dependsOn` in the listed entries. |
523
+ | `validate-suite` reports `depends on unknown testCaseId "..."` | A `dependsOn` value is misspelled, or the entry it names isn't in `entries`. | Add the entry, or fix the ID. |
524
+ | `validate-suite` reports `runIf references "..." which must be one of its own dependsOn` | A `runIf.testCaseId` isn't in that entry's `dependsOn`. | Add it to `dependsOn`, or point `runIf` at a direct dependency. |
525
+ | `resolve-next` reports `no inputBindings entry for required param "..."` | A required test case input has no binding in the suite. | Add a binding for that input in the suite file. |
526
+ | `resolve-next` reports `has not passed yet` | A `testCaseOutput` binding points at a test case that hasn't run, or that failed. | Make sure `dependsOn` includes that test case, and that it passed. |
527
+ | `resolve-next` reports `blocked` | An upstream test case failed or was skipped. | Fix the upstream failure, or accept that the dependent test case is blocked for this run. |
528
+ | `resolve-next` reports `skipped` | An entry's `runIf` condition was false. | Nothing. The condition worked as intended. |
529
+ | `resolve-next` reports `waiting` | A test case is still `running`, with no `record-result` call. | Finish that test case's `record-result` call. |
530
+ | A step's hint has `confidence: "low"` | The recording captured a row position, not a business key. | This is expected. Add a test case input with `bindTo.kind: "grid-row-selector"` for the step. |
531
+ | `validate-plan` reports `entry declares suiteId "..." but ... has id "..."` | A plan entry's `suiteId` doesn't match the `id` in the suite file it points at. | Fix whichever value is wrong. They must match. |
532
+ | `plan-status` reports a suite as `missing` | No `testruns/<suiteId>-<runId>.json` exists for the plan run's ID. | Run `init-run` for that suite with the plan run's ID, and then run it. |
533
+ | `plan-status` reports `Plan run at ... belongs to plan "..."` | The plan run file was created for a different plan. | Pass the plan run file that was created for this plan. |
534
+ | `record-result` fails with a JSON syntax error in PowerShell | PowerShell changed the inline JSON. | Use the file options. See [Pass JSON through files in Windows PowerShell](#pass-json-through-files-in-windows-powershell). |
535
+
536
+ ## Best practices
537
+
538
+ - **Never let the agent guess business data.** If a value should change from run to run, put it in
539
+ a fixture.
540
+ - **Prefer OData outputs and expectations** whenever the result is a record you can query. They're
541
+ much more reliable than reading text on a form.
542
+ - **Validate before every run.** `validate-testcase`, `validate-fixture`, `validate-suite` and
543
+ `validate-plan` are free, and they catch mistakes before a live session spends time and tokens on
544
+ them.
545
+ - **Review `example` values and literal test data before you commit them.** See
546
+ [Data hygiene](#data-hygiene).
547
+ - **Keep one test case per business scenario**, and reuse it across suites and fixtures, instead of
548
+ building one large test case that does everything.
549
+ - **Use a test plan** once you have several suites for one business area. It costs nothing extra
550
+ per suite, and it gives you one combined result.
551
+
552
+ ## Related content
553
+
554
+ - [Set up TRXA Studio for agent runs](SETUP.md)
555
+ - [Use TRXA Studio](STUDIO.md)
556
+ - [Use Model Context Protocol for finance and operations apps](https://learn.microsoft.com/dynamics365/fin-ops-core/dev-itpro/copilot/copilot-mcp)
package/README.md CHANGED
@@ -1,3 +1,91 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # TRXA-TOOL
2
+
3
+ TRXA-TOOL turns Dynamics 365 Finance and Supply Chain Management Task Recorder recordings (`.axtr`
4
+ files) into automated, data-driven regression tests that an AI agent replays against a test or
5
+ sandbox environment.
6
+
7
+ ## How it works
8
+
9
+ 1. **You record** a business process in Dynamics 365 with Task recorder, or export recordings from
10
+ a Business Process Modeler library in Lifecycle Services.
11
+ 1. **TRXA-TOOL prepares the test.** It translates each recording into steps that an agent can
12
+ perform. In TRXA Studio, you then decide which values are test data, what the test checks, and
13
+ how tests run in sequence.
14
+ 1. **An AI agent runs the test.** GitHub Copilot CLI, Claude Code, or another agent that can use
15
+ MCP tools works in Dynamics 365 through Microsoft's
16
+ [Dynamics 365 ERP MCP server](https://learn.microsoft.com/dynamics365/fin-ops-core/dev-itpro/copilot/copilot-mcp).
17
+ It performs each step, checks the results, and records whether each test passed or failed.
18
+ 1. **You review the results** in TRXA Studio, and share them as text, Markdown or PDF.
19
+
20
+ TRXA-TOOL does everything that has a fixed answer, such as reading recordings, working out the run
21
+ order and passing data between tests. The agent does only the work that needs a live Dynamics 365
22
+ session.
23
+
24
+ ![TRXA Studio, showing the steps of a recording.](media/studio/studio-recordings.png)
25
+
26
+ ## Get started
27
+
28
+ TRXA-TOOL comes in two forms. Both include TRXA Studio, and both can run tests with an AI agent.
29
+
30
+ | | Windows app | npm package |
31
+ |---|---|---|
32
+ | **Best for** | Consultants and testers who work in Studio | Developers and technical users who also want the command line |
33
+ | **Studio opens** | In its own window | In your browser |
34
+ | **`trxa` command in a terminal** | Through its full path | Yes |
35
+ | **Needs Node.js** | No | Yes, version 18.19 or later |
36
+ | **Platforms** | Windows | Windows, macOS, Linux |
37
+
38
+ - **Windows app**: download `TRXA-Studio-<version>-win-x64-portable.zip` (no installation) or
39
+ `TRXA-Studio-Setup-<version>.exe` from the [Releases](https://github.com/elcanelo/trxa-tool/releases)
40
+ page.
41
+ - **npm package**: run `npm install -g trxa-tool`, and then `trxa studio`.
42
+
43
+ For step-by-step instructions, including the agent and the Dynamics 365 connection, see
44
+ [Set up TRXA Studio for agent runs](SETUP.md).
45
+
46
+ > [!NOTE]
47
+ > The Windows app isn't code-signed yet. Windows SmartScreen might show **Windows protected your
48
+ > PC**, and a company-managed computer might block the app. [Step 1](SETUP.md#step-1-install-trxa-tool)
49
+ > of the setup article explains what to do.
50
+
51
+ ## Documentation
52
+
53
+ | Article | Read it to |
54
+ |---|---|
55
+ | [Set up TRXA Studio for agent runs](SETUP.md) | Install TRXA-TOOL and an agent, and connect the agent to Dynamics 365. |
56
+ | [Use TRXA Studio](STUDIO.md) | Create test cases, fixtures, suites and plans, run them, and review the results. |
57
+ | [TRXA-TOOL manual](MANUAL.md) | Use the `trxa` command line, and look up the file formats. |
58
+
59
+ The npm package includes these articles. To find them, run `npm root -g` and open the `trxa-tool`
60
+ folder.
61
+
62
+ ## Protect business data
63
+
64
+ A recording captures whatever was on the screen when it was made, including real account numbers,
65
+ amounts and names. Test scripts and suggested test inputs carry that data forward. Review anything
66
+ created from a real recording before you share it or commit it to source control. For guidance,
67
+ see [Data hygiene](MANUAL.md#data-hygiene) in the manual.
68
+
69
+ ## Report a problem
70
+
71
+ To report a bug, or a recording that TRXA-TOOL can't handle, open an issue at
72
+ [github.com/elcanelo/trxa-tool/issues](https://github.com/elcanelo/trxa-tool/issues). Don't attach
73
+ recordings or test files that contain real business data.
74
+
75
+ ## Source code
76
+
77
+ TRXA-TOOL is closed source for now. The product is still evolving, and keeping the source
78
+ private while new features are planned lets the design change without breaking promises to
79
+ contributors. This repository holds the documentation and the issue tracker.
80
+
81
+ Feedback is welcome. To report a problem or suggest a feature, open an
82
+ [issue](https://github.com/elcanelo/trxa-tool/issues).
83
+
84
+ To hear about new versions, go to the [trxa-tool repository](https://github.com/elcanelo/trxa-tool),
85
+ select **Watch** > **Custom**, select **Releases**, and then select **Apply**. GitHub emails you
86
+ each time a new version is published.
87
+
88
+ ## License
89
+
90
+ TRXA-TOOL is proprietary software. Its use is governed by the end-user license agreement in
91
+ [LICENSE](LICENSE).