Skip to content

Launch Zaparoo CLI v2 - #2

Merged
wizzomafizzo merged 9 commits into
mainfrom
feat/zaparoo-cli-v2
Aug 4, 2026
Merged

Launch Zaparoo CLI v2#2
wizzomafizzo merged 9 commits into
mainfrom
feat/zaparoo-cli-v2

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Aug 2, 2026

Copy link
Copy Markdown
Member

Summary

  • replace MCP runtime with bounded zaparoo-cli workflows for all 90 registered Core methods and 20 notifications
  • add public Online User API support for all 13 documented GET operations, protected saved/environment credentials, pagination, polling, and verified backup downloads
  • ship seven portable Agent Skills for development, Online account data, troubleshooting, media, NFC, ZapScript, and offline artifacts
  • publish as @zaparoo/cli with structured output contracts, redacted diagnostics, package/install smoke tests, and trusted-publishing checks

Validation

  • pnpm run api:audit -- --core ../zaparoo-core
  • pnpm run api:user:audit
  • pnpm run check
  • pnpm run typecheck
  • pnpm run skills:check
  • pnpm test (158 tests)
  • pnpm run build
  • pnpm run package:smoke
  • pnpm pack --dry-run
  • npx skills add ./skills --list (7 skills)
  • built CLI help/auth/path-restriction smoke tests
  • git diff --check

Merge gates

Authorized live Core pairing/device acceptance and authenticated Online User API acceptance remain required before merge. No real device or account credentials were used in automated tests.

Ref ZaparooProject/zaparoo-core#1188

Summary by CodeRabbit

  • New Features
    • Introduced the Zaparoo CLI for device discovery, diagnostics, pairing, media, NFC, backups, profiles, settings, notifications, and RPC.
    • Added encrypted device connections and Online account access with pagination, session monitoring, and verified backups.
    • Added human-readable, JSON, and JSON Lines output, command catalogs, safety policies, documentation lookup, and Agent Skills.
  • Documentation
    • Updated installation, usage, output, safety, security, and integration guidance.
  • Chores
    • Renamed the package and executable to @zaparoo/cli and zaparoo-cli.
    • Added automated validation for skills, APIs, packaging, and builds.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 137d6af6-84dd-41ec-bf6c-24d06798bfc1

📥 Commits

Reviewing files that changed from the base of the PR and between fe1c2ff and 5783d72.

📒 Files selected for processing (3)
  • .gitignore
  • skills/zaparoo-online/SKILL.md
  • skills/zaparoo-troubleshooting/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore

📝 Walkthrough

Walkthrough

Changes

The project changes from an MCP server to the @zaparoo/cli package. It adds a command-line interface, Core and Online API clients, PAKE pairing, encrypted sessions, credential storage, Agent Skills, package validation, API audits, smoke tests, and updated documentation and workflows.

Zaparoo CLI foundation

