slash-do 2.10.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,22 +30,59 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
30
30
  **Runtime correctness**
31
31
  - Null/undefined access without guards; off-by-one errors; spread of null (is `{}`), spread of non-objects (string → indexed chars, array → numeric keys) — guard with plain-object check before spreading
32
32
  - External/user data (parsed JSON, API responses, file reads) used without structural validation — guard parse failures, missing properties, wrong types, null elements. Optional enrichment failures should not abort the main operation
33
- - Type coercion: `Number('')` is `0` not empty; `0` is falsy in truthy checks; `NaN` comparisons always false; `"10" < "2"` (lexicographic). Deserialized booleans: `"false"` is truthy — use `=== 'true'`. `isinstance(x, int)` accepts `bool` in Python; `typeof NaN === 'number'` in JS
33
+ - Type coercion: `Number('')` is `0` not empty; `0` is falsy in truthy checks; `NaN` comparisons always false; `"10" < "2"` (lexicographic). Deserialized booleans: `"false"` is truthy — use `=== 'true'`. `isinstance(x, int)` accepts `bool` in Python; `typeof NaN === 'number'` in JS. For env-var numeric parsing in particular, use `Number.parseInt(String(value).trim(), 10)` and gate with `Number.isFinite(parsed)` — `NaN` flowing into subprocess args (`-p NaN`) or formatted strings produces opaque downstream failures (whitespace/inline-comment values are common culprits)
34
34
  - Config/option defaults applied with `||` or falsy guards — intentional `0`, `false`, or `''` values are treated as "unset" and replaced by the default. Use `?? default` or explicit `=== undefined` checks when zero, false, or empty string are valid configuration values
35
35
  - Functions returning different types depending on input conditions (string in one branch, object in another) — callers must branch on return type; prefer a consistent return shape
36
36
  - Indexing empty arrays; `every`/`some`/`reduce` on empty collections returning vacuously true; declared-but-never-updated state/variables
37
37
  - Parallel arrays coupled by index position — use objects/maps keyed by stable identifier
38
38
  - Shared mutable references: module-level defaults mutated across calls (use `structuredClone()`); `useCallback`/`useMemo` referencing later `const` (temporal dead zone); spread followed by unconditional assignment clobbering spread values
39
+ - React state invariants (uniqueness, cap/floor, monotonicity) checked against render-time value before `setX(...)` — rapid events or concurrent updates race the check. Move into the functional updater: `setX(prev => prev.includes(id) ? prev : [...prev, id])`
40
+ - `useEffect` depending on state it writes — the write retriggers the effect (infinite loop / request storm). Split into two effects, drop the self-written value from deps, or use a functional setter that doesn't require the current value in deps
39
41
  - Functions with >10 branches or >15 cyclomatic complexity — refactor
42
+ - String accumulation via `+=` inside high-frequency loops (streaming frames, chunked I/O, per-event handlers) is O(n²) for long outputs and triggers React re-renders on growing payloads. Collect chunks into an array and `join('')` at the end while still emitting per-chunk events
43
+ - Server-side string formatting (`toLocaleString`, `toLocaleDateString`, currency/number formatters) that depends on locale/timezone defaults produces non-deterministic outputs across deployments. For data flowing into prompts, logs, or persisted records, format with explicit `Intl.DateTimeFormat({ timeZone: ... })` or ISO strings; reserve locale-aware formatting for user-visible UI layers
44
+ - Required-at-use-time config values (model name, API key, endpoint URL, default selection) that may be null/undefined in source data must be validated at the boundary before invoking the downstream API. Otherwise the API responds with an opaque error far from the user's intent. Emit a clear, actionable error identifying the missing field
40
45
 
41
46
  **API route basics**
42
- - Route params passed to services without format validation; path containment using string prefix without separator boundary (use `path.relative()`)
47
+ - Route params passed to services without format validation; path containment using string prefix without separator boundary (use `path.relative()`). When sibling endpoints validate body/query fields, the path param must be validated with the same schema — skipping param validation on one endpoint turns schema violations into 404/500 instead of 400
43
48
  - Parameterized/wildcard routes registered before specific named routes (`/:id` before `/drafts` matches `/drafts` as `id="drafts"`)
