@qatonic_innovations/qaios 0.5.2 → 0.5.3

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 (3) hide show
  1. package/README.md +11 -13
  2. package/dist/index.js +106 -51
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # QAIOS
2
2
 
3
- > **AI QA engineer in your terminal.** Designs, writes, runs, heals, and explores tests for web UI and APIs — with audit-grade traceability.
3
+ > **AI QA engineer in your terminal.** Designs, writes, runs, heals, and explores tests for web UI and APIs — with tamper-evident local history.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@qatonic_innovations/qaios.svg)](https://www.npmjs.com/package/@qatonic_innovations/qaios)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/qatonic/qaios/blob/main/LICENSE)
@@ -10,7 +10,7 @@ QAIOS acts like a QA engineer on your team. Point it at a feature description or
10
10
 
11
11
  **Mental model: Claude Code, but for QA work instead of feature coding.**
12
12
 
13
- > **Status: early alpha (v0.1).** Core flows — `init`, `doctor`, test design
13
+ > **Status: pre-1.0 (v0.5.2 released).** Core flows — `init`, `doctor`, test design
14
14
  > & generation, Playwright execution, self-healing, accessibility, and the
15
15
  > audit log — work today. Expect rough edges and please
16
16
  > [report issues](https://github.com/qatonic/qaios/issues). After installing,
@@ -95,7 +95,7 @@ Generated:
95
95
  tests/auth/LoginPage.po.ts
96
96
  .qaios/specs/01JTZ1…/DesignSpec.json
97
97
 
98
- Cost: 11,403 tokens · $0.06 (3 of 15 LLM calls used)
98
+ Cost: 11,403 tokens · $0.06 (3 of 20 LLM calls used)
99
99
  ```
100
100
 
101
101
  > **Gates:** on HIGH/CRITICAL-risk features QAIOS pauses for review. Approve interactively with `qaios review`, or pass `--yes` to auto-approve for a non-interactive run.
@@ -117,7 +117,7 @@ Cost: 11,403 tokens · $0.06 (3 of 15 LLM calls used)
117
117
  | `qaios review` | Walk pending human-review gates and approve/reject; resumes the workflow. |
118
118
  | `qaios history [--verify]` | List workflows, inspect the audit log, and verify the hash chain. |
119
119
  | `qaios config get\|set\|show\|edit` | Read/write `.qaios/config.yaml` (schema-validated). |
120
- | `qaios mcp list\|add\|remove\|enable\|disable\|test` | Manage MCP servers (GitHub, Jira, Slack, custom). |
120
+ | `qaios mcp list\|add\|remove\|enable\|disable\|test` | Manage stdio MCP servers (GitHub, Jira, custom). |
121
121
 
122
122
  Run `qaios <command> --help` for the full option list of any command.
123
123
 
@@ -250,7 +250,7 @@ qaios config set mode TRUST
250
250
 
251
251
  ## Cost & privacy
252
252
 
253
- - Skills run on Claude Sonnet (Anthropic) or gpt-4o (OpenAI) per your `llm.provider`. A typical `qaios test` costs ~**$0.04–0.10**. Each workflow is capped (default `min(15 calls, $0.50)`, configurable) and aborts if exceeded.
253
+ - Skills use Anthropic or OpenAI per `llm.provider`. Each workflow is capped at `min(20 calls, $1.00)` by default (configurable) and aborts if exceeded.
254
254
  - **Local-first.** No telemetry, no phone-home. The only outbound traffic is (a) LLM calls to your configured provider (Anthropic or OpenAI) with the prompts QAIOS builds, and (b) any MCP servers you configure. You bring your own API key; QAIOS does not proxy your requests. See [SECURITY.md](https://github.com/qatonic/qaios/blob/main/SECURITY.md) for exactly what's sent.
255
255
 
256
256
  ---
@@ -280,20 +280,18 @@ output for CI consumption.
280
280
  - [Commands Reference](https://github.com/qatonic/qaios/blob/main/docs/commands.md) — every CLI command
281
281
  - [Skills Reference](https://github.com/qatonic/qaios/blob/main/docs/skills-reference.md) — what each skill does
282
282
  - [MCP Servers](https://github.com/qatonic/qaios/blob/main/docs/mcp-servers.md) — adding integrations
283
+ - [JSON Output](https://github.com/qatonic/qaios/blob/main/docs/json-output.md) — automation compatibility
284
+ - [Compatibility Policy](https://github.com/qatonic/qaios/blob/main/docs/compatibility.md) — stability and deprecation
283
285
  - A runnable end-to-end example lives in [`examples/live-saucedemo`](https://github.com/qatonic/qaios/tree/main/examples/live-saucedemo).
284
286
 
285
287
  ---
286
288
 
287
289
  ## Status & roadmap
288
290
 
289
- **v0.1 (now):** Web UI + API + visual regression + self-healing + exploratory + accessibility, as an open-source CLI. Early — feedback wanted.
290
-
291
- - **v0.2** — optional cloud sync + web dashboard
292
- - **v0.5** — mobile testing
293
- - **v0.7** — performance + security testing
294
- - **v1.0** — database testing, stable public API
295
-
296
- The roadmap is gated on real-world validation, not a calendar.
291
+ **v0.5.2 is released.** v0.5.3 focuses on truth and consistency before the
292
+ trustworthy-alpha, agent-runtime, quality-intelligence, ecosystem, and stable-OS phases.
293
+ The [active roadmap](https://github.com/qatonic/qaios/blob/main/QAIOS_PRODUCT_AND_ENGINEERING_ROADMAP.md)
294
+ is validation-gated, not calendar-driven.
297
295
 
298
296
  ---
299
297
 
package/dist/index.js CHANGED
@@ -8404,7 +8404,7 @@ var McpClient = class {
8404
8404
  for (const s of opts.servers) {
8405
8405
  if (s.enabled !== false) this.registry.set(s.name, s);
8406
8406
  }
8407
- this.connectionFactory = opts.connectionFactory ?? defaultConnectionFactory;
8407
+ this.connectionFactory = opts.connectionFactory ?? createDefaultConnectionFactory(opts.clientVersion ?? "0.0.0");
8408
8408
  if (opts.auditLogger !== void 0) this.auditLogger = opts.auditLogger;
8409
8409
  if (opts.workflowId !== void 0) this.workflowId = opts.workflowId;
8410
8410
  if (opts.skillId !== void 0) this.skillId = opts.skillId;
@@ -8555,11 +8555,14 @@ var McpClient = class {
8555
8555
  });
8556
8556
  }
8557
8557
  };
8558
- var defaultConnectionFactory = async (config) => {
8558
+ function createDefaultConnectionFactory(clientVersion) {
8559
+ return async (config) => connectDefault(config, clientVersion);
8560
+ }
8561
+ async function connectDefault(config, clientVersion) {
8559
8562
  if (config.type !== "stdio") {
8560
8563
  throw new McpError(
8561
8564
  "qaios.mcp.transport_not_supported",
8562
- `MCP transport "${config.type}" is not supported in v0.1 \u2014 only stdio is wired.`,
8565
+ `MCP transport "${config.type}" is not supported by this release \u2014 only stdio is available.`,
8563
8566
  { serverName: config.name }
8564
8567
  );
8565
8568
  }
@@ -8584,7 +8587,7 @@ var defaultConnectionFactory = async (config) => {
8584
8587
  args: [...config.args],
8585
8588
  env: buildSubprocessEnv(resolved)
8586
8589
  });
8587
- const client = new Client({ name: "qaios", version: "0.1.0" }, { capabilities: {} });
8590
+ const client = new Client({ name: "qaios", version: clientVersion }, { capabilities: {} });
8588
8591
  await client.connect(transport);
8589
8592
  return {
8590
8593
  name: config.name,
@@ -8618,7 +8621,7 @@ var defaultConnectionFactory = async (config) => {
8618
8621
  await client.close();
8619
8622
  }
8620
8623
  };
8621
- };
8624
+ }
8622
8625
  function narrowContent(block) {
8623
8626
  if (typeof block !== "object" || block === null) return null;
8624
8627
  const b = block;
@@ -8766,14 +8769,54 @@ function runDoctor(opts = {}) {
8766
8769
  checks.push(checkConfig(qaiosDir, qaiosExists));
8767
8770
  checks.push(checkPlaywright(cwd));
8768
8771
  checks.push(checkAxeCore(cwd));
8769
- checks.push({
8770
- name: "MCP servers",
8771
- status: "skip",
8772
- detail: "wired up in W8-T1 (MCP client)"
8773
- });
8772
+ checks.push(checkMcpServers(qaiosDir, qaiosExists));
8774
8773
  const exitCode = checks.some((c) => c.status === "fail") ? ExitCode.TOOL_ERROR : ExitCode.SUCCESS;
8775
8774
  return { exitCode, checks };
8776
8775
  }
8776
+ function checkMcpServers(qaiosDir, qaiosExists) {
8777
+ const name = "MCP servers";
8778
+ if (!qaiosExists) return { name, status: "skip", detail: "skipped (no .qaios/)" };
8779
+ const dbPath = path15.join(qaiosDir, "workflows.db");
8780
+ if (!existsSync(dbPath)) return { name, status: "skip", detail: "skipped (no workflows.db)" };
8781
+ let storage;
8782
+ try {
8783
+ storage = Storage.open(dbPath, { skipMigrations: true });
8784
+ const servers = new McpServersRepository(storage.db).list();
8785
+ if (servers.length === 0) {
8786
+ return { name, status: "ok", detail: "no servers configured" };
8787
+ }
8788
+ const unsupported = servers.filter((server) => server.type !== "stdio");
8789
+ const invalidStdio = servers.filter(
8790
+ (server) => server.type === "stdio" && !server.command?.trim()
8791
+ );
8792
+ if (unsupported.length > 0 || invalidStdio.length > 0) {
8793
+ const details = [];
8794
+ if (unsupported.length > 0) {
8795
+ details.push(
8796
+ `unsupported transport on ${unsupported.map((server) => server.name).join(", ")} (only stdio is available)`
8797
+ );
8798
+ }
8799
+ if (invalidStdio.length > 0) {
8800
+ details.push(`missing command on ${invalidStdio.map((server) => server.name).join(", ")}`);
8801
+ }
8802
+ return { name, status: "warn", detail: details.join("; ") };
8803
+ }
8804
+ const enabled = servers.filter((server) => server.enabled).length;
8805
+ return {
8806
+ name,
8807
+ status: "ok",
8808
+ detail: `${servers.length} configured (${enabled} enabled); local configuration valid`
8809
+ };
8810
+ } catch (err) {
8811
+ return {
8812
+ name,
8813
+ status: "fail",
8814
+ detail: `could not inspect MCP configuration: ${err.message}`
8815
+ };
8816
+ } finally {
8817
+ storage?.close();
8818
+ }
8819
+ }
8777
8820
  function checkConfig(qaiosDir, qaiosExists) {
8778
8821
  const name = "config.yaml";
8779
8822
  if (!qaiosExists) return { name, status: "skip", detail: "skipped (no .qaios/)" };
@@ -9197,8 +9240,8 @@ function scopeFooterApi(scope) {
9197
9240
  }
9198
9241
  var STATUS_OR_RESPONSE_PATTERN = /\b[1-5]\d\d\b|response\./i;
9199
9242
  var MIN_SCENARIOS_PER_ENDPOINT = 3;
9200
- function endpointStepPattern(path20, method) {
9201
- const escaped = path20.split("/").map(
9243
+ function endpointStepPattern(path21, method) {
9244
+ const escaped = path21.split("/").map(
9202
9245
  (seg) => /^\{.*\}$/.test(seg) ? "[^/\\s?#]+" : seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
9203
9246
  ).join("/");
9204
9247
  return new RegExp(`\\b${method}\\b[\\s\\S]*?${escaped}(?=$|[\\s?#])`, "i");
@@ -10244,12 +10287,13 @@ var WriteWebInput = z.object({
10244
10287
  });
10245
10288
  var WRITE_WEB_HTML_MAX_CHARS = 5e4;
10246
10289
  var HEADER_PLACEHOLDERS = {
10290
+ version: "<qaios-version will be filled by runtime>",
10247
10291
  workflowId: "<ulid will be filled by runtime>",
10248
10292
  generatedAt: "<iso-8601 will be filled by runtime>",
10249
10293
  designSpecPath: "<workflow-id>"
10250
10294
  };
10251
- function injectGeneratedFileHeader(contents, workflowId, generatedAtIso) {
10252
- return contents.split(HEADER_PLACEHOLDERS.workflowId).join(workflowId).split(HEADER_PLACEHOLDERS.generatedAt).join(generatedAtIso).split(HEADER_PLACEHOLDERS.designSpecPath).join(workflowId);
10295
+ function injectGeneratedFileHeader(contents, workflowId, generatedAtIso, qaiosVersion) {
10296
+ return contents.split(HEADER_PLACEHOLDERS.version).join(qaiosVersion).split(HEADER_PLACEHOLDERS.workflowId).join(workflowId).split(HEADER_PLACEHOLDERS.generatedAt).join(generatedAtIso).split(HEADER_PLACEHOLDERS.designSpecPath).join(workflowId);
10253
10297
  }
10254
10298
  var IMPORT_ALLOW_LIST = ["@playwright/test"];
10255
10299
  var ASSERTION_RE = /\bexpect\s*\(/;
@@ -10353,7 +10397,7 @@ Output requirements:
10353
10397
  - Header comment on every generated file (emit literally; the runtime
10354
10398
  fills the placeholder tokens):
10355
10399
 
10356
- // Generated by QAIOS v0.1.x (workflow: ${HEADER_PLACEHOLDERS.workflowId})
10400
+ // Generated by QAIOS v${HEADER_PLACEHOLDERS.version} (workflow: ${HEADER_PLACEHOLDERS.workflowId})
10357
10401
  // Generated at: ${HEADER_PLACEHOLDERS.generatedAt}
10358
10402
  // DesignSpec: .qaios/specs/${HEADER_PLACEHOLDERS.designSpecPath}/DesignSpec.json
10359
10403
  // Edit freely \u2014 QAIOS will preserve manual changes when re-generating.
@@ -10462,7 +10506,7 @@ Output requirements:
10462
10506
  - Header comment on every generated file (emit literally; the runtime
10463
10507
  fills the placeholder tokens):
10464
10508
 
10465
- // Generated by QAIOS v0.1.x (workflow: ${HEADER_PLACEHOLDERS.workflowId})
10509
+ // Generated by QAIOS v${HEADER_PLACEHOLDERS.version} (workflow: ${HEADER_PLACEHOLDERS.workflowId})
10466
10510
  // Generated at: ${HEADER_PLACEHOLDERS.generatedAt}
10467
10511
  // DesignSpec: .qaios/specs/${HEADER_PLACEHOLDERS.designSpecPath}/DesignSpec.json
10468
10512
  // Edit freely \u2014 QAIOS will preserve manual changes when re-generating.
@@ -10554,6 +10598,16 @@ var skills = {
10554
10598
  "explore.charter": exploreCharterSkill,
10555
10599
  "audit.a11y": auditA11ySkill
10556
10600
  };
10601
+ var moduleDir = path15.dirname(fileURLToPath(import.meta.url));
10602
+ function getQaiosVersion() {
10603
+ try {
10604
+ const packagePath = path15.resolve(moduleDir, "..", "package.json");
10605
+ const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
10606
+ return pkg.version?.trim() || "0.0.0";
10607
+ } catch {
10608
+ return "0.0.0";
10609
+ }
10610
+ }
10557
10611
 
10558
10612
  // src/llm.ts
10559
10613
  function resolveLlmClient(injected, llmConfig) {
@@ -10768,7 +10822,12 @@ async function runA11y(opts) {
10768
10822
  if (target !== "stdout" && mcpClient === void 0) {
10769
10823
  const repoMcp = new McpServersRepository(storage.db);
10770
10824
  const servers = repoMcp.list();
10771
- mcpClient = new McpClient({ servers, auditLogger, workflowId });
10825
+ mcpClient = new McpClient({
10826
+ servers,
10827
+ auditLogger,
10828
+ workflowId,
10829
+ clientVersion: getQaiosVersion()
10830
+ });
10772
10831
  }
10773
10832
  for (const issue of violations) {
10774
10833
  const filed = await fileIssueAsDefect({
@@ -11090,28 +11149,27 @@ async function runExplore(opts) {
11090
11149
  const sevCount = countBySeverity(findings);
11091
11150
  writeOut(`Session complete. Duration: ${formatDuration(exploreOutput.durationActual)}`);
11092
11151
  writeOut(
11093
- `Findings: ${findings.length}` + (findings.length > 0 ? ` (${sevSummary(sevCount)})` : "")
11152
+ `Unverified hypotheses: ${findings.length}` + (findings.length > 0 ? ` (${sevSummary(sevCount)})` : "")
11094
11153
  );
11095
11154
  for (const f of findings) {
11096
- writeOut(` ${GLYPH2.finding} [${f.severity.toUpperCase()}] ${f.title}`);
11155
+ writeOut(` ${GLYPH2.finding} [UNVERIFIED/${f.severity.toUpperCase()}] ${f.title}`);
11097
11156
  }
11098
11157
  writeOut("");
11099
11158
  let defectsFiled = 0;
11100
- if (opts.noDefects === true || findings.length === 0) {
11159
+ const target = opts.defectTarget ?? config?.defects?.target ?? "stdout";
11160
+ if (target !== "stdout" && findings.length > 0) {
11161
+ writeOut(
11162
+ `${GLYPH2.warn} External defect filing is disabled for unverified exploratory hypotheses. Reproduce the finding independently before filing it.`
11163
+ );
11164
+ } else if (opts.noDefects === true || findings.length === 0) {
11101
11165
  if (findings.length > 0 && opts.noDefects === true) {
11102
11166
  writeOut("Skipping defect filing (--no-defects).");
11103
11167
  }
11104
11168
  } else {
11105
- const target = opts.defectTarget ?? config?.defects?.target ?? "stdout";
11106
11169
  const repo = opts.defectRepo ?? config?.defects?.repo;
11107
11170
  const project = opts.defectProject ?? config?.defects?.project;
11108
11171
  writeOut(`Filing defects (target: ${target})...`);
11109
- let mcpClient = opts.mcpClient;
11110
- if (target !== "stdout" && mcpClient === void 0) {
11111
- const repoMcp = new McpServersRepository(storage.db);
11112
- const servers = repoMcp.list();
11113
- mcpClient = new McpClient({ servers, auditLogger, workflowId });
11114
- }
11172
+ const mcpClient = opts.mcpClient;
11115
11173
  for (const f of findings) {
11116
11174
  const filed = await fileFindingAsDefect({
11117
11175
  finding: f,
@@ -11133,9 +11191,6 @@ async function runExplore(opts) {
11133
11191
  writeOut(` ${GLYPH2.failed} ${f.title} \u2014 ${filed.error ?? "unknown failure"}`);
11134
11192
  }
11135
11193
  }
11136
- if (mcpClient !== void 0 && opts.mcpClient === void 0) {
11137
- await mcpClient.close();
11138
- }
11139
11194
  }
11140
11195
  finalize2("succeeded");
11141
11196
  return {
@@ -11143,6 +11198,7 @@ async function runExplore(opts) {
11143
11198
  workflowId,
11144
11199
  charter: exploreOutput.charter,
11145
11200
  findings,
11201
+ findingsVerification: "unverified",
11146
11202
  defectsFiled
11147
11203
  };
11148
11204
  } finally {
@@ -12472,12 +12528,20 @@ function addServer(repo, opts, writeOut) {
12472
12528
  exitCode: ExitCode.USER_ERROR,
12473
12529
  error: {
12474
12530
  code: "qaios.mcp.no_command_or_url",
12475
- message: "qaios mcp add requires a <command-or-url> argument (a binary path for stdio, or a URL for http/sse)."
12531
+ message: "qaios mcp add requires a <command> argument for a stdio server."
12532
+ }
12533
+ };
12534
+ }
12535
+ const type = opts.type ?? "stdio";
12536
+ if (type !== "stdio" || /^https?:\/\//i.test(opts.commandOrUrl)) {
12537
+ return {
12538
+ exitCode: ExitCode.USER_ERROR,
12539
+ error: {
12540
+ code: "qaios.mcp.transport_not_supported",
12541
+ message: "Only MCP stdio transport is supported in this release. HTTP and SSE registration are disabled until their runtime implementations and contract tests ship."
12476
12542
  }
12477
12543
  };
12478
12544
  }
12479
- const inferredType = /^https?:\/\//i.test(opts.commandOrUrl) ? "http" : "stdio";
12480
- const type = opts.type ?? inferredType;
12481
12545
  const env = { ...opts.env ?? {} };
12482
12546
  const secretKeys = Object.entries(env).filter(([, v]) => looksLikeSecret(v)).map(([k]) => k);
12483
12547
  if (secretKeys.length > 0) {
@@ -12496,7 +12560,7 @@ function addServer(repo, opts, writeOut) {
12496
12560
  env,
12497
12561
  enabled: opts.enabled !== false,
12498
12562
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
12499
- ...type === "stdio" ? { command: opts.commandOrUrl } : { url: opts.commandOrUrl }
12563
+ command: opts.commandOrUrl
12500
12564
  };
12501
12565
  const persisted = repo.upsert(config);
12502
12566
  writeOut(
@@ -12574,7 +12638,8 @@ async function testServer(repo, opts, writeOut) {
12574
12638
  const client = opts.mcpClient ?? new McpClient({
12575
12639
  // For `test` we always include the target server even if it's
12576
12640
  // disabled — the user explicitly asked us to test it.
12577
- servers: [{ ...config, enabled: true }]
12641
+ servers: [{ ...config, enabled: true }],
12642
+ clientVersion: getQaiosVersion()
12578
12643
  });
12579
12644
  const ownsClient = opts.mcpClient === void 0;
12580
12645
  const MCP_TEST_TIMEOUT_MS = 15e3;
@@ -14457,8 +14522,8 @@ ${epSummary}`;
14457
14522
  gateConfig.autoExpireOnTimeout = "auto_approve";
14458
14523
  }
14459
14524
  const costCap = {
14460
- maxCalls: config?.llm?.maxLlmCallsPerWorkflow ?? 15,
14461
- maxUsdCents: config?.llm?.costAlertThresholdUsdCents ?? 50
14525
+ maxCalls: config?.llm?.maxLlmCallsPerWorkflow ?? 20,
14526
+ maxUsdCents: config?.llm?.costAlertThresholdUsdCents ?? 100
14462
14527
  };
14463
14528
  const orchestrator = new Orchestrator({
14464
14529
  storage,
@@ -14536,7 +14601,8 @@ ${epSummary}`;
14536
14601
  const injected = injectGeneratedFileHeader(
14537
14602
  file.contents,
14538
14603
  result.workflowId,
14539
- generatedAtIso
14604
+ generatedAtIso,
14605
+ getQaiosVersion()
14540
14606
  );
14541
14607
  writeFileSync(absPath, injected);
14542
14608
  filesWritten.push(file.path);
@@ -14634,20 +14700,9 @@ Ran generated tests: ${runSummary.passedCount} passed, ${runSummary.failedCount}
14634
14700
  }
14635
14701
 
14636
14702
  // src/index.ts
14637
- var __dirname2 = path15.dirname(fileURLToPath(import.meta.url));
14638
- function readPackageVersion() {
14639
- for (const candidate of [path15.resolve(__dirname2, "..", "package.json")]) {
14640
- try {
14641
- const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
14642
- if (pkg.version) return pkg.version;
14643
- } catch {
14644
- }
14645
- }
14646
- return "0.0.0";
14647
- }
14648
14703
  function buildProgram() {
14649
14704
  const program = new Command();
14650
- program.name("qaios").description("AI QA engineer in your terminal").version(readPackageVersion(), "-V, --version", "print QAIOS version, exit 0").option("--workflow <id>", "explicitly set or resume a workflow ID").option("--mode <mode>", "override mode for this run (LITE | FULL | TRUST)").option("--non-interactive", "disable interactive prompts").option("--verbose", "log level: debug").option("--debug", "log level: trace").option("--quiet", "only errors to stderr; minimum stdout output").option("--json", "emit primary output as JSON (machine-readable)").option("--no-color", "disable ANSI color").showHelpAfterError();
14705
+ program.name("qaios").description("AI QA engineer in your terminal").version(getQaiosVersion(), "-V, --version", "print QAIOS version, exit 0").option("--workflow <id>", "explicitly set or resume a workflow ID").option("--mode <mode>", "override mode for this run (LITE | FULL | TRUST)").option("--non-interactive", "disable interactive prompts").option("--verbose", "log level: debug").option("--debug", "log level: trace").option("--quiet", "only errors to stderr; minimum stdout output").option("--json", "emit primary output as JSON (machine-readable)").option("--no-color", "disable ANSI color").showHelpAfterError();
14651
14706
  program.command("init [path]").description("Bootstrap a project: create .qaios/, QAIOS.md, run migrations").option("--mode <mode>", "mode to write to config (LITE | FULL | TRUST)").option("--framework <name>", 'test framework (only "playwright" in v0.1)').option("--test-dir <path>", "relative path to test directory").option("--non-interactive", "skip prompts; use defaults").option("--force", "overwrite existing .qaios/").action((cwdArg, cmdOpts) => {
14652
14707
  const initOpts = {
14653
14708
  nonInteractive: Boolean(cmdOpts["nonInteractive"]),
@@ -14998,7 +15053,7 @@ function buildProgram() {
14998
15053
  mcpGroup.command("list").description("Show every registered MCP server").action((cmdOpts, command) => {
14999
15054
  void runMcpVerb("list", cmdOpts, command, {});
15000
15055
  });
15001
- mcpGroup.command("add <name> <command-or-url>").description("Register an MCP server (stdio command path or http/sse URL)").option("--type <type>", "transport: stdio | http | sse (inferred when omitted)").option(
15056
+ mcpGroup.command("add <name> <command>").description("Register an MCP stdio server command").option("--type <type>", "transport: stdio (HTTP/SSE are not yet supported)", "stdio").option(
15002
15057
  "--arg <arg>",
15003
15058
  "stdio command-line arg (repeatable)",
15004
15059
  (v, prev = []) => [...prev, v]
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@qatonic_innovations/qaios",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
- "description": "AI QA engineer in your terminal — designs, writes, runs, heals, and explores tests for web UI and APIs with audit-grade traceability.",
5
+ "description": "AI QA engineer in your terminal — designs, writes, runs, heals, and explores tests with tamper-evident local history.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/qatonic/qaios#readme",
8
8
  "repository": {