Layer / File(s) Summary
Product and release contracts
.github/workflows/*, package.json, README.md, AGENTS.md, SECURITY.md, docs/*, skills/*
The package, workflows, documentation, security policy, skills, and validation scripts now define the CLI product and release checks.
Core API and encrypted transport
src/api/*, src/crypto/*, src/types.ts
Core method registries, PAKE pairing, AES-GCM sessions, credential storage, API baselines, and protocol tests were added.
Device client foundation
src/client/*, src/discovery/mdns.ts, src/index.ts
WebSocket JSON-RPC communication, device configuration, discovery, endpoint handling, redaction, tracing, and CLI startup were added.
CLI runtime and command handlers
src/cli/*
Argument parsing, command dispatch, Core command handlers, structured output, exit codes, secret input, and secure binary-file output were added.
Online API integration
src/online/*, src/cli/commands/online.ts
Typed Online API requests, credential resolution, pagination, account queries, backup downloads, integrity checks, and JSONL session watching were added.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant CredentialStore
  participant ZaparooClient
  participant Core
  User->>CLI: invoke command
  CLI->>CredentialStore: resolve credentials
  CLI->>ZaparooClient: connect and request
  ZaparooClient->>Core: WebSocket JSON-RPC
  Core-->>ZaparooClient: response or notification
  ZaparooClient-->>CLI: command result
  CLI-->>User: human, JSON, or JSONL output
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the launch of Zaparoo CLI v2, which is the primary change in the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/zaparoo-cli-v2

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (17)
src/cli/commands/online.test.ts-151-171 (1)

151-171: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restore the stdout spy in afterEach.

Line 170 restores the spy only when the test reaches the end. If an assertion between line 166 and line 169 fails, the spy on process.stdout.write stays active for the rest of the file and suppresses output. Add vi.restoreAllMocks() to the existing afterEach block.

💚 Proposed fix
 afterEach(() => {
   vi.unstubAllEnvs();
+  vi.restoreAllMocks();
   for (const directory of directories) rmSync(directory, { recursive: true, force: true });
   directories.length = 0;
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/online.test.ts` around lines 151 - 171, Update the existing
afterEach block in the online command tests to call vi.restoreAllMocks(),
ensuring the process.stdout.write spy created in the watch test is restored even
when assertions fail. Remove the test-local write.mockRestore() if appropriate
to avoid redundant cleanup.
src/online/client.test.ts-90-98 (1)

90-98: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert that the error contains [REDACTED]. rejects.toThrow correctly handles the rejected OnlineApiError, but the current assertion only checks that super-secret is absent. It also passes if the response body is dropped. Assert both [REDACTED] and the absence of super-secret on the same error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/online/client.test.ts` around lines 90 - 98, Update the “redacts keys
from error bodies” test around OnlineClient.get so the rejected error assertion
requires both the presence of “[REDACTED]” and the absence of “super-secret” on
the same OnlineApiError, preserving the existing rejection check.
skills/zaparoo-online/SKILL.md-43-43 (1)

43-43: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Use the contract’s exact 403 wording. Change “account is unavailable” to “account is suspended.” The contract defines 403 as a missing required scope or a suspended account. Keep the instruction not to request broader scope unless required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-online/SKILL.md` at line 43, Update the 403 description in the
relevant instruction to say the key lacks the required scope or the account is
suspended, replacing “account is unavailable.” Preserve the existing guidance
not to request broader scope unless the task requires it.

Source: Coding guidelines

src/crypto/pairing.ts-79-90 (1)

79-90: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Constrain the server-supplied error message.

Line 83 accepts any string from an unauthenticated remote host and line 87 returns it as the error message. pairCommand in src/cli/commands/pair.ts passes that message to CLI output. A hostile host can inject ANSI escape sequences or a very long string into the user's terminal.

Bound the length and strip control characters before you use the server message.

🛡️ Proposed fix
     const body = (await response.json()) as { error?: unknown };
-    if (typeof body.error === 'string') serverMessage = body.error;
+    if (typeof body.error === 'string') {
+      // biome-ignore lint/suspicious/noControlCharactersInRegex: strip terminal control sequences
+      serverMessage = body.error.replace(/[\u0000-\u001f\u007f]/g, ' ').slice(0, 200);
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/crypto/pairing.ts` around lines 79 - 90, Sanitize the serverMessage
handling in pairingError before returning it: strip control characters,
including ANSI escape sequences, and cap the resulting message to a reasonable
maximum length. Apply the sanitized bounded value only when selecting the
server-supplied message, while preserving the existing status-based and fallback
error behavior.
src/cli/commands/readers.ts-13-21 (1)

13-21: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Gate the NFC write behind an explicit confirmation flag.

readers write overwrites the contents of the physical tag. The command runs the write with no confirmation step. Add a required --force (or --yes) flag, or prompt when the session is interactive. The force flag is already in BOOLEAN_FLAGS in src/cli/args.ts.

Based on learnings: "Ask for confirmation before launching or stopping media, sending input or NFC writes, changing mappings/settings/profiles, applying updates, clearing the inbox, or causing downtime".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/readers.ts` around lines 13 - 21, Update the readers write
case to require explicit confirmation before calling request for
Methods.ReadersWrite: accept the existing force boolean flag (or an interactive
confirmation for interactive sessions), and otherwise fail with a usage error.
Preserve the current text validation and request arguments after confirmation
succeeds.

Source: Learnings

src/cli/commands/logs.ts-19-26 (1)

19-26: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate --output before the download request.

The code requests Methods.SettingsLogsDownload first, then checks --output. If the user omits --output, the CLI opens a Core session, downloads the whole log archive, and then throws a usage error. The payload is discarded. src/cli/commands/admin.ts lines 19-22 validate first. Use the same order here.

🐛 Proposed fix
   if (action === 'download') {
+    const output = flag(args.flags, 'output');
+    if (!output) throw new CliError('logs download requires --output <path>', ExitCode.Usage);
     const response = await withClient(args.options, (client) =>
       client.request<BinaryResponse>(Methods.SettingsLogsDownload),
     );
-    const output = flag(args.flags, 'output');
-    if (!output) throw new CliError('logs download requires --output <path>', ExitCode.Usage);
     return { data: writeBase64Output(response, output) };
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/logs.ts` around lines 19 - 26, Move the `flag(args.flags,
'output')` lookup and missing-output `CliError` validation before the
`withClient` call in the `action === 'download'` branch, then perform
`Methods.SettingsLogsDownload` and pass the validated output to
`writeBase64Output`. Match the validation order used by the admin command.
src/cli/commands/screenshot.ts-9-15 (1)

9-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate --output before you open the session.

The handler requests the screenshot at line 10 and validates --output at line 14. If the user omits --output, the command still connects to Core, triggers a screenshot capture on the device, and then fails with a usage error. Move the check to the top of the function.

As per coding guidelines: "Validate required command parameters and add colocated tests for non-trivial mapping."

🐛 Proposed fix
 export async function screenshotCommand(args: ParsedArgs): Promise<CommandResult> {
+  const output = flag(args.flags, 'output');
+  if (!output) throw new CliError('screenshot requires --output <path>', ExitCode.Usage);
   const response = await withClient(args.options, (client) =>
     client.request<BinaryResponse>(Methods.Screenshot),
   );
-  const output = flag(args.flags, 'output');
-  if (!output) throw new CliError('screenshot requires --output <path>', ExitCode.Usage);
   return { data: writeBase64Output(response, output) };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/screenshot.ts` around lines 9 - 15, Move the required
--output validation to the beginning of screenshotCommand, before withClient
initiates the screenshot request; preserve the existing CliError and Usage exit
behavior, then use the validated output value for writeBase64Output.

Source: Coding guidelines

src/cli/commands/devices.ts-83-95 (1)

83-95: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

stateCommand resolves the device twice.

Line 84 calls resolveDevice(args.options). withClient calls resolveDevice again at line 12 of src/cli/commands/common.ts. If resolution falls back to mDNS discovery, the command waits for the discovery timeout twice and doubles the network work.

Use client.device.id inside the callback, as devices ping does at line 39. Also replace the literal method names with Methods.* entries.

♻️ Proposed change
 export async function stateCommand(args: ParsedArgs): Promise<CommandResult> {
-  const device = await resolveDevice(args.options);
   const data = await withClient(args.options, async (client) => ({
-    device: device.id,
+    device: client.device.id,
     version: client.info,
     readers: await client.request(Methods.Readers).catch((error) => ({ error: String(error) })),
     activeMedia: await client
       .request(Methods.MediaActive)
       .catch((error) => ({ error: String(error) })),
     tokenHistory: await client
       .request(Methods.TokensHistory)
       .catch((error) => ({ error: String(error) })),
   }));
-  return { data, human: `State snapshot for ${device.id}` };
+  return { data, human: `State snapshot for ${data.device}` };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/devices.ts` around lines 83 - 95, Update stateCommand to
avoid resolving the device before withClient; use client.device.id inside its
callback for the data.device value, matching the existing ping command pattern.
Replace the literal 'readers', 'media.active', and 'tokens.history' request
names with their corresponding Methods.* entries.
src/client/config.ts-102-112 (1)

102-112: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Report a malformed config file with the file path.

Line 105 parses the config file without error handling. A truncated or hand-edited config.json makes every CLI command fail with a raw SyntaxError message. classifyError in src/cli/errors.ts maps that to ExitCode.General and the message contains no file path. Wrap the read and parse, and report the path.

🔧 Proposed fix
 export function loadCliConfig(configPath?: string): CliConfig {
   const path = configPath ?? defaultConfigPath();
-  const fileConfig = existsSync(path)
-    ? (JSON.parse(readFileSync(path, 'utf8')) as Partial<CliConfig>)
-    : {};
+  let fileConfig: Partial<CliConfig> = {};
+  if (existsSync(path)) {
+    try {
+      fileConfig = JSON.parse(readFileSync(path, 'utf8')) as Partial<CliConfig>;
+    } catch (error) {
+      const reason = error instanceof Error ? error.message : String(error);
+      throw new Error(`Failed to read config file "${path}": ${reason}`);
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/config.ts` around lines 102 - 112, Update loadCliConfig around the
JSON.parse/readFileSync call to catch malformed config-file errors and report
them with the config path, while preserving the existing configuration fallback
behavior. Use the existing classifyError/error-reporting flow from the CLI error
handling rather than allowing a raw SyntaxError to escape.
src/client/trace.ts-60-68 (1)

60-68: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Skip unparsable trace lines.

readLast throws if any selected line is not complete JSON. An interrupted append or a concurrent truncateSync at line 55 can leave a partial line. The logs trace command in src/cli/commands/logs.ts then fails instead of returning the readable entries. Skip lines that fail to parse.

🔧 Proposed fix
   readLast(count: number): TraceEntry[] {
     if (!existsSync(this.path)) return [];
-    return readFileSync(this.path, 'utf8')
-      .trim()
-      .split('\n')
-      .filter(Boolean)
-      .slice(-count)
-      .map((line) => JSON.parse(line) as TraceEntry);
+    const entries: TraceEntry[] = [];
+    for (const line of readFileSync(this.path, 'utf8').trim().split('\n').filter(Boolean)) {
+      try {
+        entries.push(JSON.parse(line) as TraceEntry);
+      } catch {
+        // Skip a partially written trace line.
+      }
+    }
+    return entries.slice(-count);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/trace.ts` around lines 60 - 68, Update TraceStore.readLast to
parse selected lines defensively, skipping any line that throws during
JSON.parse while preserving all successfully parsed TraceEntry values. Keep the
existing file-reading, filtering, and count behavior unchanged so logs trace
returns readable entries despite partial or invalid lines.
src/cli/errors.ts-54-65 (1)

54-65: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Anchor the fallback patterns to whole words.

The fallback patterns match substrings. /pair/i at line 56 also matches "repair" and "unpaired data". /connect/i at line 62 also matches "disconnected" and "reconnecting". An unrelated error then returns ExitCode.EncryptionRequired or ExitCode.Connection. Scripts consume these exit codes as a contract. Add word boundaries.

🔧 Proposed fix
-  if (/encryption required|not paired|pair/i.test(message)) {
+  if (/encryption required|not paired|\bpair(ing)?\b/i.test(message)) {
     return new CliError(message, ExitCode.EncryptionRequired);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/errors.ts` around lines 54 - 65, Update the encryption and connection
fallback regexes in the error-classification logic to use word boundaries around
standalone terms, especially “pair” and “connect,” so substrings such as
“repair,” “unpaired,” “disconnected,” and “reconnecting” do not match. Preserve
the existing classification order and all other patterns.
src/cli/output.ts-10-15 (1)

10-15: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

--json can print undefined instead of valid JSON.

JSON.stringify(undefined) returns the JavaScript value undefined, not a string. Template interpolation then writes the text undefined to stdout. Core methods that return no result produce this case, for example the pass-through results in src/cli/commands/backup.ts Line 41 and src/cli/commands/tokens.ts Line 20. A machine consumer that parses stdout then fails.

Normalize the value before serialization.

🔧 Proposed fix
 export function printResult(result: CommandResult, options: GlobalOptions): void {
   if (options.json || !result.human) {
     const space = options.pretty === false ? 0 : 2;
-    process.stdout.write(`${JSON.stringify(result.data, null, space)}\n`);
+    process.stdout.write(`${JSON.stringify(result.data ?? null, null, space)}\n`);
     return;
   }
   process.stdout.write(`${result.human}\n`);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/output.ts` around lines 10 - 15, Update printResult to normalize
result.data before JSON.stringify so undefined is converted to a valid JSON
value, such as null. Preserve the existing pretty-print spacing, stdout output,
and return behavior for all other result values.

Source: Coding guidelines

src/cli/commands/ui.ts-23-30 (1)

23-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

ui respond --action select accepts a missing --choice-id.

The handler validates the action name but not the choice. For the select action, pickDefined drops choiceId when the flag is absent, and the request reaches Core without a selection. Validate the pairing locally and fail with ExitCode.Usage.

As per coding guidelines: "Validate required command parameters and add colocated tests for non-trivial mapping."

🔧 Proposed fix
     if (!['dismiss', 'select', 'confirm'].includes(responseAction)) {
       throw new CliError('--action must be dismiss, select, or confirm', ExitCode.Usage);
     }
+    const choiceId = flag(args.flags, 'choice-id');
+    if (responseAction === 'select' && !choiceId) {
+      throw new CliError('--action select requires --choice-id', ExitCode.Usage);
+    }
     const data = await withClient(args.options, (client) =>
       client.request(
         Methods.UIRespond,
-        pickDefined({ id, action: responseAction, choiceId: flag(args.flags, 'choice-id') }),
+        pickDefined({ id, action: responseAction, choiceId }),
       ),
     );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/ui.ts` around lines 23 - 30, Update the UI response
validation before the withClient request to require a non-missing choice-id
whenever responseAction is “select”; throw CliError with ExitCode.Usage when
that pairing is invalid, while preserving other action behavior. Add colocated
tests covering select without choice-id and valid non-select actions.

Source: Coding guidelines

src/cli/commands/watch.ts-27-32 (1)

27-32: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

entries grows without bound in JSONL mode.

In JSONL mode each notification is written to stdout immediately, and Line 40 returns only entries.length. The handler still retains every notification object in memory. A long watch on a busy device then holds notifications that are never read. Keep a counter for JSONL mode.

🔧 Proposed fix
   const entries: unknown[] = [];
+  let streamed = 0;
   client.on('notification', (method, params, deviceId) => {
     if (methods.size > 0 && !methods.has(method)) return;
     const entry = { timestamp: new Date().toISOString(), deviceId, method, params };
-    entries.push(entry);
-    if (args.options.jsonl) process.stdout.write(`${JSON.stringify(entry)}\n`);
+    if (args.options.jsonl) {
+      streamed += 1;
+      process.stdout.write(`${JSON.stringify(entry)}\n`);
+      return;
+    }
+    entries.push(entry);
   });

Then return { data: { notifications: streamed } } at Line 40.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/watch.ts` around lines 27 - 32, Update the notification
handler in the watch command to avoid retaining entries in JSONL mode: keep
writing each entry immediately, but increment a dedicated streamed counter
instead of pushing into entries. Update the command’s return path to report
notifications using that counter, while preserving the existing entries
collection and result behavior for non-JSONL mode.
src/cli/commands/doctor.ts-39-43 (1)

39-43: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

doctor ignores the global --trace option.

withClient in src/cli/commands/common.ts Line 20 passes trace: options.trace ? new TraceWriter() : undefined. This handler omits it. A user who runs zaparoo-cli doctor --trace to collect diagnostics gets no trace JSONL, which is the case where a trace is most useful.

🔧 Proposed fix
+import { TraceWriter } from '../../client/trace.js';
@@
   const client = new ZaparooClient(device, {
     credentials,
     connectTimeoutMs: args.options.timeoutSeconds * 1000,
     requestTimeoutMs: args.options.timeoutSeconds * 1000,
+    trace: args.options.trace ? new TraceWriter() : undefined,
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/doctor.ts` around lines 39 - 43, Update the ZaparooClient
options in the doctor command to honor the global trace setting, matching the
trace handling in withClient from common.ts: create and pass a TraceWriter when
args.options.trace is enabled, otherwise pass undefined.
src/cli/commands/watch.ts-24-25 (1)

24-25: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Bound the watch duration.

Reject seconds values above 2_147_483 before calling setTimeout; larger values are clamped to 1 ms.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/watch.ts` around lines 24 - 25, Update the seconds
validation in the watch command to reject values greater than 2_147_483, in
addition to the existing positive-value check, before the setTimeout call.
Preserve the current CliError usage and usage exit code for invalid durations.
src/cli/commands/systems.ts-16-21 (1)

16-21: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove or remap systems refresh.

The CLI describes this action as refreshing system metadata, but it calls Methods.LaunchersRefresh, which refreshes launcher configuration. Remove the action, or add a registered SystemsRefresh method and use it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/systems.ts` around lines 16 - 21, Update the systems
command’s refresh branch to avoid calling Methods.LaunchersRefresh: either
remove the refresh action and its CLI registration, or register a SystemsRefresh
method and invoke that method from the action === 'refresh' handler.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 16: Update the checkout steps in .github/workflows/ci.yml at lines 16-16
and .github/workflows/release.yml at lines 14-14 to set persist-credentials to
false, preserving the existing actions/checkout configuration.

In @.github/workflows/release.yml:
- Around line 24-26: Update the release workflow’s version-check block to assign
github.event.release.tag_name to a RELEASE_TAG environment variable, then use
quoted shell references to RELEASE_TAG for both the comparison and error
message. Remove direct interpolation of the tag into shell expressions while
preserving the existing mismatch validation.

In `@scripts/audit-user-api.mjs`:
- Around line 34-39: Replace the backtick-based missingScopes check with
validation against authoritative structured scope metadata, such as each
operation’s x-required-scope field, and ensure the audit does not infer scopes
from descriptive text. Update the relevant logic around EXPECTED_SCOPES and
discoveredPaths while preserving the existing non-GET path validation.

In `@scripts/validate-skills.mjs`:
- Around line 25-39: Update validateSkill to detect a skill-local build
directory and append a validation error when it exists, alongside the existing
SKILL.md checks. Use the directory path already available in validateSkill and
preserve the current validation behavior for other checks.

In `@skills/zaparoo-library/SKILL.md`:
- Line 14: Remove the explicit-request exception from
skills/zaparoo-library/SKILL.md line 14 so confirmation is always required
before media launch, control, or stop commands. Apply the corresponding change
in skills/zaparoo-nfc/SKILL.md line 14 so confirmation remains required before
NFC writes, mapping changes, launch confirmation, or media launch, even when
explicitly requested.

In `@src/cli/commands/auth.ts`:
- Around line 11-15: Update the claim branch in the command handler to accept
only the `-` sentinel for `--token`; when the option is missing or equals `-`,
obtain the token via `readSecret`, and reject any other provided value. Continue
passing the resolved token through the existing `request` call to
`Methods.SettingsAuthClaim`, preserving its redacted trace handling.

In `@src/cli/commands/backup.ts`:
- Around line 17-28: Add a shared requireConfirmation(args, description) helper
in src/cli/commands/common.ts that requires an explicit --yes flag, then invoke
it before dispatching the state-changing requests in src/cli/commands/backup.ts
lines 17-28 for delete, restore, and remote-restore, src/cli/commands/input.ts
lines 7-21 for keyboard and gamepad input, and src/cli/commands/playtime.ts
lines 16-29 for playtime limits update; leave non-state-changing commands
unchanged.

In `@src/cli/commands/pair.ts`:
- Around line 96-105: Update the forget case to attempt store.deleteCredentials
for device.id and every alias without skipping later entries after a successful
deletion. Combine the individual deletion results into deleted so the response
accurately reflects whether any credentials were removed.

In `@src/cli/secret.ts`:
- Around line 26-59: Update readSecret’s Promise handling to register end,
close, and error listeners on input, and ensure finish removes all data and
stream listeners before restoring terminal state. Settle the promise when the
stream ends or closes, and reject it with the emitted error on error, while
preserving the existing data, cancellation, and length-limit behavior.

In `@src/client/client.ts`:
- Around line 281-290: Update decryptIncoming to reject any frame without an
encrypted e field when this.encryptedSession is active, while preserving
decryption for valid encrypted frames and plaintext handling before session
establishment. Ensure plaintext frames cannot be accepted once the encrypted
session exists.

In `@src/client/config.ts`:
- Around line 90-100: Update parseDeviceList so apiKeys preserves the original
comma-separated positions while treating empty entries as missing values. Remove
the filter(Boolean) behavior from the keys mapping, keep trimming each entry,
and ensure parseDevice receives apiKeys[index] for the corresponding host.

In `@src/client/redact.ts`:
- Around line 1-15: Update SECRET_KEYS and URL_KEYS in redact so their patterns
accept an optional trailing “s”, covering plural secret and URL key names. In
redact’s array handling, pass the current key to each recursive redact call so
key-based rules remain effective for array values while preserving object-entry
behavior.

In `@src/client/resolver.ts`:
- Around line 18-25: Update the configured-device merge in the options.device
branch of the resolver so fields omitted by the user are preserved from
configured, matching the existing apiKey override behavior. In particular, do
not let parseDevice’s default scheme or undefined apiPath overwrite configured
values; only apply parsed values for fields explicitly supplied by the user,
while retaining parsed values for an unconfigured device.

In `@src/crypto/pairing.ts`:
- Around line 192-205: The unauthenticated pairing response fields are cast
without runtime validation, causing raw internal errors and unsafe HMAC
comparison. In src/crypto/pairing.ts lines 192-205, validate that
finishResult.authToken, finishResult.clientId, and finishResult.confirm are
strings, and verify serverHmac.length matches expectedServerHmac.length before
timingSafeEqual. In src/crypto/pairing.ts lines 152-153, validate that
startResult.session and startResult.pake are strings before decoding pake; use
the pairing error path for invalid responses.
- Around line 152-153: Validate the parsed `/api/pair/start` response before
using it in the pairing flow around `startResult` and `msgB`. Confirm that the
body is an object containing non-empty string `session` and `pake` fields, and
convert invalid responses into the pairing failure error path rather than
passing an unchecked value to `Buffer.from`; preserve normal processing for
valid responses.

In `@src/crypto/pake.ts`:
- Around line 57-76: Update the PakeClient constructor’s randomBytes handling to
store a defensive copy in this.alpha rather than the caller-provided Uint8Array
reference. Preserve the existing generated-key path when randomBytes is absent
and keep update()’s zeroization behavior unchanged.

---

Minor comments:
In `@skills/zaparoo-online/SKILL.md`:
- Line 43: Update the 403 description in the relevant instruction to say the key
lacks the required scope or the account is suspended, replacing “account is
unavailable.” Preserve the existing guidance not to request broader scope unless
the task requires it.

In `@src/cli/commands/devices.ts`:
- Around line 83-95: Update stateCommand to avoid resolving the device before
withClient; use client.device.id inside its callback for the data.device value,
matching the existing ping command pattern. Replace the literal 'readers',
'media.active', and 'tokens.history' request names with their corresponding
Methods.* entries.

In `@src/cli/commands/doctor.ts`:
- Around line 39-43: Update the ZaparooClient options in the doctor command to
honor the global trace setting, matching the trace handling in withClient from
common.ts: create and pass a TraceWriter when args.options.trace is enabled,
otherwise pass undefined.

In `@src/cli/commands/logs.ts`:
- Around line 19-26: Move the `flag(args.flags, 'output')` lookup and
missing-output `CliError` validation before the `withClient` call in the `action
=== 'download'` branch, then perform `Methods.SettingsLogsDownload` and pass the
validated output to `writeBase64Output`. Match the validation order used by the
admin command.

In `@src/cli/commands/online.test.ts`:
- Around line 151-171: Update the existing afterEach block in the online command
tests to call vi.restoreAllMocks(), ensuring the process.stdout.write spy
created in the watch test is restored even when assertions fail. Remove the
test-local write.mockRestore() if appropriate to avoid redundant cleanup.

In `@src/cli/commands/readers.ts`:
- Around line 13-21: Update the readers write case to require explicit
confirmation before calling request for Methods.ReadersWrite: accept the
existing force boolean flag (or an interactive confirmation for interactive
sessions), and otherwise fail with a usage error. Preserve the current text
validation and request arguments after confirmation succeeds.

In `@src/cli/commands/screenshot.ts`:
- Around line 9-15: Move the required --output validation to the beginning of
screenshotCommand, before withClient initiates the screenshot request; preserve
the existing CliError and Usage exit behavior, then use the validated output
value for writeBase64Output.

In `@src/cli/commands/systems.ts`:
- Around line 16-21: Update the systems command’s refresh branch to avoid
calling Methods.LaunchersRefresh: either remove the refresh action and its CLI
registration, or register a SystemsRefresh method and invoke that method from
the action === 'refresh' handler.

In `@src/cli/commands/ui.ts`:
- Around line 23-30: Update the UI response validation before the withClient
request to require a non-missing choice-id whenever responseAction is “select”;
throw CliError with ExitCode.Usage when that pairing is invalid, while
preserving other action behavior. Add colocated tests covering select without
choice-id and valid non-select actions.

In `@src/cli/commands/watch.ts`:
- Around line 27-32: Update the notification handler in the watch command to
avoid retaining entries in JSONL mode: keep writing each entry immediately, but
increment a dedicated streamed counter instead of pushing into entries. Update
the command’s return path to report notifications using that counter, while
preserving the existing entries collection and result behavior for non-JSONL
mode.
- Around line 24-25: Update the seconds validation in the watch command to
reject values greater than 2_147_483, in addition to the existing positive-value
check, before the setTimeout call. Preserve the current CliError usage and usage
exit code for invalid durations.

In `@src/cli/errors.ts`:
- Around line 54-65: Update the encryption and connection fallback regexes in
the error-classification logic to use word boundaries around standalone terms,
especially “pair” and “connect,” so substrings such as “repair,” “unpaired,”
“disconnected,” and “reconnecting” do not match. Preserve the existing
classification order and all other patterns.

In `@src/cli/output.ts`:
- Around line 10-15: Update printResult to normalize result.data before
JSON.stringify so undefined is converted to a valid JSON value, such as null.
Preserve the existing pretty-print spacing, stdout output, and return behavior
for all other result values.

In `@src/client/config.ts`:
- Around line 102-112: Update loadCliConfig around the JSON.parse/readFileSync
call to catch malformed config-file errors and report them with the config path,
while preserving the existing configuration fallback behavior. Use the existing
classifyError/error-reporting flow from the CLI error handling rather than
allowing a raw SyntaxError to escape.

In `@src/client/trace.ts`:
- Around line 60-68: Update TraceStore.readLast to parse selected lines
defensively, skipping any line that throws during JSON.parse while preserving
all successfully parsed TraceEntry values. Keep the existing file-reading,
filtering, and count behavior unchanged so logs trace returns readable entries
despite partial or invalid lines.

In `@src/crypto/pairing.ts`:
- Around line 79-90: Sanitize the serverMessage handling in pairingError before
returning it: strip control characters, including ANSI escape sequences, and cap
the resulting message to a reasonable maximum length. Apply the sanitized
bounded value only when selecting the server-supplied message, while preserving
the existing status-based and fallback error behavior.

In `@src/online/client.test.ts`:
- Around line 90-98: Update the “redacts keys from error bodies” test around
OnlineClient.get so the rejected error assertion requires both the presence of
“[REDACTED]” and the absence of “super-secret” on the same OnlineApiError,
preserving the existing rejection check.

---

Nitpick comments:
In `@src/cli/args.ts`:
- Around line 136-142: Update takeValue to treat only an undefined next argument
as missing, while continuing to reject values beginning with “--”. Preserve
empty-string values so separated and inline option forms behave consistently.
- Around line 208-211: Update the switch cases around the trace option so help
no longer shares the trace-handling body: keep help’s existing behavior separate
and handle trace alone by preserving or enabling options.trace without using the
name comparison.

In `@src/cli/commands/admin.ts`:
- Around line 18-27: Extract the shared SettingsLogsDownload request and
writeBase64Output handling from the admin logs-download case and the logs
download dispatcher into one helper. Have both dispatchers call that helper,
while preserving the required --output validation and ensuring both paths use
the same validation order.

In `@src/cli/commands/backup.ts`:
- Around line 40-42: The request helper is duplicated across three command
handlers. Add the shared request implementation to src/cli/commands/common.ts,
then remove the local helper and import the shared helper in
src/cli/commands/backup.ts lines 40-42, src/cli/commands/tokens.ts lines 19-22,
and src/cli/commands/playtime.ts lines 34-36; preserve the existing withClient
and client.request behavior.

In `@src/cli/commands/clients.ts`:
- Around line 20-25: Update the `pair-begin` branch in the clients command
handler to validate the `role` argument against the same `member` and `admin`
values accepted by `pair.ts`, rejecting invalid values before calling `request`.
Reuse the existing validation behavior or shared symbol so both entry points
fail consistently, and add colocated tests covering invalid-role rejection and
the existing valid mappings.

In `@src/cli/commands/commands.test.ts`:
- Around line 36-62: Add colocated tests in the command-to-RPC mapping suite for
runCommand with --unsafe, screenshotCommand when --output is missing, and a
representative CliError usage path. Assert the unsafe option maps correctly,
missing required output rejects with the expected usage error, and each path
verifies the relevant RPC request or confirms no request is sent.

In `@src/cli/commands/devices.ts`:
- Around line 37-44: Update the ping handler in the `withClient` callback to
replace the literal `version` and `health` request names with the corresponding
entries from the `Methods` registry, matching the established usage in other
command handlers. Keep the existing fallback and health error handling
unchanged.

In `@src/cli/commands/doctor.ts`:
- Around line 120-143: Define a shared union type for all supported doctor error
kinds, then use it for DoctorCheck.kind and the return type of errorKind. Update
checkFailure and the kind extraction logic to narrow unknown values to that
union, so doctorExitCode’s string comparisons are compile-time checked and
unsupported kinds cannot silently pass through.

In `@src/cli/commands/inbox.ts`:
- Around line 18-19: Update the `case 'clear'` branch in the inbox command to
require explicit confirmation before calling `request(args, Methods.InboxClear).
Accept a `--yes` flag, or prompt interactively when stdin is a TTY; otherwise
abort without clearing, preserving non-interactive safety for agent callers.

In `@src/cli/commands/input.ts`:
- Line 1: Use the authoritative Methods registry from ../../api/methods.js in
the handlers at src/cli/commands/input.ts:1, src/cli/commands/systems.ts:1, and
src/cli/commands/tokens.ts:1; remove any competing registry re-export from
src/types.ts if present, while keeping src/api/methods.ts synchronized with
registered Core methods.

In `@src/cli/commands/media.ts`:
- Around line 216-232: Move the shared rawRequest and request helpers from the
media command module into common.ts, preserving the generic raw request behavior
and pickDefined parameter handling. Update media.ts, admin.ts, and readers.ts to
import and use the common helpers, removing their duplicate local definitions.

In `@src/cli/commands/online.ts`:
- Around line 317-318: Update the existing-output hashing near createContext and
currentHash to use a streaming or chunked file read, incrementally updating the
hash instead of calling readFileSync on the entire backup. Preserve the
existsSync check and undefined result when outputPath is absent, and keep the
resulting digest equivalent to hashing the complete file.
- Around line 274-279: Update the online request handler around createContext
and the URL construction to import and use ONLINE_API_ORIGIN instead of the
hardcoded origin, and convert invalid URL inputs such as “http://” into the
command’s established CliError usage-error path rather than allowing a raw
TypeError to escape.
- Around line 366-404: Update the sleep interval in watchActiveSessions to honor
the server-provided retryAfter value when context.client.get returns a 429,
rather than relying only on response.pollInterval. Use retryAfter as the backoff
for rate-limited responses while preserving the existing poll interval and
jitter behavior otherwise, and continue allowing persistent client errors to
propagate and terminate the loop.

In `@src/cli/commands/pair.ts`:
- Around line 14-15: Update the pair command’s validation error flow around
requestedAction and action so invoking pair start without --pin reports the
user-typed start action instead of complete, or add explicit help text
documenting start as an alias for complete. Preserve the existing alias behavior
while ensuring the user-facing guidance is unambiguous.
- Around line 55-58: Update the `complete` case in the pair command so that when
`--pin` is absent, it obtains the PIN through the existing `src/cli/secret.ts`
prompt/stdin mechanism instead of reading `args.positionals[2]`; retain the
usage error when no PIN is provided or received, and leave the existing `--pin`
behavior unchanged.

In `@src/cli/commands/settings.ts`:
- Around line 66-83: Move the parseJson and parseJsonObject helpers out of the
settings command into a shared module such as common.ts or args.ts, preserving
their current validation and CliError behavior. Update settings.ts and
profiles.ts to import these helpers from the shared module, leaving command
handlers independent of one another.

In `@src/cli/commands/update.ts`:
- Around line 7-13: Update updateCommand so the Methods.UpdateApply path
requires explicit user confirmation, supporting a --yes override for
non-interactive or intentional callers before invoking client.request. Keep the
check action unchanged, and abort with the existing CLI error/usage mechanism
when confirmation is not provided.

In `@src/cli/files.ts`:
- Around line 34-50: Update writeBytesOutput to generate a randomized temporary
suffix in addition to process.pid, and pass the exclusive-create wx flag to
writeFileSync so pre-existing files or symlinks cause the write to fail.
Preserve the existing cleanup and rename behavior.
- Around line 19-31: Update the decoded payload handling near writeBytesOutput
to compare bytes.length with response.size when response.size is present, and
reject mismatches before writing the output. Preserve the existing behavior when
size is absent and continue returning the current metadata for valid payloads.

In `@src/cli/index.test.ts`:
- Around line 6-9: Restore the PACKAGE_VERSION global stub after the test suite
by adding an afterAll cleanup that calls vi.unstubAllGlobals() alongside the
existing beforeAll setup in the suite containing the dynamic index.js import. Do
not change the stub value or import behavior.

In `@src/cli/index.ts`:
- Around line 246-266: Update main and run so the already-created ParsedArgs
from parseCliArgs is passed into run instead of parsing argv again. Export an
overload or compatible run signature that accepts ParsedArgs while preserving
the existing argv form for tests, and ensure execution reuses the same parsed
object and validation result.

In `@src/cli/output.test.ts`:
- Around line 38-62: Move the entire “error classification” describe block from
output.test.ts into errors.test.ts alongside classifyError. Preserve all
existing test cases and assertions, and remove the duplicated block from
output.test.ts.

In `@src/cli/secret.test.ts`:
- Around line 5-19: Extend the readSecret tests with a fake TTY input exposing
isTTY, setRawMode, isRaw, and isPaused, then emit data chunks to exercise
raw-mode input handling. Cover cancellation with \u0003, backspace editing, the
maximum-length limit, and restoration of raw mode, while keeping the existing
non-TTY test unchanged.

In `@src/client/client.test.ts`:
- Around line 216-236: Add a test alongside the existing connection rejection
tests that starts ZaparooClient.connect(), emits the socket’s
unexpected-response event with statusCode 401, and asserts the connection
promise rejects with kind 'api-auth'. Use the existing client, socket, and timer
setup patterns without changing production behavior.

In `@src/client/resolver.ts`:
- Around line 6-14: Update scanDevices so the timeout wait and device collection
execute within a try block, with discovery.stop() in a finally block that always
runs when the wait or discovery flow rejects; preserve returning the collected
devices after successful completion.

In `@src/client/trace.ts`:
- Around line 16-28: Update SENSITIVE_REQUEST_METHODS and SENSITIVE_DATA_METHODS
in trace.ts to use the corresponding Methods enum members from src/types.ts
instead of string literals, preserving the existing set membership. Ensure every
referenced method is type-checked so renaming a Methods member causes a build
failure rather than disabling trace redaction.

In `@src/crypto/pairing.test.ts`:
- Around line 108-132: Remove the unused fetchMock definition and its initial
vi.stubGlobal call from the 401 test; retain fetchMock401 and the existing
performPairing assertion so the test contains only the effective mock setup.
- Around line 156-164: The 429 retry test incurs real retry delays, slowing the
suite. Update the test around performPairing to use fake timers, advance them
enough to complete all fetchWithRetry retries before asserting the rejection,
and restore real timers in an afterEach hook.
- Around line 39-41: Update the afterEach cleanup in pairing tests to call
vi.unstubAllGlobals() alongside vi.restoreAllMocks(), ensuring global fetch
stubs installed by vi.stubGlobal are removed after every test.

In `@src/crypto/storage.test.ts`:
- Around line 157-203: Add three focused tests covering CredentialStore.load
rejection branches: a credentials file with version greater than 3 must throw
“Unsupported credentials file version,” a device entry with an invalid
pairingKey must throw “Invalid credentials entry for <deviceId>,” and an online
API key not matching the zpk1_ format must throw “Invalid Online User API
credentials entry.” Follow the existing tempPath, paths, writeFileSync, and
assertion patterns in the surrounding tests.

In `@src/crypto/storage.ts`:
- Around line 148-212: Protect each mutating load–modify–write sequence with an
exclusive lock file created using wx, covering the full operation from load
through write. Reuse the storage class’s mutation entry points and ensure the
lock is always removed in a finally block, including when load or write fails,
so concurrent processes cannot overwrite each other’s credential changes.

In `@src/discovery/mdns.ts`:
- Line 58: Extract the repeated IPv6-aware host/port formatting from the
discovery and removal paths into one private helper, then use that helper
wherever the IDs are built near the existing declarations. Preserve the current
bracketed-IPv6 and host:port output exactly so discovered and removed IDs
continue to match.
- Around line 2-3: Update the type imports in the mDNS implementation to use the
package-root value exports for Bonjour, Browser, and Service, and derive their
instance types with InstanceType<typeof ...> wherever they are used as types.
Remove the deep direct type imports from bonjour-service/dist/lib/bonjour.js
while preserving the existing runtime constructors and behavior.

In `@src/online/contract.ts`:
- Around line 15-21: Update the CLI path definitions in the online command flow
to derive or validate them against the canonical OnlineOperations contract,
preventing independent path lists from drifting. Prefer reusing OnlineOperations
when constructing request paths; otherwise add coverage that asserts every CLI
path template, including /v1/play-sessions/summary, exists in the contract.

In `@src/online/pagination.ts`:
- Around line 13-18: Separate the configurable default from the validation
ceiling in the max-pages handling: declare a MAX_ALLOWED_PAGES constant and use
it for the upper-bound check and error message, while keeping DEFAULT_MAX_PAGES
only as the default value.

In `@src/version.ts`:
- Around line 1-3: Update src/cli/index.ts to import and use packageVersion from
version.ts, removing its duplicate PACKAGE_VERSION declaration and any local
version fallback. Preserve the existing CLI version behavior for both injected
build versions and direct module imports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 10089d21-7f91-4e96-955e-a369a81d8856

📥 Commits

Reviewing files that changed from the base of the PR and between 70fa63a and ea5353f.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (150)
  • .agents/skills
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .gitignore
  • AGENTS.md
  • README.md
  • SECURITY.md
  • docs/cli-output.md
  • docs/skill-scenarios.md
  • package.json
  • scripts/audit-core-api.mjs
  • scripts/audit-user-api.mjs
  • scripts/smoke-packed-package.mjs
  • scripts/validate-skills.mjs
  • skills/zaparoo-artifacts/SKILL.md
  • skills/zaparoo-artifacts/references/database-safety.md
  • skills/zaparoo-artifacts/references/platform-paths.md
  • skills/zaparoo-development/SKILL.md
  • skills/zaparoo-development/references/integration.md
  • skills/zaparoo-library/SKILL.md
  • skills/zaparoo-nfc/SKILL.md
  • skills/zaparoo-online/SKILL.md
  • skills/zaparoo-online/references/user-api.md
  • skills/zaparoo-troubleshooting/SKILL.md
  • skills/zaparoo-troubleshooting/references/cli.md
  • skills/zaparoo-zapscript/SKILL.md
  • skills/zaparoo-zapscript/references/zapscript.md
  • src/api/baseline.ts
  • src/api/methods.test.ts
  • src/api/methods.ts
  • src/cli/args.test.ts
  • src/cli/args.ts
  • src/cli/commands/admin.ts
  • src/cli/commands/auth.ts
  • src/cli/commands/backup.ts
  • src/cli/commands/clients.ts
  • src/cli/commands/commands.test.ts
  • src/cli/commands/common.ts
  • src/cli/commands/devices.ts
  • src/cli/commands/doctor.ts
  • src/cli/commands/inbox.ts
  • src/cli/commands/input.ts
  • src/cli/commands/logs.ts
  • src/cli/commands/mappings.ts
  • src/cli/commands/media.ts
  • src/cli/commands/online.test.ts
  • src/cli/commands/online.ts
  • src/cli/commands/pair.ts
  • src/cli/commands/playtime.ts
  • src/cli/commands/profiles.ts
  • src/cli/commands/readers.ts
  • src/cli/commands/rpc.ts
  • src/cli/commands/run.ts
  • src/cli/commands/screenshot.ts
  • src/cli/commands/settings.ts
  • src/cli/commands/systems.ts
  • src/cli/commands/tokens.ts
  • src/cli/commands/ui.ts
  • src/cli/commands/update.ts
  • src/cli/commands/watch.ts
  • src/cli/errors.test.ts
  • src/cli/errors.ts
  • src/cli/files.test.ts
  • src/cli/files.ts
  • src/cli/index.test.ts
  • src/cli/index.ts
  • src/cli/output.test.ts
  • src/cli/output.ts
  • src/cli/secret.test.ts
  • src/cli/secret.ts
  • src/client/client.test.ts
  • src/client/client.ts
  • src/client/config.test.ts
  • src/client/config.ts
  • src/client/endpoint.ts
  • src/client/errors.ts
  • src/client/redact.ts
  • src/client/resolver.test.ts
  • src/client/resolver.ts
  • src/client/trace.test.ts
  • src/client/trace.ts
  • src/config.test.ts
  • src/config.ts
  • src/connection/device.test.ts
  • src/connection/device.ts
  • src/connection/manager.test.ts
  • src/connection/manager.ts
  • src/connection/trace.test.ts
  • src/connection/trace.ts
  • src/connection/types.ts
  • src/crypto/fixtures/core-v2.16-pake.json
  • src/crypto/index.ts
  • src/crypto/pairing.test.ts
  • src/crypto/pairing.ts
  • src/crypto/pake.test.ts
  • src/crypto/pake.ts
  • src/crypto/session.test.ts
  • src/crypto/session.ts
  • src/crypto/storage.test.ts
  • src/crypto/storage.ts
  • src/discovery/mdns.test.ts
  • src/discovery/mdns.ts
  • src/index.ts
  • src/notifications/buffer.test.ts
  • src/notifications/buffer.ts
  • src/notifications/handler.test.ts
  • src/notifications/handler.ts
  • src/notifications/state.test.ts
  • src/notifications/state.ts
  • src/online/client.test.ts
  • src/online/client.ts
  • src/online/contract.test.ts
  • src/online/contract.ts
  • src/online/credentials.test.ts
  • src/online/credentials.ts
  • src/online/errors.ts
  • src/online/pagination.test.ts
  • src/online/pagination.ts
  • src/prompts/index.ts
  • src/resources/device-state.ts
  • src/resources/zapscript-ref.ts
  • src/server.ts
  • src/tools/admin-manage.ts
  • src/tools/admin.ts
  • src/tools/devices.ts
  • src/tools/helpers.test.ts
  • src/tools/helpers.ts
  • src/tools/inbox.ts
  • src/tools/index.test.ts
  • src/tools/index.ts
  • src/tools/input.ts
  • src/tools/logs.test.ts
  • src/tools/logs.ts
  • src/tools/mappings.ts
  • src/tools/media-control.ts
  • src/tools/media-index.ts
  • src/tools/media.ts
  • src/tools/notifications.test.ts
  • src/tools/notifications.ts
  • src/tools/readers-write.ts
  • src/tools/readers.ts
  • src/tools/run.ts
  • src/tools/screenshot.ts
  • src/tools/settings-update.ts
  • src/tools/settings.ts
  • src/tools/stop.ts
  • src/tools/systems.ts
  • src/tools/tokens.ts
  • src/types.ts
  • src/version.ts
💤 Files with no reviewable changes (45)
  • src/notifications/buffer.test.ts
  • src/tools/admin-manage.ts
  • src/tools/run.ts
  • src/config.ts
  • src/prompts/index.ts
  • src/tools/readers-write.ts
  • src/tools/screenshot.ts
  • src/connection/types.ts
  • src/notifications/handler.test.ts
  • src/notifications/handler.ts
  • src/tools/systems.ts
  • src/tools/input.ts
  • src/connection/device.test.ts
  • src/config.test.ts
  • src/resources/zapscript-ref.ts
  • src/connection/trace.test.ts
  • src/tools/notifications.test.ts
  • src/server.ts
  • src/resources/device-state.ts
  • src/notifications/state.ts
  • src/tools/helpers.test.ts
  • src/tools/inbox.ts
  • src/tools/stop.ts
  • src/connection/manager.test.ts
  • src/tools/mappings.ts
  • src/tools/index.test.ts
  • src/tools/notifications.ts
  • src/tools/media-control.ts
  • src/tools/settings-update.ts
  • src/tools/admin.ts
  • src/notifications/buffer.ts
  • src/tools/logs.test.ts
  • src/connection/trace.ts
  • src/tools/logs.ts
  • src/tools/tokens.ts
  • src/tools/readers.ts
  • src/connection/manager.ts
  • src/tools/settings.ts
  • src/tools/media-index.ts
  • src/tools/helpers.ts
  • src/tools/devices.ts
  • src/tools/media.ts
  • src/notifications/state.test.ts
  • src/tools/index.ts
  • src/connection/device.ts

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread scripts/audit-user-api.mjs Outdated
Comment thread scripts/validate-skills.mjs
Comment thread skills/zaparoo-library/SKILL.md Outdated
Comment thread src/client/redact.ts Outdated
Comment thread src/client/resolver.ts
Comment thread src/crypto/pairing.ts Outdated
Comment thread src/crypto/pairing.ts Outdated
Comment thread src/crypto/pake.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/audit-user-api.mjs`:
- Around line 57-60: Update the nonGetPaths filter to recognize head, options,
and trace operations in addition to post, put, patch, and delete. Ensure paths
containing any non-GET method are reported while preserving GET-only paths,
preferably by parsing each path item’s declared methods before filtering.
- Around line 86-90: Update operationBlock to end at the next same-indentation
path or top-level section, rather than only searching for the next “/v1” marker.
Ensure the final path block cannot extend into components or capture later
six-space x-required-scope entries, while preserving the existing slice behavior
for valid operation blocks.
- Around line 47-56: The scope audit currently treats an empty structuredScopes
collection as success. Update the scopeMetadataAvailable handling in the scope
metadata validation to fail when EXPECTED_SCOPE_BY_PATH or EXPECTED_SCOPES
require mappings, or explicitly report the audit as unsupported when the
authoritative document defines no x-required-scope entries; do not allow an
empty structuredScopes result to pass silently.

In `@skills/zaparoo-online/SKILL.md`:
- Line 43: Update the 403 guidance in the API error-handling section to state
that it means access denied, without attributing it to account suspension.
Instruct readers to use the documented error reason to identify the cause before
changing requested scopes.

In `@src/client/client.test.ts`:
- Around line 133-138: Update the onUnexpectedResponse handler to call
ws.terminate() when a WebSocket upgrade fails, ensuring the underlying HTTP
request is aborted. Extend the 401 authentication test around client.connect()
to assert that socket.terminate was invoked.

In `@src/crypto/storage.ts`:
- Around line 203-218: Update mutate() to inspect the existing lock file with
statSync and reclaim it when its age exceeds a short stale-lock threshold before
retrying acquisition; preserve exclusive creation for active locks and normal
cleanup through the existing finally block. Add statSync to the node:fs imports
and ensure active, non-stale locks still fail rather than being removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: af1419b8-9b76-4db9-9515-5eb481229f12

📥 Commits

Reviewing files that changed from the base of the PR and between ea5353f and cc3b8e9.

📒 Files selected for processing (67)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • scripts/audit-user-api.mjs
  • scripts/validate-skills.mjs
  • skills/zaparoo-library/SKILL.md
  • skills/zaparoo-nfc/SKILL.md
  • skills/zaparoo-online/SKILL.md
  • src/cli/args.test.ts
  • src/cli/args.ts
  • src/cli/commands/admin.ts
  • src/cli/commands/auth.ts
  • src/cli/commands/backup.ts
  • src/cli/commands/clients.ts
  • src/cli/commands/commands.test.ts
  • src/cli/commands/common.ts
  • src/cli/commands/devices.ts
  • src/cli/commands/doctor.ts
  • src/cli/commands/inbox.ts
  • src/cli/commands/input.ts
  • src/cli/commands/logs.ts
  • src/cli/commands/mappings.ts
  • src/cli/commands/media.ts
  • src/cli/commands/online.test.ts
  • src/cli/commands/online.ts
  • src/cli/commands/pair.ts
  • src/cli/commands/playtime.ts
  • src/cli/commands/profiles.ts
  • src/cli/commands/readers.ts
  • src/cli/commands/run.ts
  • src/cli/commands/screenshot.ts
  • src/cli/commands/settings.ts
  • src/cli/commands/systems.ts
  • src/cli/commands/tokens.ts
  • src/cli/commands/ui.ts
  • src/cli/commands/update.ts
  • src/cli/commands/watch.ts
  • src/cli/errors.test.ts
  • src/cli/errors.ts
  • src/cli/files.test.ts
  • src/cli/files.ts
  • src/cli/index.test.ts
  • src/cli/index.ts
  • src/cli/output.test.ts
  • src/cli/output.ts
  • src/cli/secret.test.ts
  • src/cli/secret.ts
  • src/client/client.test.ts
  • src/client/client.ts
  • src/client/config.test.ts
  • src/client/config.ts
  • src/client/redact.ts
  • src/client/resolver.test.ts
  • src/client/resolver.ts
  • src/client/trace.test.ts
  • src/client/trace.ts
  • src/crypto/pairing.test.ts
  • src/crypto/pairing.ts
  • src/crypto/pake.test.ts
  • src/crypto/pake.ts
  • src/crypto/storage.test.ts
  • src/crypto/storage.ts
  • src/discovery/mdns.ts
  • src/online/client.test.ts
  • src/online/contract.test.ts
  • src/online/contract.ts
  • src/online/pagination.ts
  • src/types.ts
💤 Files with no reviewable changes (1)
  • src/types.ts
🚧 Files skipped from review as they are similar to previous changes (38)
  • src/cli/commands/run.ts
  • src/online/contract.test.ts
  • src/cli/commands/screenshot.ts
  • src/cli/commands/update.ts
  • src/cli/index.test.ts
  • src/cli/commands/clients.ts
  • src/cli/commands/logs.ts
  • src/cli/commands/inbox.ts
  • src/cli/commands/mappings.ts
  • src/client/resolver.test.ts
  • src/cli/commands/backup.ts
  • src/cli/commands/profiles.ts
  • src/cli/commands/ui.ts
  • src/online/pagination.ts
  • src/cli/index.ts
  • src/client/trace.ts
  • src/cli/files.ts
  • src/cli/secret.ts
  • src/client/config.test.ts
  • src/cli/commands/pair.ts
  • src/cli/errors.ts
  • src/discovery/mdns.ts
  • src/cli/commands/devices.ts
  • src/crypto/pake.ts
  • .github/workflows/ci.yml
  • src/cli/commands/watch.ts
  • src/crypto/pairing.ts
  • src/cli/commands/readers.ts
  • src/cli/commands/doctor.ts
  • src/cli/output.ts
  • src/cli/commands/media.ts
  • .github/workflows/release.yml
  • src/cli/commands/admin.ts
  • src/client/client.ts
  • scripts/validate-skills.mjs
  • src/cli/commands/online.ts
  • src/cli/commands/auth.ts
  • src/cli/args.ts

Comment thread scripts/audit-user-api.mjs Outdated
Comment thread scripts/audit-user-api.mjs
Comment thread scripts/audit-user-api.mjs
Comment thread skills/zaparoo-online/SKILL.md Outdated
Comment thread src/client/client.test.ts
Comment thread src/crypto/storage.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
skills/zaparoo-online/SKILL.md (1)

14-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Document the local credential contract.

ZAPAROO_ONLINE_USER_API_KEY overrides the saved key. online auth set stores the key without returning it. online auth status --json returns configuration metadata only. online auth forget removes only the saved key. These local operations use no read:* scope; the six scopes apply only to API data requests. State these rules and retain the key-handling restrictions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-online/SKILL.md` around lines 14 - 21, Update the “Protect
account access” section to document the local credential contract: state that
ZAPAROO_ONLINE_USER_API_KEY overrides the saved key, online auth set stores
without returning it, online auth status --json exposes metadata only, and
online auth forget removes only the saved key. Clarify that these local
operations require no read:* scope, while the six scopes apply only to API data
requests, and retain all existing key-handling restrictions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@skills/zaparoo-online/SKILL.md`:
- Around line 14-21: Update the “Protect account access” section to document the
local credential contract: state that ZAPAROO_ONLINE_USER_API_KEY overrides the
saved key, online auth set stores without returning it, online auth status
--json exposes metadata only, and online auth forget removes only the saved key.
Clarify that these local operations require no read:* scope, while the six
scopes apply only to API data requests, and retain all existing key-handling
restrictions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ee5f5c51-b4db-4602-8f60-30f69fae1923

📥 Commits

Reviewing files that changed from the base of the PR and between cc3b8e9 and 103a1cb.

📒 Files selected for processing (6)
  • scripts/audit-user-api.mjs
  • skills/zaparoo-online/SKILL.md
  • src/client/client.test.ts
  • src/client/client.ts
  • src/crypto/storage.test.ts
  • src/crypto/storage.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • scripts/audit-user-api.mjs
  • src/crypto/storage.test.ts
  • src/client/client.test.ts
  • src/crypto/storage.ts
  • src/client/client.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (8)
src/cli/commands/capabilities.ts (2)

19-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pass a thunk instead of a started promise to probe.

probe currently receives an already-started promise, so each call site must append .then(() => undefined). A thunk removes that boilerplate and keeps rejection handling inside probe.

♻️ Proposed refactor
-    const probes = await Promise.all([
-      probe(
-        client.request('health').then(() => undefined),
-        'health',
-      ),
-      probe(
-        client.request('clients.current').then(() => undefined),
-        'clients.current',
-      ),
-    ]);
+    const probes = await Promise.all([
+      probe(() => client.request('health'), 'health'),
+      probe(() => client.request('clients.current'), 'clients.current'),
+    ]);
-async function probe(operation: Promise<void>, method: string): Promise<ProbeResult> {
+async function probe(operation: () => Promise<unknown>, method: string): Promise<ProbeResult> {
   try {
-    await operation;
+    await operation();
     return { method, supported: true };

Also applies to: 61-71

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/capabilities.ts` around lines 19 - 28, Update the probe call
sites in the capabilities command to pass thunks that invoke
client.request('health') and client.request('clients.current'), rather than
starting promises and mapping their results beforehand. Adjust probe’s parameter
and execution flow as needed so it invokes each thunk and retains responsibility
for rejection handling.

73-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add colocated tests for version comparison mapping.

No capabilities test file covers compareCoreVersion or numericVersion. Add tests for compatible, older, prerelease, missing, and unparsable versions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/capabilities.ts` around lines 73 - 109, Add a colocated
capabilities test file covering compareCoreVersion and numericVersion, with
cases for compatible versions, older versions, prerelease versions, missing
input, and unparsable values. Assert the returned status and version fields,
including unknown handling for missing or invalid versions, while preserving the
existing comparison behavior.

Source: Coding guidelines

src/cli/commands/systems.ts (2)

33-53: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Preserve the wrapper shape when filtering a wrapped payload.

If Core returns { systems: [...] } plus sibling metadata, and the user supplies only --filter or --category, the command returns a bare array. Without those flags it returns the original wrapper. Consumers then see two different result shapes for the same command. Return the wrapper with a replaced systems array to keep one shape.

♻️ Proposed refactor
-  const systems = Array.isArray(value)
-    ? value
-    : value &&
-        typeof value === 'object' &&
-        Array.isArray((value as Record<string, unknown>).systems)
-      ? ((value as Record<string, unknown>).systems as unknown[])
-      : undefined;
-  if (!systems) return value;
+  const wrapper =
+    !Array.isArray(value) &&
+    value &&
+    typeof value === 'object' &&
+    Array.isArray((value as Record<string, unknown>).systems)
+      ? (value as Record<string, unknown>)
+      : undefined;
+  const systems = Array.isArray(value)
+    ? value
+    : ((wrapper?.systems as unknown[] | undefined) ?? undefined);
+  if (!systems) return value;
@@
-  if (!summary) return selected;
+  if (!summary) return wrapper ? { ...wrapper, systems: selected } : selected;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/systems.ts` around lines 33 - 53, Update the filtering flow
around the systems extraction and selected result so wrapped payloads retain
their original object shape when --filter or --category is used. When value
contains a systems array, return a copy of that wrapper with its systems
property replaced by selected, preserving sibling metadata; continue returning a
bare array for unwrapped array inputs and preserve the existing summary
behavior.

14-21: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a --filter test case for systems. filter, category, and summary are registered flags. The colocated test covers only --category and --summary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/systems.ts` around lines 14 - 21, Add a colocated test case
for the systems command’s --filter flag, verifying that the filter value is
passed through the selectSystems call alongside the existing category and
summary coverage.

Source: Coding guidelines

scripts/evaluate-agent-scenarios.mjs (1)

280-288: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound the catalog subprocess and report a missing build clearly.

execFileSync runs build/index.js with no timeout and no maxBuffer limit. If the CLI hangs, the evaluation script hangs with it. If build/index.js is absent, the failure surfaces as a raw spawn error. Add a timeout and a pre-check.

♻️ Proposed refactor
 function loadCatalog(root, path) {
   if (path) return readJson(resolve(path));
+  const entry = resolve(root, 'build/index.js');
+  if (!existsSync(entry)) {
+    throw new Error(`Built CLI not found at ${entry}; run the build first or pass --catalog`);
+  }
   const output = execFileSync(
     process.execPath,
-    [resolve(root, 'build/index.js'), 'catalog', '--json', '--no-pretty'],
-    { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] },
+    [entry, 'catalog', '--json', '--no-pretty'],
+    { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 60_000 },
   );
   return JSON.parse(output);
 }

Import existsSync alongside readFileSync:

-import { readFileSync } from 'node:fs';
+import { existsSync, readFileSync } from 'node:fs';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/evaluate-agent-scenarios.mjs` around lines 280 - 288, Update
loadCatalog to pre-check that the resolved build/index.js exists before invoking
execFileSync, reporting a clear missing-build error when absent. Configure
execFileSync with a finite timeout and maxBuffer limit so catalog generation
cannot hang or exceed output bounds, while preserving the existing JSON parsing
behavior.
src/api/access.ts (1)

5-115: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a disjointness assertion for method classifications.

The existing test covers all 90 methods. Add a check that READ_METHODS and WRITE_METHODS remain disjoint. Otherwise, a future duplicate makes methodEffect() return read while methodAccessCatalog() returns write.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/access.ts` around lines 5 - 115, Add a disjointness assertion for
READ_METHODS and WRITE_METHODS, preferably in the existing method-classification
test covering all methods. Verify their intersection is empty so duplicate
classifications cannot cause methodEffect() and methodAccessCatalog() to
disagree.
src/cli/commands/devices.ts (1)

86-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Return a structured error shape instead of String(error).

String(error) produces text such as Error: WebSocket closed (1006). Agents then parse prose. doctorCommand in src/cli/commands/doctor.ts already exposes a structured kind for failed checks. Use the same shape here so state stays machine-readable.

♻️ Proposed refactor
-    const [readers, activeMedia, tokens] = await Promise.all([
-      client.request(Methods.Readers).catch((error) => ({ error: String(error) })),
-      client.request(Methods.MediaActive).catch((error) => ({ error: String(error) })),
-      client.request(Methods.Tokens).catch((error) => ({ error: String(error) })),
-    ]);
+    const failure = (error: unknown) => ({
+      error: {
+        kind: error instanceof ClientError ? error.kind : 'unknown',
+        message: error instanceof Error ? error.message : String(error),
+      },
+    });
+    const [readers, activeMedia, tokens] = await Promise.all([
+      client.request(Methods.Readers).catch(failure),
+      client.request(Methods.MediaActive).catch(failure),
+      client.request(Methods.Tokens).catch(failure),
+    ]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/commands/devices.ts` around lines 86 - 90, Update the request error
handlers in the Promise.all block for readers, activeMedia, and tokens to return
the same structured error shape used by doctorCommand’s failed checks, including
its machine-readable kind field, instead of String(error). Preserve the existing
per-request fallback behavior and ensure state remains machine-readable.
src/cli/policy.test.ts (1)

5-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for unrestricted policy and confirmationGranted.

The suite covers interactive and read-only. unrestricted is the branch that allows a write without --yes, and confirmationGranted returns true for it without any flag. Both are security-relevant paths in src/cli/policy.ts. Add two cases.

💚 Proposed tests
+  it('allows unconfirmed writes under unrestricted policy', () => {
+    const args = parseCliArgs(['mappings', 'delete', '1', '--policy', 'unrestricted']);
+    expect(enforceCommandPolicy(args)).toMatchObject({ path: 'mappings delete' });
+    expect(confirmationGranted(args)).toBe(true);
+  });
+
+  it('withholds confirmation under read-only policy', () => {
+    const args = parseCliArgs(['state', '--policy', 'read-only', '--yes']);
+    expect(confirmationGranted(args)).toBe(false);
+  });

Import confirmationGranted from ./policy.js.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/policy.test.ts` around lines 5 - 59, Add coverage in the command
policy suite for the unrestricted policy: verify a state-changing command
succeeds without --yes when --policy unrestricted is supplied, and verify
confirmationGranted returns true for unrestricted without any confirmation flag.
Import confirmationGranted from ./policy.js and keep the existing interactive
and read-only cases unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/evaluate-agent-scenarios.mjs`:
- Around line 96-113: Validate scenario.maxCommands and scenario.maxOutputBytes
before applying the command-count and output-byte comparisons in the scenario
evaluation flow. Fail the scenario when either budget is missing or non-numeric,
rather than allowing the comparisons to be skipped; preserve the existing
efficiency and context failures for valid budgets that are exceeded.

In `@skills/zaparoo-artifacts/SKILL.md`:
- Line 41: Update the bounded mDNS discovery step in the skill instructions to
require explicit authorization and a clearly identified target before invoking
`zaparoo-cli devices scan`; otherwise make the scan conditional on an already
authorized target. Preserve the timeout and agent options once those
prerequisites are satisfied.

In `@src/cli/args.ts`:
- Around line 239-243: Update the invalid-policy error handling in parsePolicy
and its callers to identify whether the value came from the --policy flag or
ZAPAROO_POLICY, and include that source in the message. Preserve the existing
policy validation and ensure the environment-variable path used by the
options.policy assignment reports ZAPAROO_POLICY instead of --policy.

In `@src/cli/commands/agent.ts`:
- Around line 143-145: Update the detectedClients filter to validate the full
client skills directory path from CLIENT_TARGETS rather than only
path.split('/')[0], so copilot is detected only when its complete target
directory exists.

In `@src/cli/policy.ts`:
- Around line 7-22: Update the local-write flow used by enforceCommandPolicy and
writeBytesOutput so writing to an existing output path is rejected by default
rather than replaced. Use no-overwrite filesystem semantics, or gate replacement
behind an explicit overwrite option, while preserving the required --output
behavior.

In `@src/client/client.ts`:
- Around line 78-99: Update the discarded socket cleanup in the connection retry
catch block to attach a no-op error listener to failedSocket after
removeAllListeners() and before terminate(). Keep the existing cleanup and retry
behavior unchanged.

---

Nitpick comments:
In `@scripts/evaluate-agent-scenarios.mjs`:
- Around line 280-288: Update loadCatalog to pre-check that the resolved
build/index.js exists before invoking execFileSync, reporting a clear
missing-build error when absent. Configure execFileSync with a finite timeout
and maxBuffer limit so catalog generation cannot hang or exceed output bounds,
while preserving the existing JSON parsing behavior.

In `@src/api/access.ts`:
- Around line 5-115: Add a disjointness assertion for READ_METHODS and
WRITE_METHODS, preferably in the existing method-classification test covering
all methods. Verify their intersection is empty so duplicate classifications
cannot cause methodEffect() and methodAccessCatalog() to disagree.

In `@src/cli/commands/capabilities.ts`:
- Around line 19-28: Update the probe call sites in the capabilities command to
pass thunks that invoke client.request('health') and
client.request('clients.current'), rather than starting promises and mapping
their results beforehand. Adjust probe’s parameter and execution flow as needed
so it invokes each thunk and retains responsibility for rejection handling.
- Around line 73-109: Add a colocated capabilities test file covering
compareCoreVersion and numericVersion, with cases for compatible versions, older
versions, prerelease versions, missing input, and unparsable values. Assert the
returned status and version fields, including unknown handling for missing or
invalid versions, while preserving the existing comparison behavior.

In `@src/cli/commands/devices.ts`:
- Around line 86-90: Update the request error handlers in the Promise.all block
for readers, activeMedia, and tokens to return the same structured error shape
used by doctorCommand’s failed checks, including its machine-readable kind
field, instead of String(error). Preserve the existing per-request fallback
behavior and ensure state remains machine-readable.

In `@src/cli/commands/systems.ts`:
- Around line 33-53: Update the filtering flow around the systems extraction and
selected result so wrapped payloads retain their original object shape when
--filter or --category is used. When value contains a systems array, return a
copy of that wrapper with its systems property replaced by selected, preserving
sibling metadata; continue returning a bare array for unwrapped array inputs and
preserve the existing summary behavior.
- Around line 14-21: Add a colocated test case for the systems command’s
--filter flag, verifying that the filter value is passed through the
selectSystems call alongside the existing category and summary coverage.

In `@src/cli/policy.test.ts`:
- Around line 5-59: Add coverage in the command policy suite for the
unrestricted policy: verify a state-changing command succeeds without --yes when
--policy unrestricted is supplied, and verify confirmationGranted returns true
for unrestricted without any confirmation flag. Import confirmationGranted from
./policy.js and keep the existing interactive and read-only cases unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 008f499d-f3da-4c0e-be1e-b0a3049ed768

📥 Commits

Reviewing files that changed from the base of the PR and between f424799 and 8a6a0af.

📒 Files selected for processing (57)
  • README.md
  • SECURITY.md
  • docs/cli-output.md
  • docs/mcp-boundary.md
  • docs/skill-scenarios.md
  • evals/fixtures/reference.json
  • evals/fixtures/unsafe.json
  • evals/scenarios.json
  • package.json
  • scripts/audit-user-api.mjs
  • scripts/evaluate-agent-scenarios.mjs
  • scripts/evaluate-agent-scenarios.test.mjs
  • scripts/smoke-packed-package.mjs
  • scripts/validate-skills.mjs
  • skills/zaparoo-artifacts/SKILL.md
  • skills/zaparoo-development/SKILL.md
  • skills/zaparoo-library/SKILL.md
  • skills/zaparoo-nfc/SKILL.md
  • skills/zaparoo-online/SKILL.md
  • skills/zaparoo-troubleshooting/SKILL.md
  • skills/zaparoo-troubleshooting/references/cli.md
  • skills/zaparoo-zapscript/SKILL.md
  • skills/zaparoo-zapscript/references/zapscript.md
  • src/api/access.ts
  • src/cli/agent-output.test.ts
  • src/cli/agent-output.ts
  • src/cli/args.ts
  • src/cli/catalog.test.ts
  • src/cli/catalog.ts
  • src/cli/commands/agent.test.ts
  • src/cli/commands/agent.ts
  • src/cli/commands/auth.ts
  • src/cli/commands/capabilities.ts
  • src/cli/commands/catalog.ts
  • src/cli/commands/commands.test.ts
  • src/cli/commands/common.ts
  • src/cli/commands/devices.ts
  • src/cli/commands/docs.test.ts
  • src/cli/commands/docs.ts
  • src/cli/commands/doctor.ts
  • src/cli/commands/feedback.ts
  • src/cli/commands/pair.ts
  • src/cli/commands/run.ts
  • src/cli/commands/systems.ts
  • src/cli/commands/tokens.ts
  • src/cli/errors.test.ts
  • src/cli/errors.ts
  • src/cli/index.test.ts
  • src/cli/index.ts
  • src/cli/output.test.ts
  • src/cli/output.ts
  • src/cli/package-files.ts
  • src/cli/policy.test.ts
  • src/cli/policy.ts
  • src/client/client.test.ts
  • src/client/client.ts
  • src/client/errors.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/cli/commands/pair.ts
  • src/cli/commands/auth.ts
  • src/cli/errors.test.ts
  • src/cli/commands/doctor.ts
  • skills/zaparoo-troubleshooting/references/cli.md
  • src/cli/output.test.ts
  • src/cli/commands/run.ts
  • src/cli/commands/common.ts
  • SECURITY.md
  • scripts/audit-user-api.mjs
  • skills/zaparoo-zapscript/references/zapscript.md
  • README.md
  • src/cli/errors.ts
  • src/cli/index.ts

Comment thread scripts/evaluate-agent-scenarios.mjs Outdated
Comment thread skills/zaparoo-artifacts/SKILL.md Outdated
Comment thread src/cli/args.ts
Comment thread src/cli/commands/agent.ts
Comment thread src/cli/policy.ts
Comment thread src/client/client.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
skills/zaparoo-artifacts/SKILL.md (1)

84-86: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove CLI SSH transport instructions from the skill.

Lines [84-86] add scp, sftp, and SSH streaming procedures. Skills must not contain CLI SSH logic. Keep this workflow user-assisted, or move the transport procedure outside the skill.

As per coding guidelines, skills/**/* must not add CLI SSH, PowerShell, filesystem scouting, process probing, Core stop/restart, or artifact collector logic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-artifacts/SKILL.md` around lines 84 - 86, Remove the scp,
sftp, and SSH streaming transport instructions from the skill’s
artifact-transfer workflow. Keep the workflow user-assisted using the existing
API, device file manager, mounted share, or similar non-CLI options, and do not
add replacement CLI transport, filesystem, process, or service-management logic.

Source: Coding guidelines

skills/zaparoo-zapscript/SKILL.md (1)

30-35: 🔒 Security & Privacy | 🟠 Major

Require confirmation for every high-impact live action.

Line [34] allows launch, stop, input, HTTP, and execute actions when the user explicitly requested them. Remove this exception. Keep --policy interactive --yes only after confirmation.

This repeats the earlier confirmation-gate finding from the library and NFC skills.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-zapscript/SKILL.md` around lines 30 - 35, Update the
live-execution guidance around the confirmation rule to require explicit
confirmation for every high-impact action, including launch, stop, input, HTTP,
execute, and profile changes, even when the user previously requested it. Remove
the explicit-request exception and retain --policy interactive --yes only after
confirmation.
skills/zaparoo-development/SKILL.md (1)