44
49
  - Stored or external URLs rendered as clickable links without protocol validation — allowlist `http:`/`https:`
45
50
  - Request schema fields for large string/binary payloads (base64, file content, free text) without per-field size limits — a total body-size limit alone doesn't prevent individual oversized fields from consuming excessive memory or exceeding downstream service limits; add per-field `max(N)` constraints with clear error messages
51
+ - Character-class regex validators (`^[a-z0-9-]+$`) claiming to enforce a structured format (slug, kebab-case, reverse-DNS) — they accept leading/trailing separators (`-foo`, `foo-`) and repeated separators (`a--b`). Require alnum boundaries or use a parser
52
+ - `z.string().min(1)` without `.trim()` accepts whitespace-only values for user-visible names — use `z.string().trim().min(1)` when the field represents a human-readable identifier
53
+ - Object spread of a potentially-null/undefined boundary value (`{ ...req.body, id }`) — throws a TypeError and surfaces as 500 instead of 4xx. Use `{ ...(req.body ?? {}), id }` at request/boundary entry points
54
+ - Schemas accepting paired range fields (`startDate`/`endDate`, `min`/`max`, `from`/`to`) without a cross-field refinement (`zod .refine()`) — accepts inconsistent ranges (start > end). Define deterministic rules when only one bound is supplied
55
+ - Outbound payloads (snippets, previews, cached excerpts) stored in persisted records or sent over streaming protocols without size caps — applies the same per-field max constraint as inbound payloads, enforced at capture time so display-layer truncation isn't the only defense
56
+
57
+ **Async & state (single-file patterns)**
58
+ - Optimistic UI state (selection, active flag, list membership) updated before an async call and never reverted on failure — the user sees success, the server remains on the old state. Capture the previous value, await in try/catch, and reset on rejection. Optimistic placeholder IDs ('pending', 'temp_*', client-generated UUIDs) must NOT be echoed back to the server in subsequent requests — the server validates against its real ID format and rejects them as 400s. Disable controls bound to optimistic IDs until the server returns a real one, OR omit the field from outgoing payloads when the local value still matches the optimistic shape
59
+ - Settings whose persistence model is per-record (per-conversation, per-document, per-project) must be persisted on every mutation, not just held in local component state — otherwise refresh resets to the persisted value. Decide explicitly whether the field is per-record, per-session, or per-action — and persist accordingly
60
+ - Async functions invoked from sync event handlers (`onClick`, `onKeyDown`), effects, or dispatchers without rejection handling at the call site — even when a shared `request()` toasts the error, the unhandled rejection leaves UI stuck (modal doesn't close, palette doesn't navigate, dirty state doesn't clear). Wrap in try/catch, attach `.catch(...)`, or use `void p.catch(...)`; only run close/navigate/success in the resolve branch. After awaiting, check `signal.aborted` (or a `mountedRef`) before subsequent state writes — otherwise React warns about updates on unmounted trees and stale state leaks through
61
+ - Single shared error-state variable reused by multiple independent async flows — one flow's success path clears the other flow's displayed error. Split errors by domain or only overwrite the specific error you own
62
+ - Loading flag covers only the primary fetch — a slow or failed secondary fetch renders a blank page with no indicator. Include every render-gating load in the loading state or provide explicit empty/error states
63
+ - Streaming UIs that clear the streaming buffer when a terminal `error` event arrives discard deltas the user already saw. Preserve accumulated content as a partial result with an error indicator so users don't lose what was visible
64
+ - Raw `fetch()` failures (TypeError "Failed to fetch", DNS errors, ECONNREFUSED) at API client boundaries must be translated to a consistent user-friendly message matching the project's established transport-error utility — preserve `AbortError` so callers can still distinguish cancellation from failure
65
+ - Child process `spawn()` calls without an `error` event handler — when the binary is missing or unexecutable, Node emits an `'error'` event and never emits `'close'`. Promise wrappers that only listen for `'close'` hang forever; bare spawn calls with no listener crash the parent process via uncaught exception. Always register `proc.on('error', ...)` alongside `'close'`. SIGKILL escalation timers must check liveness via `proc.exitCode == null` (or a `closed` flag set in the close handler) — `proc.killed` becomes `true` immediately after `kill('SIGTERM')` is called, so guards using `if (!proc.killed)` never fire and hung children survive indefinitely. Single-process tracking ("BUSY guard", `activeProcess` global) must hold the reference until the `'close'` event fires, not until `kill()` is sent — clearing the reference at SIGTERM opens a race window where a new job can start while the previous child is still alive
66
+ - `spawn`/`exec` env objects: setting a key to `undefined` may coerce to the literal string `"undefined"` instead of unsetting the variable — build the env, then `delete env.PYTHONPATH` (or set to `''` if you explicitly want it cleared). Same caveat applies to nullish/numeric values being coerced to strings inside the env map
67
+ - Caches that store negative/error results (`null`, "not found", probe failure) without a TTL or invalidation hook — when a user installs the missing dependency mid-runtime (ffmpeg, python venv, model file), the cache reports "still missing" until process restart. Cache only successful lookups, OR use a short TTL for negatives, OR re-probe on demand when the cached value is the negative sentinel
68
+ - Late-connecting clients to long-running async jobs (SSE, WebSocket subscribe-by-id) receive nothing if they connect after the terminal `complete`/`error` broadcast — the server emitted once and moved on. Persist the most-recent (or terminal) payload on the job and emit it immediately on attach, OR document that subscribers must connect before kicking off the job and update any "late connectors will get the final state" comments accordingly
69
+ - Server returning an empty success payload (`200` with `{ images: [] }`, `{ items: null }`, etc.) when an awaited operation succeeded but the artifact fetch failed — clients treat empty as "no work to show" and never surface the underlying error. After awaiting completion, a missing/unreadable artifact is an internal error: return non-2xx with a structured error, never an empty 200
70
+
71
+ **Streaming response handlers (server-side)**
72
+ - Long-lived streaming handlers (SSE, chunked HTTP) must register a client-disconnect listener (`req.on('close')`/`req.on('aborted')`), set an `aborted` flag, and check it before subsequent writes — otherwise the server keeps emitting frames and incurring `write-after-end` errors after the client navigates away
73
+ - After flushing streaming headers, framework error middleware (asyncHandler, exception filters) cannot send a JSON error — wrap post-handshake logic in try/finally that translates errors into a terminal `event: error` SSE frame and ends the response gracefully (`if (!res.writableEnded && !res.destroyed) res.end()`)
74
+ - Per-request timeouts on streaming responses must remain active for the full duration of stream consumption, not cleared on initial fetch resolution — a stalled upstream that keeps the connection open hangs the consumer indefinitely
75
+ - Honor write backpressure: check the boolean return of `write()` and await `'drain'` when it returns false; otherwise a slow client causes unbounded server-side buffering
76
+ - When attaching paired listeners for backpressure or completion (`drain` + `close`), the cleanup handler must remove ALL of them — asymmetric removal accumulates listeners across slow-client cycles
77
+ - Named lifecycle events on streams (`error`, `done`, `complete`) must be MUTUALLY EXCLUSIVE — after emitting `error`, do NOT also emit `done`. Otherwise clients parsing the last event treat failed runs as completed
46
78
 
47
79
  **Error handling (single-file)**
48
80
  - Swallowed errors (empty `.catch(() => {})`); error handlers that exit cleanly (`exit 0`, `return`) without user-visible output; handlers replacing detailed failure info with generic messages
81
+ - Error discrimination by string matching (`err.message.includes('not found')`, regex on error text) — localization, refactors, or wrapper rewrites silently change HTTP status / retry behavior. Use explicit error codes or typed classes
82
+ - Route handlers mapping any exception from a service into a single HTTP status (e.g., `catch { throw new NotFoundError() }`) — hides real server errors (file I/O, parse, write failures) as domain 404s. Map only known codes/classes; let unknown errors surface as 500
83
+ - Error wrappers that re-throw with only `{ status }` and drop `code`/`context`/`cause` — downstream consumers see generic `INTERNAL_ERROR` instead of the specific code. Preserve structured detail when wrapping
84
+ - Errors thrown from middleware/parser modules (multipart, body parsers, validators) without `err.status` set are normalized to HTTP 500 by the framework's default error handler — but they typically represent client payload issues (bad multipart, payload too large, file type rejected, missing boundary). Set `err.status = 400` (or 413 for size limits, etc.) and a stable `err.code` (`PAYLOAD_TOO_LARGE`, `INVALID_MULTIPART`, `VALIDATION_ERROR`) at the throw site, OR throw a typed `ServerError`/`ApiError`, so clients distinguish their bad input from real server failures
85
+ - Outbound `fetch()` / HTTP calls in setup, install, or update scripts (`scripts/*.js`, `setup.sh` invoked tools, post-install hooks) without an `AbortController` per-request timeout — a hung server (accepts connection, never responds) blocks the parent shell process indefinitely, breaking "fail-soft" guarantees that the parent script depends on. Use the same timeout helper the rest of the codebase uses for outbound HTTP, and treat timeout as a skip with a clean exit code
49
86
 
50
87
  ### Domain-Specific (check only when file type matches)
51
88
 
@@ -82,13 +119,17 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
82
119
 
83
120
  **Shell & portability** _[subprocesses, shell scripts, CLI tools]_
84
121
  - `set -e` aborting on non-critical failures; broken pipes on non-critical writes — use `|| true`
85
- - Interactive prompts in non-interactive contexts (CI, cron) — guard with TTY detection
122
+ - Interactive prompts in non-interactive contexts (CI, cron) — guard with TTY detection (`[ -t 0 ]`). Also handle EOF (Ctrl-D, closed stdin) explicitly under `set -e` — a `read` returning non-zero on EOF aborts the script. Use `read ... || true` and check the return; default to a safe value. Validate the full set of expected answers (e.g., `y`/`yes`/`n`/`no` case-insensitive) — treating any non-default input as consent surprises users
86
123
  - Detached processes with piped stdio — SIGPIPE on parent exit. Use `'ignore'`
87
124
  - Subprocess output buffered without size limits — unbounded memory growth
88
125
  - Platform-specific: hardcoded shell interpreters; `path.join()` backslashes breaking ESM imports — use `pathToFileURL()`
89
126
  - Naive whitespace splitting of command strings breaks quoted arguments — use proper argv parser
90
127
  - Subprocess output parsed from single stream (stdout or stderr) to detect conditions — check both streams and exit code
128
+ - Readiness/health probes that rely solely on subprocess exit code without inspecting output — many CLIs (`psql`, `curl`, `kubectl`) exit 0 for empty results, missing schema, or auth-only handshake. Capture stdout and verify it contains the expected marker. For tools that read user-level config (`.psqlrc`, `~/.curlrc`), pass flags that ignore those files (`-X`, `--no-rcfile`) so the probe behaves the same in every environment
129
+ - Setup/provisioning scripts invoked from hot paths (`npm start`, dev script, container entrypoint) that mutate credentials, privileges, or installed-package state (`ALTER USER`, password resets, brew installs) on every invocation — gate the heavy work behind a cheap readiness check, OR refactor each step to be idempotent and detect already-applied state
91
130
  - Shell expansions suppressed by quoting — single quotes prevent all expansion
131
+ - Arguments passed via process argv have OS-imposed length limits (notoriously low on Windows, ~32KB). For variable-length payloads (prompts, JSON blobs, file contents), pipe via stdin instead of constructing a long argv. If argv must be used, enforce a strict cap and fail with a clear message before spawning
132
+ - PowerShell `$LASTEXITCODE` propagates from any external call and is read by the script's final exit. A step claiming to be "fail-soft" (e.g., a non-essential post-install hook) that runs an external command without explicitly resetting `$LASTEXITCODE = 0` (or wrapping in try/catch with `$global:LASTEXITCODE = 0`) leaks a non-zero exit code from the soft step into the parent script's overall exit status — breaking the fail-soft contract that callers depend on
92
133
 
93
134
  **Search & navigation** _[search, deep-linking]_
94
135
  - Search results linking to generic list pages instead of deep-linking to specific record
@@ -98,17 +139,27 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
98
139
  - Destructive actions without confirmation step
99
140
 
100
141
  **Accessibility** _[UI components, interactive elements]_
101
- - Interactive elements missing accessible names, roles, or ARIA states — including labels removed or replaced with non-descriptive placeholders in conditional/compact rendering modes
142
+ - Interactive elements missing accessible names, roles, or ARIA states — including labels removed or replaced with non-descriptive placeholders in conditional/compact rendering modes. ARIA attributes should match established patterns used elsewhere for the same widget type (disclosure, menu, dialog)
143
+ - ARIA roles applied without the keyboard interactions they imply — `role="menu"`/`menuitem*` expects roving focus, arrow-key navigation, Escape scoped to the menu, and focus management; `role="listbox"` expects Home/End/typeahead; `role="dialog"` expects focus trap + return focus. Either implement the full interaction pattern or drop to a simpler one (native `<button>` + disclosure)
144
+ - Nested inputs handling `Escape`/`Enter`/`ArrowUp`/`ArrowDown` inside a modal/form that also handles the key at the ancestor — the event bubbles and the ancestor fires too (closes modal, submits form). Call `e.stopPropagation()` (and usually `preventDefault()`) in the inner handler
102
145
  - Custom toggles from non-semantic elements instead of native inputs
103
146
  - Overlay layers with `pointer-events-auto` intercepting clicks beneath; `pointer-events-none` on parent killing child hover handlers
147
+ - HTML `<button>` elements without an explicit `type="button"` attribute default to `type="submit"`. When the component is rendered (or could be rendered) inside a `<form>` ancestor, clicks trigger unintended form submission. Set `type="button"` on every non-submit button (close, cancel, expand, menu trigger) — the cost is one attribute and the bug is silent until the component lands inside a form
104
148
 
105
149
  **UI performance** _[UI components with streaming, scroll, or frequent updates]_
106
150
  - Event handlers or `useEffect` callbacks firing on every high-frequency event (streaming deltas, scroll, resize, keydown) without throttle, debounce, or `requestAnimationFrame` batching — causes jank and excessive re-renders. Batch with rAF or a time-based limiter when the handler doesn't need to run on every tick
107
151
 
152
+ **Wire-protocol parsers** _[SSE/NDJSON/line-delimited frame parsers, multipart, etc.]_
153
+ - Wire-protocol parsers must (a) handle the spec's full set of separators (e.g., both `\n\n` and `\r\n\r\n` for SSE; multiple `data:` lines joined with `\n`); (b) flush remaining buffered content on EOF — otherwise the last frame is dropped when upstream closes mid-frame; (c) wrap per-frame deserialization (`JSON.parse`) so a single malformed frame doesn't terminate the entire stream
154
+ - Stateful parsers (multipart, MIME, framed protocols) must verify they reached the terminal state on `req.on('end')` / EOF — calling `finish()` while still in `STATE_HEADERS`/`STATE_BODY` accepts truncated input as success, silently corrupting partially-written uploads or persisting half-written state. Track the terminal-state transition (e.g., `STATE_DONE` after the closing `--boundary--`) and return a 400 error otherwise (and clean up any partial files written)
155
+ - Per-part state in stateful parsers must be reset at part boundaries — fields like `currentFileMimetype`, accumulated headers, decoder state, and offsets that aren't cleared at the start of each new part will leak the previous part's value (e.g., a file part with no `Content-Type` inherits the previous part's mimetype). Reset per-part state at the top of the part-start handler
156
+ - Refactoring a streaming parser to "buffer-then-process" (calling `readAllBytes()` / `Buffer.concat(chunks)` / `await req.text()` before parsing) defeats the streaming contract and re-introduces an OOM/DoS vector for large uploads — verify the new implementation still respects each caller's `maxSize`/body cap WHILE reading (stop collecting once bytes exceed the cap), or restore true streaming. Watch for header comments still claiming "streams" / "never buffers entire body in memory" after such refactors — they become a documentation lie
157
+ - Library wrappers advertising a multer/express-style contract `(req, file, cb)` must pass the real `req` (not `null`) through to filters/hooks; treating the `cb` as synchronous breaks any caller that supplied an async filter (callback fires later, but the wrapper already read pre-callback state). Either enforce synchronous filters with a clear error and document, or `await` a Promise-wrapped callback before continuing
158
+
108
159
  ### Always Check — Quality & Conventions
109
160
 
110
161
  **Intent vs implementation (single-file)**
111
- - Labels, comments, status messages describing behavior the code doesn't implement
162
+ - Labels, comments, status messages describing behavior the code doesn't implement. Also covers factual doc drift: file paths/extensions (`foo.js` referenced when the file is `foo.jsx`), item counts ("13 widgets" when there are 15), default entity names ("Default" vs actual "Everything"), and route/response-shape comments that don't match what the handler returns. Verify every factual claim in a comment or JSDoc against the code it references
112
163
  - Inline code examples or command templates that aren't syntactically valid
113
164
  - Sequential numbering with gaps or jumps after edits
114
165
  - Template/workflow variables referenced but never assigned — trace each placeholder to a definition
@@ -119,6 +170,10 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
119
170
  - Lookups checking only one scope when multiple exist (local branches but not remote)
120
171
  - Tracking/checkpoint files defaulting to empty on parse failure — fail-open guards
121
172
  - Registering references to resources without verifying resource exists
173
+ - Composed instructions, prompts, system messages, or rule sets that vary by mode/role/context — unconditional clauses can contradict mode-specific directives (e.g., "always cite sources inline" combined with a `draft` mode that asks for "no preamble, no commentary"). Build the composition conditionally — include each block only for modes that want it — or define an explicit precedence so contradictions are predictable
174
+
175
+ **UX integrity (single-component)**
176
+ - Unsaved changes / dirty state silently discarded when the user switches context in a multi-record editor or closes a sheet — data loss. Dirty-check on switch (inline confirm), auto-save drafts, or disable the switch control while dirty. `beforeunload` does not cover in-app context switches
122
177
 
123
178
  **AI-generated code quality**
124
179
  - New abstractions, wrapper functions, helper files serving only one call site — inline instead
@@ -126,6 +181,7 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
126
181
  - Commit messages claiming a fix while the bug remains
127
182
  - Placeholder comments (`// TODO`, `// FIXME`) or stubs presented as complete
128
183
  - Unnecessary defensive code for scenarios that provably cannot occur
184
+ - Cleanup callbacks (useEffect return, finalizer, dispose, signal handler) containing only comments are misleading — implement the cleanup or remove the callback entirely
129
185
 
130
186
  **Configuration & hardcoding**
131
187
  - Hardcoded values when config/env var exists; dead config fields; unused function parameters
@@ -149,6 +205,7 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
149
205
  - Missing tests for trust-boundary enforcement
150
206
  - Tests exercising code paths the integration layer doesn't expose — pass against mocks but untriggerable in production
151
207
  - Test mock state leaking between tests — "clear" resets invocation counts but not configured behavior; use "reset" variants
208
+ - Response/status assertions written as loose ranges (`status >= 400`, `status < 500`, `ok: false`) — a regression that turns a 400 validation failure into a 500 still passes. Assert the specific expected status so tests distinguish validation from server failure
152
209
 
153
210
  **Automated pipeline discipline**
154
211
  - Internal code review must run before creating PRs — never go straight from "tests pass" to PR
@@ -157,7 +214,7 @@ For each changed file, read the **ENTIRE file** (not just diff hunks). New code
157
214
 
158
215
  **Style & conventions**
159
216
  - Naming and patterns inconsistent with rest of codebase
160
- - New content not matching existing indentation, bullet style, heading levels
217
+ - New content not matching existing indentation, bullet style, heading levels. Within a single structured file (changelog, README, TOML config), section headers must be unique — duplicate `## Fixed` blocks or repeated table sections are a merge artifact that splits content downstream tools expect to find under one header. Consolidate
161
218
  - Shell instructions with destructive operations not verifying preconditions first
162
219
 
163
220
  ## Output Format
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slash-do",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "Curated slash commands for AI coding assistants — Claude Code, OpenCode, Gemini CLI, and Codex",
5
5
  "author": "Adam Eivy <adam@eivy.com>",
6
6
  "license": "MIT",
package/uninstall.sh CHANGED
@@ -23,8 +23,8 @@ banner() {
23
23
  }
24
24
 
25
25
  COMMANDS=(
26
- better better-swift fpr goals help omd
27
- pr push release replan review rpr update
26
+ better better-swift depfree fpr goals help omd
27
+ pr pr-better push release replan review rpr scan update
28
28
  )
29
29
 
30
30