@automatify-au/cli 0.1.5 → 0.1.6

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.
package/README.md CHANGED
@@ -76,6 +76,16 @@ Minimum:
76
76
  - `TESTOPS_FORGE_ENDPOINT` for commands that call Forge contracts (`doctor`, `ingest`, `run`, `sync`)
77
77
  - `TESTOPS_FORGE_AUTH_TOKEN` from the one-time token shown in Forge `Operations -> CLI access`
78
78
 
79
+ Local config helper:
80
+ ```bash
81
+ automatify testops config set baseUrl https://automatify-com-au.atlassian.net
82
+ automatify testops config set projectKey DEV
83
+ automatify testops config set forgeEndpoint "<webtrigger-url>"
84
+ printf "%s" "$TESTOPS_FORGE_AUTH_TOKEN" | automatify testops config set forgeAuthToken --stdin
85
+ ```
86
+
87
+ `forgeAuthToken` local storage currently uses macOS Keychain. On Windows, Linux, and CI, keep the token in `TESTOPS_FORGE_AUTH_TOKEN` instead. `.testops-cli.json` should store non-secret values only.
88
+
79
89
  Optional:
80
90
  - `TESTOPS_FORGE_TIMEOUT_MS`
81
91
  - `TESTOPS_FORGE_MAX_RETRIES`
@@ -91,6 +101,7 @@ All TestOps commands are invoked as `automatify testops <command>`:
91
101
  - `bdd`
92
102
  - `automatify testops bdd scenarios show --id <SCENARIO_ID>`
93
103
  - `automatify testops bdd scenarios show --id <SCENARIO_ID> --format feature`
104
+ - `automatify testops bdd scenarios show --id <SCENARIO_ID|SC-4> --feature`
94
105
  - `automatify testops bdd scenarios export --id <SCENARIO_ID|SC-4> --output-dir ./scenario-export`
95
106
  - `automatify testops bdd scenarios export --all --output-dir ./scenario-export`
96
107
  - `automatify testops bdd scenarios import --file ./scenario-export/SC-4.feature`
@@ -171,6 +182,19 @@ export JIRA_BASE_URL="https://automatify-com-au.atlassian.net"
171
182
  export JIRA_PROJECT_KEY="DEV"
172
183
  ```
173
184
 
185
+ Or store the non-secret values in `.testops-cli.json` and, on macOS, the token in Keychain:
186
+ ```bash
187
+ automatify testops config set baseUrl https://automatify-com-au.atlassian.net
188
+ automatify testops config set projectKey DEV
189
+ automatify testops config set forgeEndpoint "<webtrigger-url>"
190
+ printf "%s" "$TESTOPS_FORGE_AUTH_TOKEN" | automatify testops config set forgeAuthToken --stdin
191
+ ```
192
+
193
+ Windows, Linux, and CI should keep the token in environment variables:
194
+ ```bash
195
+ export TESTOPS_FORGE_AUTH_TOKEN="<one-time-token-from-forge-ui>"
196
+ ```
197
+
174
198
  Transport notes:
175
199
  - Bearer auth is required for operator/CI use. Forge stores only the token hash plus metadata.
176
200
  - Tokens are project-scoped, shown once at creation time, and can be revoked from the Forge UI.
@@ -317,7 +341,7 @@ automatify testops ingest feature --project-key DEV --file ./artifacts/features-
317
341
  ```
318
342
 
319
343
  Feature export notes:
320
- - `bdd scenarios show --format feature` renders one scenario in feature-style text.
344
+ - `bdd scenarios show --format feature` and `bdd scenarios show --feature` render one scenario in feature-style text.
321
345
  - `bdd scenarios export` writes a single-scenario `SC-*.feature` file with a reserved `@testops-scenario-SC-*` tag.
322
346
  - Jira issue links are exported as normal Gherkin tags like `@DEV-2`; on import they are written back to `linkedIssueKeys`.
323
347
  - current model has `linked issues`, not a separate persisted `primary issue`, so all exported issue-key tags are treated as equal links.
@@ -1030,8 +1030,10 @@ var Priority;
1030
1030
 
1031
1031
  // src/config.ts
1032
1032
  var import_node_fs = require("node:fs");