57-62: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Include the complete validation workflow.

Lines [57-60] cover unit tests and build, but omit API audit, check, typecheck, the full test suite, and pack dry-run. Add all required checks before broad changes are considered complete.

As per coding guidelines, before finishing broad changes, run API audit, check, typecheck, full tests, build, and pack dry-run.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-development/SKILL.md` around lines 57 - 62, Expand the
validation workflow in SKILL.md to require API audit, check, typecheck, the full
test suite, build, and pack dry-run before broad changes are considered
complete. Preserve the existing deployment, live-state inspection,
authorization, and skipped-check reporting steps.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/zaparoo-library/SKILL.md`:
- Around line 108-110: Bound lifecycle polling in
skills/zaparoo-library/SKILL.md lines 108-110 for both launch and stop
workflows, adding terminal deadlines or attempt limits and reporting timeout or
state mismatch. Apply the same bounded polling and explicit
timeout/state-mismatch reporting to diagnostic polling in
skills/zaparoo-troubleshooting/SKILL.md line 91 and post-run/post-stop settling
checks in skills/zaparoo-zapscript/SKILL.md line 41.
- Line 110: Update the lifecycle guidance in SKILL.md to remove the
unconditional stop from the launch workflow. Keep launch limited to running and
waiting for active media to clear, and document stop as a separate flow that is
performed only when the user explicitly requests and approves it.

