@plune-ai/cli 0.32.2 → 0.34.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.
package/README.md CHANGED
@@ -121,8 +121,9 @@ the last resort, used only when `PLUNE_TOKEN` is set nowhere else. Nothing write
121
121
  | `plune init` | Scaffold `plune.yaml`, a sample dataset, and `.env.example`. Flags: `--yes` (non-interactive), `--force`. |
122
122
  | `plune login` | Save a [Plune platform](https://plune.ai/platform) API token so `sync` and `ingest` can reach it. The token is **checked against the API before it is saved**, so a wrong one fails here rather than two commands later. Get one at `https://beta.plune.ai` → Account → API tokens. Flags: `--token <token>` (omit to paste it or pipe it via stdin), `--skip-verify` (save without checking, for offline setup). In CI, skip this step: every platform command reads `PLUNE_TOKEN` from the environment first, and the saved login only when it is not set. |
123
123
  | `plune logout` | Remove the saved token. |
124
+ | `plune mcp serve` | Serve the Plune tools to an AI agent (Claude Code, Codex, any MCP client) over **MCP stdio**. See [Plune tools for AI agents](#plune-tools-for-ai-agents-plune-mcp). Flags: `--project <id>` (default `PLUNE_PROJECT`), `--read-only` (offer only the read tools). |
124
125
  | `plune sync` | Upload the latest local run to the platform. Flags: `--file <path>` to send a specific run JSON, `--fail-on-failures` to read the run's summary back once after the upload and exit with [the gate](#a-release-gate---fail-on-failures)'s code. Each upload carries an `Idempotency-Key` (SHA-256 of the body), so sending the same run again returns the same run rather than creating a second one. Against a platform with `POST /v1/jobs` the upload is also reported as a job (kind `sync`, counting the run's rows) that ends completed, or failed with the error text if the sync fails; an older platform without the route is not told, and a job report never fails the sync: when the sync goes through, one the platform did not take is said in one line on stderr. |
125
- | `plune run import <file \| folder>` | Turn a **JUnit XML** or **Playwright JSON** report, a **folder of JUnit XML files** (Maven Surefire's `target/surefire-reports`, Gradle's `build/test-results/test`), or an **Allure `allure-results` folder**, into a run in Plune. Needs no provider key — nothing is generated. Flags: `--format junit\|playwright-json\|allure` (detected when omitted: a folder with a `*-result.json` is Allure, any other folder is read as the JUnit `*.xml` files in it), `--name <text>` to call the run something other than the [folder-based default](#what-the-run-is-called), `--key <externalKey>` to land several reports in one run (with `PLUNE_SHARED_RUN=1` — see below), `--create` to offer unmatched tests to the review queue, `--fail-on-missing-attachments` to exit 1 when a file a JUnit report names with `[[ATTACHMENT\|path]]`, or an Allure result names as a `source`, is not there (the results are sent either way), `--upload-concurrency <n>` for files uploaded at once ([1 to 32, default 16](#many-screenshots-upload-concurrency-and-retries)), `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code on the summary the platform froze when this import finished the run. |
126
+ | `plune run import <file \| folder>` | Turn a **JUnit XML** or **Playwright JSON** report, a **k6 summary** or **Lighthouse JSON** report, a **folder of JUnit XML files** (Maven Surefire's `target/surefire-reports`, Gradle's `build/test-results/test`), or an **Allure `allure-results` folder**, into a run in Plune. Needs no provider key — nothing is generated. Flags: `--format junit\|playwright-json\|allure\|k6\|lighthouse` (detected when omitted: a folder with a `*-result.json` is Allure, any other folder is read as the JUnit `*.xml` files in it), `--name <text>` to call the run something other than the [folder-based default](#what-the-run-is-called), `--min-score <category>=<0-100>` (repeatable) for the score a [Lighthouse](#a-k6-summary-or-a-lighthouse-report) category needs to pass, `--key <externalKey>` to land several reports in one run (with `PLUNE_SHARED_RUN=1` — see below), `--create` to offer unmatched tests to the review queue, `--fail-on-missing-attachments` to exit 1 when a file a JUnit report names with `[[ATTACHMENT\|path]]`, or an Allure result names as a `source`, is not there (the results are sent either way), `--upload-concurrency <n>` for files uploaded at once ([1 to 32, default 16](#many-screenshots-upload-concurrency-and-retries)), `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code on the summary the platform froze when this import finished the run. |
126
127
  | `plune run start` | Open a platform run — or join the one already carrying `--key` — and print its id. Flags: `--key <externalKey>` (generated when absent), `--name <text>` to call the run something other than the [default](#what-the-run-is-called), `--json` for one machine-readable line. |
127
128
  | `plune run finish <id>` | Close a platform run. This is what the reporter tells you to do for a run it had to leave open. Flags: `--terminate` to record it as cut short, `--reason <text>`, `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code on the summary the platform froze. |
128
129
  | `plune run exec -- <command>` | Open a run, run the command inside it, close the run — and exit with whatever the command returned. Sets `PLUNE_SHARED_RUN` for you, so anything reporting inside joins that run. Flags: `--key <externalKey>`, `--name <text>` (as on `run start`), `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code instead — or with the command's own when no result reached the run. |
@@ -242,6 +243,8 @@ plune run import ./junit.xml # Jest, Vitest, pytest, PHPUnit, Surefire,
242
243
  plune run import target/surefire-reports # or a folder of JUnit files: Maven, Gradle — see Java below
243
244
  plune run import ./playwright.json # or Playwright's own JSON report
244
245
  plune run import ./allure-results # or the folder an Allure adapter wrote — see below
246
+ plune run import ./summary.json # or a k6 summary, thresholds as pass or fail — see below
247
+ plune run import ./lighthouse.json # or a Lighthouse report, a category per result — see below
245
248
  ```
246
249
 
247
250
  The format is read from the file, not from its name. Statuses go over as the report wrote them and
@@ -410,6 +413,56 @@ For a JUnit report, check that the output reaches the report: Gradle writes it o
410
413
  and Maven Surefire moves it out of the XML when `redirectTestOutputToFile` is `true`. As in the Playwright
411
414
  reporter, a file whose name starts with an underscore is skipped, and a file several tests name is uploaded once per test.
412
415
 
416
+ ### A k6 summary or a Lighthouse report
417
+
418
+ Plune runs no load or page-speed tests of its own: it takes the results of the tools that do, as a run.
419
+
420
+ **k6.** Import the end-of-test summary, written with `k6 run --summary-export=summary.json script.js` or
421
+ from `handleSummary` (`return { 'summary.json': JSON.stringify(data) }`; both have the same `metrics`).
422
+ Each threshold of each metric is one result, named after the metric and the expression
423
+ (`http_req_duration p(95)<500`): passed when k6 says the threshold held, failed when it was crossed. The
424
+ metric's measured values (`avg`, `p(95)`, `rate`, …) are the result's message. A summary with no
425
+ thresholds is refused (exit 2) and nothing is imported: k6 judged nothing, so there is nothing to pass or fail.
426
+ A threshold is known by the file's name as well as the metric and the expression, so `smoke.json` and
427
+ `load.json` imported under one `--key` stay two results each; renaming the summary file starts a new test.
428
+
429
+ Only the file's base name counts, not its folder: `a/summary.json` and `b/summary.json` give the same keys.
430
+ So when the jobs of a matrix import into one run under one `--key`, each job names its summary file
431
+ apart, or every job's thresholds land on one result (the same key twice is a duplicate, not a second
432
+ result) and all but one job's verdict is lost:
433
+
434
+ ```yaml
435
+ - run: k6 run --summary-export=summary-${{ matrix.scenario }}.json script.js
436
+ ```
437
+
438
+ What a verdict does: a crossed k6 threshold, or a Lighthouse category under its bar, is a **failed** result,
439
+ and only that. The run takes it like any other failed test and is finished as usual — neither the run nor
440
+ the import is stopped or refused for it — and `plune run import` exits 0. To have the job fail, add
441
+ [`--fail-on-failures`](#a-release-gate---fail-on-failures): the command then exits 1 when the summary the
442
+ platform froze has a failed (or broken) result, 0 when every threshold held and every category reached its
443
+ bar. The results are sent either way. A shard that leaves a shared run open has no verdict yet; gate on the
444
+ step that finishes it.
445
+
446
+ **Lighthouse.** Import the JSON report, `lighthouse <url> --output=json --output-path=lighthouse.json`. Each
447
+ category in it (`performance`, `accessibility`, `best-practices`, `seo`, …) is one result, named after the
448
+ category, the page and the form factor Lighthouse ran as (`performance (https://example.com/, mobile)`), so a
449
+ mobile and a desktop report of one page imported under one `--key` are two sets of results, with the score as Lighthouse shows it, 0–100. It passes at or above the bar:
450
+ `--min-score performance=80` sets it per category (repeat the flag), and a category you do not name needs 90,
451
+ where Lighthouse's own "good" band starts. A category Lighthouse could not score (`null`) fails and says so;
452
+ a report that stopped on a runtime error (`NO_FCP`, …) fails every category with that error's message
453
+ (`NO_ERROR`, which older Lighthouse writes into a clean report, is no error). A `--min-score` for a category
454
+ the report does not have (`perf=95` for `performance`) is refused with exit 2 and the categories it does have,
455
+ and so is `--min-score` for any report that is not Lighthouse, a folder included; no run is opened either way.
456
+
457
+ ```bash
458
+ plune run import summary.json
459
+ plune run import lighthouse.json --min-score performance=80 --min-score seo=95
460
+ ```
461
+
462
+ Both are recognised by their own keys (`metrics` for k6, `lighthouseVersion` and `categories` for
463
+ Lighthouse), never by the file name; `--format k6` or `--format lighthouse` says it outright. A report file
464
+ that starts with a UTF-8 byte order mark is read as if it did not, in every format.
465
+
413
466
  ### Several jobs, one run
414
467
 
415
468
  Two suites, or a sharded matrix, report into a single run when every job shares a key **and** knows
@@ -570,6 +623,32 @@ and is never printed or logged. `PLUNE_API_URL` points `sync`, `pull` and `push`
570
623
  useful for a self-hosted backend. The Markdown format `pull` writes and `push` reads is documented at
571
624
  [docs.plune.ai/platform/cases/markdown](https://docs.plune.ai/platform/cases/markdown/).
572
625
 
626
+ ### Plune tools for AI agents: `plune mcp`
627
+
628
+ `plune mcp serve` gives an agent the same Plune your token reaches — the review queue, cases,
629
+ missions, questions, strategy, reports — as MCP tools over stdio. The agent sees at most 20 tools at
630
+ once; the rest it finds with `plune_discover_tools`. Every write tool takes `dry_run`, batches stop at
631
+ 100 items, and the agent is held to the platform's agent rules: a proposed case lands in the review
632
+ queue, a bulk decision needs a confirm, and nothing is deleted through MCP.
633
+
634
+ Claude Code:
635
+
636
+ ```bash
637
+ claude mcp add plune -- npx -y @plune-ai/cli mcp serve
638
+ ```
639
+
640
+ Codex (`~/.codex/config.toml`):
641
+
642
+ ```toml
643
+ [mcp_servers.plune]
644
+ command = "npx"
645
+ args = ["-y", "@plune-ai/cli", "mcp", "serve"]
646
+ ```
647
+
648
+ The server reads the token the way every platform command does: `PLUNE_TOKEN` from the environment
649
+ (set it in the client's `env` block), else the login `plune login` saved. A read token, or
650
+ `--read-only`, offers only the read tools.
651
+
573
652
  ## Programmatic API
574
653
 
575
654
  The same engine that powers `plune run` is exported for use from your own code. Unlike the