1033
+ var import_node_child_process = require("node:child_process");
1033
1034
  var import_node_path = __toESM(require("node:path"), 1);
1034
1035
  var DEFAULT_CONFIG_FILENAME = ".testops-cli.json";
1036
+ var KEYCHAIN_SERVICE = "automatify-testops-cli";
1035
1037
  function parseFlags(args) {
1036
1038
  const flags = {};
1037
1039
  const unknownFlags = [];
@@ -1077,6 +1079,11 @@ function readConfigFile(configPath) {
1077
1079
  return {};
1078
1080
  }
1079
1081
  }
1082
+ function writeConfigFile(configPath, file) {
1083
+ (0, import_node_fs.writeFileSync)(configPath, `${JSON.stringify(file, null, 2)}
1084
+ `, "utf8");
1085
+ (0, import_node_fs.chmodSync)(configPath, 384);
1086
+ }
1080
1087
  function normalizeBaseUrl(value) {
1081
1088
  if (value.endsWith("/")) {
1082
1089
  return value.slice(0, -1);
@@ -1086,6 +1093,30 @@ function normalizeBaseUrl(value) {
1086
1093
  function readAuthMode(input) {
1087
1094
  return input === "api-token" ? "api-token" : "none";
1088
1095
  }
1096
+ function defaultKeychainAccount(configPath) {
1097
+ return import_node_path.default.resolve(configPath);
1098
+ }
1099
+ function readKeychainSecret(account) {
1100
+ if (!account || process.platform !== "darwin") {
1101
+ return "";
1102
+ }
1103
+ try {
1104
+ return (0, import_node_child_process.execFileSync)("security", ["find-generic-password", "-s", KEYCHAIN_SERVICE, "-a", account, "-w"], {
1105
+ encoding: "utf8",
1106
+ stdio: ["ignore", "pipe", "ignore"]
1107
+ }).trim();
1108
+ } catch {
1109
+ return "";
1110
+ }
1111
+ }
1112
+ function setKeychainSecret(account, value) {
1113
+ if (process.platform !== "darwin") {
1114
+ throw new Error("Keychain-backed secrets are only supported on macOS.");
1115
+ }
1116
+ (0, import_node_child_process.execFileSync)("security", ["add-generic-password", "-U", "-s", KEYCHAIN_SERVICE, "-a", account, "-w", value], {
1117
+ stdio: ["ignore", "ignore", "pipe"]
1118
+ });
1119
+ }
1089
1120
  function valueFromPrecedence(key, flagValue, envValue, fileValue, fallback = "") {
1090
1121
  if (flagValue) {
1091
1122
  return { value: flagValue, source: "flag" };
@@ -1145,6 +1176,22 @@ function resolveCliConfig(args, env = process.env, cwd = process.cwd()) {
1145
1176
  toStringValue(env.JIRA_API_TOKEN),
1146
1177
  toStringValue(file.jiraApiToken ?? file.JIRA_API_TOKEN)
1147
1178
  );
1179
+ const forgeEndpointResolved = valueFromPrecedence(
1180
+ "forgeEndpoint",
1181
+ "",
1182
+ toStringValue(env.TESTOPS_FORGE_ENDPOINT),
1183
+ toStringValue(file.forgeEndpoint ?? file.TESTOPS_FORGE_ENDPOINT)
1184
+ );
1185
+ const forgeAuthTokenKeychainAccountResolved = valueFromPrecedence(
1186
+ "forgeAuthTokenKeychainAccount",
1187
+ "",
1188
+ "",
1189
+ toStringValue(file.forgeAuthTokenKeychainAccount)
1190
+ );
1191
+ const forgeAuthTokenFromEnv = toStringValue(env.TESTOPS_FORGE_AUTH_TOKEN);
1192
+ const forgeAuthTokenFromFile = toStringValue(file.forgeAuthToken ?? file.TESTOPS_FORGE_AUTH_TOKEN);
1193
+ const forgeAuthTokenFromKeychain = forgeAuthTokenFromEnv || forgeAuthTokenFromFile || !forgeAuthTokenKeychainAccountResolved.value ? "" : readKeychainSecret(forgeAuthTokenKeychainAccountResolved.value);
1194
+ const forgeAuthTokenResolved = forgeAuthTokenFromEnv ? { value: forgeAuthTokenFromEnv, source: "env" } : forgeAuthTokenFromFile ? { value: forgeAuthTokenFromFile, source: "file" } : forgeAuthTokenFromKeychain ? { value: forgeAuthTokenFromKeychain, source: "keychain" } : { value: "", source: "default" };
1148
1195
  const config = {
1149
1196
  baseUrl: normalizeBaseUrl(baseUrlResolved.value),
1150
1197
  projectKey: projectKeyResolved.value,
@@ -1152,6 +1199,9 @@ function resolveCliConfig(args, env = process.env, cwd = process.cwd()) {
1152
1199
  authMode: readAuthMode(authModeResolved.value),
1153
1200
  jiraEmail: jiraEmailResolved.value,
1154
1201
  jiraApiToken: jiraApiTokenResolved.value,
1202
+ forgeEndpoint: normalizeBaseUrl(forgeEndpointResolved.value),
1203
+ forgeAuthToken: forgeAuthTokenResolved.value,
1204
+ forgeAuthTokenKeychainAccount: forgeAuthTokenKeychainAccountResolved.value,
1155
1205
  configPath
1156
1206
  };
1157
1207
  const sources = {
@@ -1161,6 +1211,9 @@ function resolveCliConfig(args, env = process.env, cwd = process.cwd()) {
1161
1211
  authMode: authModeResolved.source,
1162
1212
  jiraEmail: jiraEmailResolved.source,
1163
1213
  jiraApiToken: jiraApiTokenResolved.source,
1214
+ forgeEndpoint: forgeEndpointResolved.source,
1215
+ forgeAuthToken: forgeAuthTokenResolved.source,
1216
+ forgeAuthTokenKeychainAccount: forgeAuthTokenKeychainAccountResolved.source,
1164
1217
  configPath: configPathSource
1165
1218
  };
1166
1219
  const warnings = [];
@@ -1218,9 +1271,78 @@ function toDisplayLines(resolution) {
1218
1271
  ` authMode: ${values.authMode} (${sources.authMode})`,
1219
1272
  ` jiraEmail: ${values.jiraEmail || "<unset>"} (${sources.jiraEmail})`,
1220
1273
  ` jiraApiToken: ${values.jiraApiToken ? maskSecret(values.jiraApiToken) : "<unset>"} (${sources.jiraApiToken})`,
1274
+ ` forgeEndpoint: ${values.forgeEndpoint || "<unset>"} (${sources.forgeEndpoint})`,
1275
+ ` forgeAuthToken: ${values.forgeAuthToken ? maskSecret(values.forgeAuthToken) : "<unset>"} (${sources.forgeAuthToken})`,
1276
+ ` forgeAuthTokenKeychainAccount: ${values.forgeAuthTokenKeychainAccount || "<unset>"} (${sources.forgeAuthTokenKeychainAccount})`,
1221
1277
  ` configPath: ${values.configPath} (${sources.configPath})`
1222
1278
  ];
1223
1279
  }
1280
+ function normalizeConfigSetKey(input) {
1281
+ switch (input) {
1282
+ case "baseUrl":
1283
+ case "JIRA_BASE_URL":
1284
+ return "baseUrl";
1285
+ case "projectKey":
1286
+ case "JIRA_PROJECT_KEY":
1287
+ return "projectKey";
1288
+ case "issueKey":
1289
+ case "JIRA_ISSUE_KEY":
1290
+ return "issueKey";
1291
+ case "authMode":
1292
+ case "TESTOPS_AUTH_MODE":
1293
+ return "authMode";
1294
+ case "jiraEmail":
1295
+ case "JIRA_EMAIL":
1296
+ return "jiraEmail";
1297
+ case "jiraApiToken":
1298
+ case "JIRA_API_TOKEN":
1299
+ return "jiraApiToken";
1300
+ case "forgeEndpoint":
1301
+ case "TESTOPS_FORGE_ENDPOINT":
1302
+ return "forgeEndpoint";
1303
+ case "forgeAuthToken":
1304
+ case "TESTOPS_FORGE_AUTH_TOKEN":
1305
+ return "forgeAuthToken";
1306
+ default:
1307
+ return "";
1308
+ }
1309
+ }
1310
+ function applyConfigSet(configPath, rawKey, value) {
1311
+ const key = normalizeConfigSetKey(rawKey);
1312
+ if (!key) {
1313
+ return {
1314
+ exitCode: ExitCode.UsageError,
1315
+ stderr: [
1316
+ "Unsupported config key. Use one of: baseUrl, projectKey, issueKey, authMode, jiraEmail, jiraApiToken, forgeEndpoint, forgeAuthToken."
1317
+ ]
1318
+ };
1319
+ }
1320
+ const file = readConfigFile(configPath);
1321
+ if (key === "forgeAuthToken") {
1322
+ const account = toStringValue(file.forgeAuthTokenKeychainAccount) || defaultKeychainAccount(configPath);
1323
+ setKeychainSecret(account, value);
1324
+ const nextFile2 = {
1325
+ ...file,
1326
+ forgeAuthToken: void 0,
1327
+ TESTOPS_FORGE_AUTH_TOKEN: void 0,
1328
+ forgeAuthTokenKeychainAccount: account
1329
+ };
1330
+ writeConfigFile(configPath, nextFile2);
1331
+ return {
1332
+ exitCode: ExitCode.Success,
1333
+ stdout: [`Config updated: forgeAuthToken stored in macOS Keychain (${account}).`]
1334
+ };
1335
+ }
1336
+ const nextFile = {
1337
+ ...file,
1338
+ [key]: key === "baseUrl" || key === "forgeEndpoint" ? normalizeBaseUrl(value) : value
1339
+ };
1340
+ writeConfigFile(configPath, nextFile);
1341
+ return {
1342
+ exitCode: ExitCode.Success,
1343
+ stdout: [`Config updated: ${rawKey}.`]
1344
+ };
1345
+ }
1224
1346
  function createConfigHandler(env = process.env, cwd = process.cwd()) {
1225
1347
  return (request) => {
1226
1348
  const [subcommand, ...subArgs] = request.args;
@@ -1245,6 +1367,18 @@ function createConfigHandler(env = process.env, cwd = process.cwd()) {
1245
1367
  stderr: validation.errors.map((line) => `ERROR: ${line}`)
1246
1368
  };
1247
1369
  }
1370
+ if (subcommand === "set") {
1371
+ const [key, ...valueParts] = subArgs;
1372
+ const readValueFromStdin = key === "forgeAuthToken" && valueParts.length === 1 && valueParts[0] === "--stdin";
1373
+ const value = readValueFromStdin ? (0, import_node_fs.readFileSync)(0, "utf8").trim() : valueParts.join(" ").trim();
1374
+ if (!key || !value) {
1375
+ return {
1376
+ exitCode: ExitCode.UsageError,
1377
+ stderr: ["Usage: automatify testops config set <key> <value>"]
1378
+ };
1379
+ }
1380
+ return applyConfigSet(resolution.values.configPath, key, value);
1381
+ }
1248
1382
  return {
1249
1383
  exitCode: ExitCode.UsageError,
1250
1384
  stderr: [`Unsupported config subcommand: ${subcommand}`]
@@ -2761,7 +2895,7 @@ function parseArgs2(args) {
2761
2895
  "--file",
2762
2896
  ...CONFIG_FLAGS2
2763
2897
  ]);
2764
- const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all", "--dry-run"]);
2898
+ const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all", "--dry-run", "--feature"]);
2765
2899
  for (let index = 0; index < args.length; index += 1) {
2766
2900
  const token = args[index];
2767
2901
  if (!token.startsWith("--")) {
@@ -2923,6 +3057,39 @@ function scenarioToLines(scenario) {
2923
3057
  }
2924
3058
  return lines;
2925
3059
  }
3060
+ async function resolveScenarioId(context, projectKey, issueKey, scenarioSelector) {
3061
+ const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
3062
+ context: {
3063
+ projectKey,
3064
+ issueKey: issueKey || void 0
3065
+ }
3066
+ });
3067
+ if (!scenariosResult.ok) {
3068
+ return {
3069
+ ok: false,
3070
+ response: {
3071
+ exitCode: ExitCode.RemoteError,
3072
+ stderr: [`ERROR: ${scenariosResult.error.code}: ${scenariosResult.error.message}`]
3073
+ }
3074
+ };
3075
+ }
3076
+ const matchedScenario = scenariosResult.data.find(
3077
+ (item) => item.id === scenarioSelector || (item.key ?? "").toUpperCase() === scenarioSelector.toUpperCase()
3078
+ );
3079
+ if (!matchedScenario) {
3080
+ return {
3081
+ ok: false,
3082
+ response: {
3083
+ exitCode: ExitCode.RemoteError,
3084
+ stderr: [`ERROR: NOT_FOUND: BDD scenario ${scenarioSelector} was not found in this project.`]
3085
+ }
3086
+ };
3087
+ }
3088
+ return {
3089
+ ok: true,
3090
+ scenarioId: matchedScenario.id
3091
+ };
3092
+ }
2926
3093
  function featureToLines(feature) {
2927
3094
  return [
2928
3095
  `BDD feature: ${feature.payload.name}`,
@@ -3010,7 +3177,7 @@ function createBddHandler(deps = {}) {
3010
3177
  const [subcommand, ...restArgs] = request.args;
3011
3178
  const parsed = parseArgs2(restArgs);
3012
3179
  const requestedFormat = (parsed.flags["--format"] ?? "").trim().toLowerCase();
3013
- const outputFormat = parsed.boolFlags.has("--json") ? "json" : requestedFormat || "text";
3180
+ const outputFormat = parsed.boolFlags.has("--json") ? "json" : parsed.boolFlags.has("--feature") ? "feature" : requestedFormat || "text";
3014
3181
  const config = resolveCliConfig(pickConfigArgs2(parsed), env, cwd);
3015
3182
  const projectKey = config.values.projectKey;
3016
3183
  const issueKey = config.values.issueKey;
@@ -3152,10 +3319,10 @@ function createBddHandler(deps = {}) {
3152
3319
  };
3153
3320
  }
3154
3321
  if (nested === "export") {
3155
- const scenarioSelector = parsed.flags["--id"]?.trim() ?? "";
3322
+ const scenarioSelector2 = parsed.flags["--id"]?.trim() ?? "";
3156
3323
  const exportAll = parsed.boolFlags.has("--all");
3157
3324
  const outputDirFlag = parsed.flags["--output-dir"]?.trim() ?? "";
3158
- if (!scenarioSelector && !exportAll) {
3325
+ if (!scenarioSelector2 && !exportAll) {
3159
3326
  return {
3160
3327
  exitCode: ExitCode.ValidationError,
3161
3328
  stderr: ["ERROR: Provide --id <SCENARIO_ID|SC-4> or --all for testops bdd scenarios export."]
@@ -3183,12 +3350,12 @@ function createBddHandler(deps = {}) {
3183
3350
  };
3184
3351
  }
3185
3352
  const selectedScenarios = exportAll ? [...scenariosResult.data].sort((left, right) => (left.key ?? left.id).localeCompare(right.key ?? right.id)) : scenariosResult.data.filter(
3186
- (item) => item.id === scenarioSelector || (item.key ?? "").toUpperCase() === scenarioSelector.toUpperCase()
3353
+ (item) => item.id === scenarioSelector2 || (item.key ?? "").toUpperCase() === scenarioSelector2.toUpperCase()
3187
3354
  );
3188
3355
  if (!exportAll && selectedScenarios.length === 0) {
3189
3356
  return {
3190
3357
  exitCode: ExitCode.RemoteError,
3191
- stderr: [`ERROR: NOT_FOUND: BDD scenario ${scenarioSelector} was not found in this project.`]
3358
+ stderr: [`ERROR: NOT_FOUND: BDD scenario ${scenarioSelector2} was not found in this project.`]
3192
3359
  };
3193
3360
  }
3194
3361
  if (selectedScenarios.length === 0) {
@@ -3429,9 +3596,9 @@ function createBddHandler(deps = {}) {
3429
3596
  };
3430
3597
  }
3431
3598
  }
3432
- const scenarioId2 = parsed.flags["--id"]?.trim() ?? "";
3599
+ const scenarioId = parsed.flags["--id"]?.trim() ?? "";
3433
3600
  const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
3434
- if (!scenarioId2 && !testCaseKey) {
3601
+ if (!scenarioId && !testCaseKey) {
3435
3602
  return {
3436
3603
  exitCode: ExitCode.ValidationError,
3437
3604
  stderr: ["ERROR: Provide either --id <SCENARIO_ID> or --test-case-key <TC-197> for testops bdd scenarios run."]
@@ -3439,8 +3606,8 @@ function createBddHandler(deps = {}) {
3439
3606
  }
3440
3607
  try {
3441
3608
  let scenarioIds = [];
3442
- let scenarioLabel = scenarioId2 || testCaseKey;
3443
- if (testCaseKey && !scenarioId2) {
3609
+ let scenarioLabel = scenarioId || testCaseKey;
3610
+ if (testCaseKey && !scenarioId) {
3444
3611
  const testCaseResult = await context.invokeForgeContract("getTestCase", {
3445
3612
  context: {
3446
3613
  projectKey,
@@ -3475,8 +3642,8 @@ function createBddHandler(deps = {}) {
3475
3642
  };
3476
3643
  }
3477
3644
  scenarioLabel = `${testCase.key} (${scenarioIds.length} scenario${scenarioIds.length === 1 ? "" : "s"})`;
3478
- } else if (scenarioId2) {
3479
- scenarioIds = [scenarioId2];
3645
+ } else if (scenarioId) {
3646
+ scenarioIds = [scenarioId];
3480
3647
  }
3481
3648
  const runs = [];
3482
3649
  for (const currentScenarioId of scenarioIds) {
@@ -3532,20 +3699,24 @@ function createBddHandler(deps = {}) {
3532
3699
  };
3533
3700
  }
3534
3701
  }
3535
- const scenarioId = parsed.flags["--id"]?.trim() ?? "";
3536
- if (!scenarioId) {
3702
+ const scenarioSelector = parsed.flags["--id"]?.trim() ?? "";
3703
+ if (!scenarioSelector) {
3537
3704
  return {
3538
3705
  exitCode: ExitCode.ValidationError,
3539
3706
  stderr: ["ERROR: Missing required --id for testops bdd scenarios show."]
3540
3707
  };
3541
3708
  }
3542
3709
  try {
3710
+ const resolvedScenario = await resolveScenarioId(context, projectKey, issueKey, scenarioSelector);
3711
+ if (!resolvedScenario.ok) {
3712
+ return resolvedScenario.response;
3713
+ }
3543
3714
  const result = await context.invokeForgeContract("getBddScenario", {
3544
3715
  context: {
3545
3716
  projectKey,
3546
3717
  issueKey: issueKey || void 0
3547
3718
  },
3548
- scenarioId
3719
+ scenarioId: resolvedScenario.scenarioId
3549
3720
  });
3550
3721
  if (!result.ok) {
3551
3722
  return {
@@ -5454,7 +5625,7 @@ var COMMAND_REGISTRY = [
5454
5625
  {
5455
5626
  name: "config",
5456
5627
  description: "Configuration and auth bootstrap commands",
5457
- subcommands: ["show", "validate"],
5628
+ subcommands: ["show", "validate", "set"],
5458
5629
  handler: createConfigHandler()
5459
5630
  },
5460
5631
  {
@@ -5496,8 +5667,9 @@ var COMMAND_REGISTRY = [
5496
5667
  }
5497
5668
  ];
5498
5669
  function createThinClientContext() {
5499
- const endpoint = process.env.TESTOPS_FORGE_ENDPOINT?.trim() ?? "";
5500
- const authToken = process.env.TESTOPS_FORGE_AUTH_TOKEN?.trim() ?? "";
5670
+ const config = resolveCliConfig([], process.env, process.cwd()).values;
5671
+ const endpoint = process.env.TESTOPS_FORGE_ENDPOINT?.trim() || config.forgeEndpoint;
5672
+ const authToken = process.env.TESTOPS_FORGE_AUTH_TOKEN?.trim() || config.forgeAuthToken;
5501
5673
  if (!endpoint) {
5502
5674
  return {
5503
5675
  invokeForgeContract: async (_contractName, _payload) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automatify-au/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Forge-first CLI for Automatify Jira TestOps",
5
5
  "type": "module",
6
6
  "bin": {