In `@skills/zaparoo-online/SKILL.md`:
- Line 79: Update the documented backup download command to require explicit
confirmation when downloading private backups, rather than allowing --agent to
bypass approval for this local-write operation. Classify the command as write or
define command-specific confirmation, and document the resulting approval
workflow near the command example.

In `@skills/zaparoo-troubleshooting/SKILL.md`:
- Around line 35-44: Update the discovery workflow around “Then narrow discovery
only as needed” so `zaparoo-cli devices scan --timeout 5 --agent` is shown or
invoked only after explicit approval and a clearly identified device or network
scope are established. Keep targeted commands such as devices list, devices
ping, and state available within their existing authorization boundaries, and do
not treat the timeout as authorization.

In `@src/cli/commands/capabilities.ts`:
- Around line 79-95: The capabilities check must not infer API compatibility
from the Core version: update the logic around numericVersion and
CORE_API_BASELINE in src/cli/commands/capabilities.ts lines 79-95 to report
unprobed method availability as unverified unless an explicit documented
compatibility signal exists, while preserving prerelease distinctions such as
2.16.0-beta.1 versus 2.16.0. Review the related version handling at
src/cli/commands/capabilities.ts lines 47-49 and update coverage in
src/cli/commands/capabilities.test.ts lines 5-18 for newer major versions and
prereleases.

