@yawlabs/mcp 0.62.0 → 0.63.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  All notable changes to `@yawlabs/mcp` (formerly `@yawlabs/mcph`) are documented here. This project uses [semantic versioning](https://semver.org) and a script-gated release flow: `./release.sh <version>` runs lint + tests + build, bumps, tags, publishes to npm, and creates the GitHub release.
4
4
 
5
+ ## 0.63.1 -- CLI follow-ups: wire dead --dry-run/--stdin flags, fix completion drift, dedup probes
6
+
7
+ Patch-level follow-ups on the 0.63.0 CLI hardening pass. All fixes; no behavior changes for callers who weren't already hitting the dead-flag bugs.
8
+
9
+ - **`sync push --dry-run`** now short-circuits before any remote mutation. The flag was parsed but never checked by `syncPush`, so a "dry-run" PUT actually mutated `mcp_bundles`. Preview now prints server count and exits 0 without calling `putResource`.
10
+ - **`secrets set --stdin`** now reads raw multi-line stdin even on a TTY. The flag was parsed but never consumed by `runSecrets`, so it silently fell through to the line-buffered echo-off prompt regardless. `--stdin` now forces the raw read path as documented.
11
+ - **`install <client> --dry-run`** now bypasses the collision gate. With an existing yaw-mcp entry + non-TTY stdin, the gate refused before the dry-run preview block ever ran -- so the "...or --dry-run to preview" hint was unreachable. The decision chain now treats `dryRun` like `force` for the overwrite-vs-skip choice.
12
+ - **Completion `SUBCOMMAND_SPEC` drift fixed.** `sync` no longer advertises a phantom `--key` (replaced with the real `--dry-run`); `secrets` no longer advertises a phantom `--key` (replaced with the real `--force`).
13
+ - **`try-cmd` telemetry POSTs are now awaited.** Three fire-and-forget `postEvent(...).catch(() => undefined)` calls (try / cleanup / expiry-gc) could be killed by `process.exit` before the request landed. Now awaited so the analytics event reliably reaches the backend before exit.
14
+ - **`doctor` `state.json` double-read eliminated.** `peekStateFile` hoisted to the caller and the result threaded into `renderStateSection`, removing the redundant disk read inside the section.
15
+ - **`doctor` probe duplication removed.** Extracted `classifyProbeContent` shared by both sync and async client-config probes (~60 lines deduped). Also added the missing `try/catch` around `resolveInstallPath` in `probeClientsAsync` for parity with the sync variant.
16
+ - **`secrets get` / `remove` against a missing vault or missing entry** now short-circuit before the passphrase prompt, avoiding the wasted scrypt key derivation just to say "not found".
17
+ - **`upgrade-cmd`:** removed unreachable `if (!plan.command)` branch -- every install method whose plan reaches that point already returned earlier in the chain.
18
+ - **`index.ts` help text:** corrected the `YAW_MCP_AUTO_UPGRADE` description ("yaw-mcp serve startup" was not a subcommand; now "server startup").
19
+
20
+ ## 0.63.0 -- CLI hardening: flag parsing, exit-code consistency, secret-file perms, dispatch error handling
21
+
22
+ A full-pass sweep of the `yaw-mcp` subcommand surface. Every change is a fix, a hardening, or additive; there are no breaking changes to the MCP server or the public CLI contract.
23
+
24
+ - **Value-taking flags no longer swallow a following flag.** `login --key`, `secrets set --value`, `try --base`, and `add --catalog` reject a dash-prefixed token instead of storing it as the value -- e.g. `login --key --json` no longer POSTs `"--json"` as the license key, and `try slug --base --dry-run` no longer silently drops `--dry-run` and wires the trial for real. (`--value` points at `--stdin` for a genuinely dash-leading secret.)
25
+ - **`--help` / exit-code consistency.** `yaw-mcp audit --help` and `compliance --help` now print usage to stdout and exit 0 like every other subcommand (compliance previously forwarded `--help` into an `npx` download); `compliance` with no target exits 2 (arg error) instead of 1.
26
+ - **Uncaught command rejections are handled.** Every subcommand funnels through a shared dispatcher `.catch` that prints `yaw-mcp <cmd>: <message>` and exits 1, instead of dumping a raw Node stack and bypassing the logger (reachable e.g. via `secrets` against a corrupt vault).
27
+ - **Secret-bearing files are born 0600.** `atomicWriteFile` gained a creation-mode option; the token config, team session cookie, encrypted vault, and the install config backup are now written owner-only rather than sitting at the default umask in the window before the post-hoc chmod. `install --dry-run` redacts the token in the config dump, and `--token` carries a process-table exposure note.
28
+ - **`doctor`:** `--json` now runs the same expired-trial GC as the text path, and the snapshot carries the `trials` + `backgroundPosters` sections (it was not the "1:1 mirror" its comment claimed). The header documents the config read-modify-write side effect and the now-unreachable exit code 1.
29
+ - **Completion drift guard made real.** Shell completion now offers `foundry`, and the completion test asserts coverage against the real dispatch table (extracted to `src/subcommands.ts`) instead of a hand-maintained list that had silently diverged.
30
+ - **`secrets`:** `get` documents that it prints cleartext (with an interactive-TTY stderr warning); Ctrl-D at the passphrase prompt cancels instead of submitting a partial passphrase; `pull` empty-remote `--json` carries the same hint as the prose path.
31
+ - **`compliance --publish`** projects the report to an explicit allowlist before upload (no echoed env/argv/stack leaks), and the suite child's stdout is capped (16 MB) behind a wall-clock watchdog.
32
+ - **`upgrade`:** the `_npx` marker now requires the full npm-cache hex context, so a user project path that merely contains a `_npx` segment is no longer misclassified as an npx run; the 1->2 exit sequence for non-runnable methods (binary/dev-checkout) is documented.
33
+ - **`add`** trims whitespace-only `--env` values so a blank-ish required secret is never persisted to bundles.json. Did-you-mean now includes `help`, gates its substring tier for very short queries, and a leading-dash near-miss (`--versionn`) suggests the flag instead of silently booting the MCP server.
34
+ - **deps:** `esbuild` override pinned to `^0.28.1`.
35
+
5
36
  ## 0.62.0 -- verifiable-signal routing: graded reward, miss tracking, and an eval foundry
6
37
 
7
38
  Lands #25, #26, and #27. The dispatch router's learning signal moves from a binary "any non-error reply counts as success" to a sound, quality-graded reward, plus the surrounding machinery to manufacture and verify that signal. All of the new behavior is additive and the new knobs are off by default, so existing setups are unchanged.
@@ -9,12 +9,12 @@ import { join } from "path";
9
9
  // src/atomic-write.ts
10
10
  import { mkdir, rename, unlink, writeFile } from "fs/promises";
11
11
  import path from "path";
12
- async function atomicWriteFile(filePath, contents, encoding = "utf8") {
12
+ async function atomicWriteFile(filePath, contents, encoding = "utf8", mode) {
13
13
  const dir = path.dirname(filePath);
14
14
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
15
15
  await mkdir(dir, { recursive: true });
16
16
  try {
17
- await writeFile(tmp, contents, encoding);
17
+ await writeFile(tmp, contents, mode === void 0 ? { encoding } : { encoding, mode });
18
18
  await rename(tmp, filePath);
19
19
  } catch (err) {
20
20
  await unlink(tmp).catch(() => void 0);
@@ -144,7 +144,7 @@ async function loadStoredState(filePath) {
144
144
  async function saveStoredState(filePath, state) {
145
145
  cachedState = { filePath, state };
146
146
  try {
147
- await atomicWriteFile(filePath, JSON.stringify(state, null, 2));
147
+ await atomicWriteFile(filePath, JSON.stringify(state, null, 2), "utf8", 384);
148
148
  if (process.platform !== "win32") {
149
149
  try {
150
150
  await chmod(filePath, 384);