---

Outside diff comments:
In `@skills/zaparoo-artifacts/SKILL.md`:
- Around line 84-86: Remove the scp, sftp, and SSH streaming transport
instructions from the skill’s artifact-transfer workflow. Keep the workflow
user-assisted using the existing API, device file manager, mounted share, or
similar non-CLI options, and do not add replacement CLI transport, filesystem,
process, or service-management logic.

In `@skills/zaparoo-development/SKILL.md`:
- Around line 57-62: Expand the validation workflow in SKILL.md to require API
audit, check, typecheck, the full test suite, build, and pack dry-run before
broad changes are considered complete. Preserve the existing deployment,
live-state inspection, authorization, and skipped-check reporting steps.

In `@skills/zaparoo-zapscript/SKILL.md`:
- Around line 30-35: Update the live-execution guidance around the confirmation
rule to require explicit confirmation for every high-impact action, including
launch, stop, input, HTTP, execute, and profile changes, even when the user
previously requested it. Remove the explicit-request exception and retain
--policy interactive --yes only after confirmation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: edba1cce-0c2d-4b4a-80eb-2e9e12e33033

📥 Commits

Reviewing files that changed from the base of the PR and between f424799 and 00d703a.

📒 Files selected for processing (62)
  • README.md
  • SECURITY.md
  • docs/cli-output.md
  • docs/mcp-boundary.md
  • docs/skill-scenarios.md
  • evals/fixtures/reference.json
  • evals/fixtures/unsafe.json
  • evals/scenarios.json
  • package.json
  • scripts/audit-user-api.mjs
  • scripts/evaluate-agent-scenarios.mjs
  • scripts/evaluate-agent-scenarios.test.mjs
  • scripts/smoke-packed-package.mjs
  • scripts/validate-skills.mjs
  • skills/zaparoo-artifacts/SKILL.md
  • skills/zaparoo-development/SKILL.md
  • skills/zaparoo-library/SKILL.md
  • skills/zaparoo-nfc/SKILL.md
  • skills/zaparoo-online/SKILL.md
  • skills/zaparoo-troubleshooting/SKILL.md
  • skills/zaparoo-troubleshooting/references/cli.md
  • skills/zaparoo-zapscript/SKILL.md
  • skills/zaparoo-zapscript/references/zapscript.md
  • src/api/access.ts
  • src/cli/agent-output.test.ts
  • src/cli/agent-output.ts
  • src/cli/args.test.ts
  • src/cli/args.ts
  • src/cli/catalog.test.ts
  • src/cli/catalog.ts
  • src/cli/commands/agent.test.ts
  • src/cli/commands/agent.ts
  • src/cli/commands/auth.ts
  • src/cli/commands/capabilities.test.ts
  • src/cli/commands/capabilities.ts
  • src/cli/commands/catalog.ts
  • src/cli/commands/commands.test.ts
  • src/cli/commands/common.ts
  • src/cli/commands/devices.test.ts
  • src/cli/commands/devices.ts
  • src/cli/commands/docs.test.ts
  • src/cli/commands/docs.ts
  • src/cli/commands/doctor.ts
  • src/cli/commands/feedback.ts
  • src/cli/commands/pair.ts
  • src/cli/commands/run.ts
  • src/cli/commands/systems.ts
  • src/cli/commands/tokens.ts
  • src/cli/errors.test.ts
  • src/cli/errors.ts
  • src/cli/files.test.ts
  • src/cli/files.ts
  • src/cli/index.test.ts
  • src/cli/index.ts
  • src/cli/output.test.ts
  • src/cli/output.ts
  • src/cli/package-files.ts
  • src/cli/policy.test.ts
  • src/cli/policy.ts
  • src/client/client.test.ts
  • src/client/client.ts
  • src/client/errors.ts
🚧 Files skipped from review as they are similar to previous changes (47)
  • src/cli/commands/catalog.ts
  • docs/mcp-boundary.md
  • src/cli/errors.test.ts
  • evals/fixtures/unsafe.json
  • scripts/validate-skills.mjs
  • skills/zaparoo-troubleshooting/references/cli.md
  • src/cli/catalog.test.ts
  • src/client/client.test.ts
  • SECURITY.md
  • scripts/smoke-packed-package.mjs
  • src/cli/index.test.ts
  • scripts/evaluate-agent-scenarios.test.mjs
  • src/cli/commands/feedback.ts
  • src/cli/commands/tokens.ts
  • src/cli/commands/run.ts
  • src/cli/commands/devices.ts
  • evals/scenarios.json
  • scripts/audit-user-api.mjs
  • src/cli/files.ts
  • docs/skill-scenarios.md
  • src/cli/output.test.ts
  • src/cli/errors.ts
  • skills/zaparoo-zapscript/references/zapscript.md
  • src/cli/commands/commands.test.ts
  • src/cli/agent-output.test.ts
  • src/cli/output.ts
  • src/cli/agent-output.ts
  • scripts/evaluate-agent-scenarios.mjs
  • src/cli/package-files.ts
  • src/cli/commands/docs.ts
  • src/cli/commands/common.ts
  • src/api/access.ts
  • src/cli/commands/auth.ts
  • src/cli/commands/pair.ts
  • src/cli/catalog.ts
  • src/cli/commands/agent.ts
  • docs/cli-output.md
  • src/cli/commands/systems.ts
  • src/cli/commands/doctor.ts
  • src/client/errors.ts
  • src/cli/args.ts
  • src/cli/commands/docs.test.ts
  • evals/fixtures/reference.json
  • src/client/client.ts
  • src/cli/index.ts
  • package.json
  • README.md

Comment thread skills/zaparoo-library/SKILL.md Outdated
Comment thread skills/zaparoo-library/SKILL.md Outdated
Comment thread skills/zaparoo-online/SKILL.md Outdated
Comment thread skills/zaparoo-troubleshooting/SKILL.md Outdated
Comment thread src/cli/commands/capabilities.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
skills/zaparoo-online/SKILL.md (1)

62-62: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Document the --all-pages page cap.

--all-pages retrieves up to 100 pages by default. Users can set a lower limit with --max-pages <n>, where n is 1–100. Add these limits to line 62.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/zaparoo-online/SKILL.md` at line 62, Update the pagination guidance
near the returned next_cursor and --all-pages instructions to document that
--all-pages retrieves up to 100 pages by default, and that --max-pages <n> can
lower the limit with n restricted to 1–100.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/zaparoo-troubleshooting/SKILL.md`:
- Line 49: Move the WebSocket upgrade retry and bounded-backoff guidance from
the devices scan section to the connecting command’s instructions. Keep devices
scan limited to bounded mDNS discovery, and retain only the accurate timeout,
authorization, and single-device --device omission guidance there.

---

Nitpick comments:
In `@skills/zaparoo-online/SKILL.md`:
- Line 62: Update the pagination guidance near the returned next_cursor and
--all-pages instructions to document that --all-pages retrieves up to 100 pages
by default, and that --max-pages <n> can lower the limit with n restricted to
1–100.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f796dcac-7646-4f68-be4a-7bc155834fa4

📥 Commits

Reviewing files that changed from the base of the PR and between 00d703a and fe1c2ff.

📒 Files selected for processing (11)
  • skills/zaparoo-artifacts/SKILL.md
  • skills/zaparoo-development/SKILL.md
  • skills/zaparoo-library/SKILL.md
  • skills/zaparoo-online/SKILL.md
  • skills/zaparoo-troubleshooting/SKILL.md
  • skills/zaparoo-zapscript/SKILL.md
  • src/cli/catalog.ts
  • src/cli/commands/capabilities.test.ts
  • src/cli/commands/capabilities.ts
  • src/cli/policy.test.ts
  • src/cli/policy.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/cli/catalog.ts
  • src/cli/policy.ts

Comment thread skills/zaparoo-troubleshooting/SKILL.md Outdated
@wizzomafizzo
wizzomafizzo merged commit dcaae59 into main Aug 4, 2026
2 checks passed
@wizzomafizzo
wizzomafizzo deleted the feat/zaparoo-cli-v2 branch August 4, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant