@caseywebb/elmq-darwin-x64 0.0.0 → 0.8.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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +420 -0
  3. package/elmq +0 -0
  4. package/package.json +7 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Casey Webb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,420 @@
1
+ ---
2
+ update-when: CLI commands, output format, or installation steps change
3
+ ---
4
+
5
+ # elmq
6
+
7
+ A CLI for querying and editing Elm files — like jq for Elm.
8
+
9
+ Designed as a next-gen LSP for agents and scripts, not editors. Optimized for token efficiency and structured output.
10
+
11
+ > **Status:** Active development. Supports reading and writing Elm declarations, imports, and module lines, plus project-wide operations (rename, move, extract, add/remove variant). See [ROADMAP.md](ROADMAP.md) for what's planned.
12
+
13
+ > [!TIP]
14
+ > Curious why elmq exists and what it's trying to prove? Read [HYPOTHESIS.md](HYPOTHESIS.md) for the claim, the experimental design, and the threats to validity.
15
+
16
+ ## Install
17
+
18
+ ### Homebrew
19
+
20
+ ```sh
21
+ brew install caseyWebb/tap/elmq
22
+ ```
23
+
24
+ ### npm
25
+
26
+ ```sh
27
+ npm install -g @caseywebb/elmq
28
+ ```
29
+
30
+ Or run without installing:
31
+
32
+ ```sh
33
+ npx @caseywebb/elmq <command>
34
+ ```
35
+
36
+ ### From source
37
+
38
+ Requires [Rust](https://rustup.rs/):
39
+
40
+ ```sh
41
+ cargo install --path .
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ### Write-safety precondition
47
+
48
+ Every elmq command that mutates a `.elm` file — `set decl`, `patch`, `rm decl`, `add/rm import`, `expose`/`unexpose`, `mv`, `rename decl`, `move-decl`, `add/rm variant`, `set let`, `set case`, `rm let`, `rm case`, `rm arg`, `rename let`, `rename arg`, `add arg` — refuses to operate on a file that has pre-existing tree-sitter parse errors, and refuses to produce an output buffer that would not parse. If either check fires, elmq exits non-zero with a `refusing to edit …` or `rejected '<op>' write to …` message naming the file and the first error location, and the file on disk is left unchanged. Fix the file by hand (or with your editor) and retry. All write commands confirm success with `ok` output (sole exception: `rm variant` emits an actionable `references_not_rewritten` advisory section when the removed constructor appears in non-cleanly-rewritable positions). Read commands (`list`, `get`, `grep`, `refs`, `variant cases`) keep their existing tolerant behavior — they print a warning and continue so you can still inspect broken files.
49
+
50
+ ### File summary
51
+
52
+ ```sh
53
+ elmq list src/Main.elm
54
+ ```
55
+
56
+ ```
57
+ module Main exposing (Model, Msg(..), update, view) (38 lines)
58
+
59
+ imports:
60
+ Html exposing (Html, div, text)
61
+ Html.Attributes as Attr
62
+
63
+ type aliases:
64
+ Model L4-8
65
+
66
+ types:
67
+ Msg L11-15
68
+
69
+ functions:
70
+ update Msg -> Model -> Model L18-28
71
+ view Model -> Html Msg L31-34
72
+ helper L37-38
73
+ ```
74
+
75
+ ### With doc comments
76
+
77
+ ```sh
78
+ elmq list src/Main.elm --docs
79
+ ```
80
+
81
+ ```
82
+ type aliases:
83
+ Model L4-8
84
+ The model for our app
85
+
86
+ types:
87
+ Msg L11-15
88
+ Messages for the update function
89
+ ...
90
+ ```
91
+
92
+ ### Extract a declaration
93
+
94
+ ```sh
95
+ elmq get src/Main.elm update
96
+ ```
97
+
98
+ ```
99
+ update : Msg -> Model -> Model
100
+ update msg model =
101
+ case msg of
102
+ Increment ->
103
+ { model | count = model.count + 1 }
104
+
105
+ Decrement ->
106
+ { model | count = model.count - 1 }
107
+
108
+ Reset ->
109
+ { model | count = 0 }
110
+ ```
111
+
112
+ Includes doc comments and type annotations when present. Returns non-zero exit code if the declaration is not found.
113
+
114
+ Read across multiple files in one call with `-f`:
115
+
116
+ ```sh
117
+ elmq get -f src/Page/Home.elm update view -f src/Update.elm main
118
+ ```
119
+
120
+ Each `-f` group is a file followed by one or more names. Output is framed as `## Module.decl` blocks (falls back to `## file:decl` without `elm.json`).
121
+
122
+ ### Upsert a declaration
123
+
124
+ ```sh
125
+ echo 'helper x =
126
+ x + 42' | elmq set decl src/Main.elm
127
+ ```
128
+
129
+ Reads a full declaration from stdin, parses the name, and replaces the existing declaration (or appends if new). Use `--content` to pass the declaration inline instead of stdin:
130
+
131
+ ```sh
132
+ elmq set decl src/Main.elm --content 'helper x = x + 1'
133
+ ```
134
+
135
+ A name mismatch between the declaration source and the target is an error; use `rename decl` to rename instead of upsert.
136
+
137
+ ### Patch a declaration
138
+
139
+ ```sh
140
+ elmq patch src/Main.elm update --old "model.count + 1" --new "model.count + 2"
141
+ ```
142
+
143
+ Surgical find-and-replace scoped to a single declaration. The `--old` string must match exactly once.
144
+
145
+ ### Remove a declaration
146
+
147
+ ```sh
148
+ elmq rm decl src/Main.elm helper
149
+ ```
150
+
151
+ Removes the declaration, its type annotation, and doc comment. Cleans up excess blank lines.
152
+
153
+ ### Manage imports
154
+
155
+ ```sh
156
+ elmq add import src/Main.elm "Browser exposing (element)"
157
+ elmq rm import src/Main.elm Html
158
+ ```
159
+
160
+ `add import` inserts in alphabetical order or replaces an existing import with the same module name.
161
+
162
+ ### Manage exposing list
163
+
164
+ ```sh
165
+ elmq expose src/Main.elm update
166
+ elmq expose src/Main.elm "Msg(..)"
167
+ elmq unexpose src/Main.elm helper
168
+ ```
169
+
170
+ Granularly add or remove items from the module's exposing list. If the module has `exposing (..)`, `unexpose` auto-expands to an explicit list then removes the target. `expose` is a no-op when `exposing (..)`. Neither command ever produces `exposing (..)`.
171
+
172
+ ### Rename/move a module
173
+
174
+ ```sh
175
+ elmq mv src/Foo/Bar.elm src/Foo/Baz.elm
176
+ ```
177
+
178
+ ```
179
+ renamed src/Foo/Bar.elm -> src/Foo/Baz.elm
180
+ updated src/Main.elm
181
+ updated src/Page/Home.elm
182
+ ```
183
+
184
+ Renames the file, updates the module declaration, and rewrites all imports and qualified references (`Foo.Bar.something` -> `Foo.Baz.something`) across the project. Requires `elm.json` in a parent directory. Use `--dry-run` to preview changes without writing.
185
+
186
+ ### Rename a declaration
187
+
188
+ ```sh
189
+ elmq rename decl src/Main.elm helper newHelper
190
+ ```
191
+
192
+ ```
193
+ renamed helper -> newHelper
194
+ updated src/Main.elm
195
+ updated src/Page/Home.elm
196
+ ```
197
+
198
+ Renames a declaration (function, type, type alias, port, or variant) in the defining file and updates all references across the project — including qualified (`Module.helper`), aliased (`M.helper`), and exposed references. Requires `elm.json` in a parent directory. Use `--dry-run` to preview changes without writing.
199
+
200
+ ### Find references
201
+
202
+ ```sh
203
+ elmq refs src/Lib/Utils.elm
204
+ ```
205
+
206
+ ```
207
+ src/Main.elm:3
208
+ src/Page/Home.elm:5
209
+ src/Page/Settings.elm:3
210
+ ```
211
+
212
+ Find all files that import a module. Add a declaration name to find specific usage sites:
213
+
214
+ ```sh
215
+ elmq refs src/Lib/Utils.elm helper
216
+ ```
217
+
218
+ ```
219
+ src/Page/Home.elm:3: import Lib.Utils exposing (helper)
220
+ src/Page/Settings.elm:5: LU.helper config
221
+ src/Main.elm:7: Lib.Utils.helper model
222
+ ```
223
+
224
+ Resolves fully-qualified references (`Lib.Utils.helper`), aliased references (`LU.helper`), and explicitly-exposed names. Requires `elm.json` in a parent directory.
225
+
226
+ ### Move declarations between modules
227
+
228
+ ```sh
229
+ elmq move-decl src/Page/Home.elm --to src/Shared/Layout.elm viewHeader viewFooter
230
+ ```
231
+
232
+ ```
233
+ moved viewHeader
234
+ moved viewFooter
235
+ auto-included renderNav
236
+ updated src/Page/Home.elm
237
+ updated src/Shared/Layout.elm
238
+ updated src/Main.elm
239
+ ```
240
+
241
+ Moves declarations from one module to another, rewriting the declaration bodies to match the target file's import conventions (aliases, exposed names). Automatically includes unexposed helpers used only by the moved declarations. Creates the target file if it doesn't exist. Auto-upgrades the target to a `port module` when moving ports.
242
+
243
+ Use `--copy-shared-helpers` to duplicate (not move) helpers that are used by both moved and non-moved declarations. Use `--dry-run` to preview changes.
244
+
245
+ ### Add/remove type variant constructors
246
+
247
+ ```sh
248
+ elmq add variant src/Types.elm --type Msg "SetName String"
249
+ ```
250
+
251
+ ```
252
+ ok
253
+ src/Update.elm:22 update — inserted branch
254
+ src/View.elm:15 label — inserted branch
255
+ src/Main.elm:31 update — skipped (wildcard branch covers new variant)
256
+ ```
257
+
258
+ Appends a constructor to a custom type and inserts `Debug.todo` branches in all matching case expressions project-wide. Case expressions with wildcard (`_`) branches are skipped with an info message.
259
+
260
+ To fill branch bodies in the same call, first survey the sites with `elmq variant cases`, then pass their keys to `--fill`:
261
+
262
+ ```sh
263
+ elmq variant cases src/Types.elm --type Msg
264
+ ```
265
+
266
+ ```
267
+ ## case sites for type Types.Msg (2 files, 2 functions)
268
+
269
+ ### src/Update.elm
270
+
271
+ #### update (key: update, line 12)
272
+ update : Msg -> Model -> Model
273
+ update msg model =
274
+ case msg of
275
+ Increment -> ...
276
+ Decrement -> ...
277
+
278
+ ### src/View.elm
279
+
280
+ #### label (key: label, line 8)
281
+ ...
282
+ ```
283
+
284
+ ```sh
285
+ elmq add variant src/Types.elm --type Msg "Reset" \
286
+ --fill 'update=Reset -> { model | count = 0 }' \
287
+ --fill 'label=Reset -> "reset"'
288
+ ```
289
+
290
+ `variant cases` is read-only and returns every case expression project-wide that matches the target type, with its enclosing function body (including type annotation) and a stable site key. Pass those keys to `--fill <key>=<branch_text>` (repeatable) on `add variant` to replace the default `Debug.todo "<Variant>"` stub with real branch bodies in the same call. Unmatched fill keys fail validation before any file is touched; unfilled sites fall back to `Debug.todo` stubs (graceful degradation).
291
+
292
+ When one function contains multiple case expressions on the same type, or two files both define a function with the same name, `variant cases` disambiguates with `function#N` or `file:function` keys. Passing an ambiguous bare key to `--fill` errors with the valid alternatives listed.
293
+
294
+ ```sh
295
+ elmq rm variant src/Types.elm --type Msg Decrement
296
+ ```
297
+
298
+ ```
299
+ ok
300
+ src/Update.elm:22 update — removed branch
301
+ src/View.elm:15 label — removed branch
302
+ ```
303
+
304
+ Removes a constructor and its matching branches from all case expressions — including nested patterns like `Just Decrement -> ...`. Errors if removing the last variant (use `elmq rm decl` instead). Use `--dry-run` to preview changes.
305
+
306
+ When the constructor is also used outside case branches (expression position, refutable patterns in function/lambda/let arguments), `rm variant` emits a `references_not_rewritten` advisory section listing every such site with its file, line, enclosing declaration, and classification so the agent can fix them by hand before running `elm make`:
307
+
308
+ ```
309
+ ok
310
+ src/Update.elm:47 update — removed branch
311
+
312
+ references_not_rewritten (2):
313
+ src/Init.elm:15 init expression-position
314
+ init = ( Model 0, Cmd.map Wrap (Increment 1) )
315
+ src/Debug.elm:8 debugMsg expression-position
316
+ debugMsg m = m == Increment 0
317
+ run `elm make` to confirm and fix these before continuing
318
+ ```
319
+
320
+ The advisory is the *same data* surfaced by `elmq refs` (see below), included in the rm output so the removal loop is one or two `elmq` touches at most — don't chain `elmq refs` into the rm flow.
321
+
322
+ ### Audit constructor references
323
+
324
+ The regular `elmq refs` command auto-routes on what the name is. For top-level declarations it emits a flat list of call sites; for a constructor of a custom type declared in the target file it emits a **classified** report:
325
+
326
+ ```sh
327
+ elmq refs src/Types.elm Increment
328
+ ```
329
+
330
+ ```
331
+ Msg.Increment — 3 references (1 clean, 2 blocking)
332
+ src/Update.elm
333
+ 47 update case-branch
334
+ Increment ->
335
+ src/Init.elm
336
+ 15 init expression-position
337
+ init = ( Model 0, Cmd.map Wrap (Increment 1) )
338
+ src/Debug.elm
339
+ 8 debugMsg expression-position
340
+ debugMsg m = m == Increment 0
341
+ ```
342
+
343
+ Walks the entire project and classifies every reference by its syntactic role: `case-branch` and `case-wildcard-covered` are "clean" (what `rm variant` would rewrite); `function-arg-pattern`, `lambda-arg-pattern`, `let-binding-pattern`, and `expression-position` are "blocking" (what `rm variant` would leave for the agent). Use it to audit whether a constructor is still needed, to plan a rename, or to understand the blast radius of a type change — independent of any removal flow. `--format json` emits `total_sites`, `total_clean`, `total_blocking`, and a flat `sites` array with `file`, `line`, `column`, `declaration`, `kind`, and `snippet` per entry.
344
+
345
+ Decl and constructor names can be mixed in a single `elmq refs` call; each is framed under its own `## <arg>` header.
346
+
347
+ ### Search Elm sources
348
+
349
+ ```sh
350
+ elmq grep "Http\.get"
351
+ ```
352
+
353
+ ```
354
+ src/Api.elm:42:fetchUser: Http.get { url = userUrl, expect = Http.expectJson GotUser decoder }
355
+ src/Page/Home.elm:88:init: Http.get { url = feedUrl, expect = Http.expectJson GotFeed feedDecoder }
356
+ ```
357
+
358
+ Regex search over Elm files (Rust `regex` dialect, same as ripgrep) that annotates each hit with its **enclosing top-level declaration** — the discovery entry point that feeds into `elmq get`. Use `-F` for literal matching and `-i` for case-insensitive. Matches inside `--` / `{- -}` comments and string literals are filtered by default; pass `--include-comments` or `--include-strings` to opt back in independently.
359
+
360
+ Project discovery walks up for `elm.json` and honors its `source-directories`; if no `elm.json` is found, falls back to recursively walking the CWD. Both paths honor `.gitignore`. Exit codes match ripgrep: `0` on matches, `1` on none, `2` on error.
361
+
362
+ Two additional flags enable one-call definition lookup and source retrieval:
363
+
364
+ - `--definitions` — only emit matches at the declaration name site (filters out call sites)
365
+ - `--source` — emit full declaration source for each matched decl, deduped by `(file, decl)`. Output is framed `## Module.decl` (single result stays bare).
366
+
367
+ Combine them for definition lookup: `elmq grep --definitions --source 'update'` returns the full source of the `update` declaration without any call-site noise.
368
+
369
+ Pipe into `elmq get` for a find-then-retrieve workflow:
370
+
371
+ ```sh
372
+ elmq grep --format json "Http\.get" \
373
+ | jq -r 'select(.decl) | "\(.file) \(.decl)"' \
374
+ | sort -u \
375
+ | while read file decl; do elmq get "$file" "$decl"; done
376
+ ```
377
+
378
+ Matches that land outside any top-level declaration (imports, module header) report `decl: null` in JSON and an empty decl slot in compact output.
379
+
380
+ ### Agent integration guide
381
+
382
+ ```sh
383
+ elmq guide
384
+ ```
385
+
386
+ Prints the built-in agent integration guide to stdout. This is the guide that tells LLM coding agents how to use elmq effectively — when to prefer `elmq get` over `Read`, how to chain edits, etc. The Claude Code plugin (`/plugin install elmq@caseyWebb`) uses this automatically via a SessionStart hook.
387
+
388
+ ### JSON output
389
+
390
+ ```sh
391
+ elmq list src/Main.elm --format json
392
+ ```
393
+
394
+ ```json
395
+ {
396
+ "module_line": "module Main exposing (Model, Msg(..), update, view)",
397
+ "imports": ["Html exposing (Html, div, text)"],
398
+ "declarations": [
399
+ {
400
+ "name": "update",
401
+ "kind": "function",
402
+ "type_annotation": "Msg -> Model -> Model",
403
+ "start_line": 18,
404
+ "end_line": 28
405
+ }
406
+ ]
407
+ }
408
+ ```
409
+
410
+ ## Using elmq with LLM coding agents
411
+
412
+ elmq is designed to be used from any coding agent that can shell out to a CLI (Claude Code, Cursor, Aider, Codex, etc.). The built-in agent guide (`elmq guide`) tells agents how to use elmq effectively.
413
+
414
+ **Claude Code**: Install the plugin with `/plugin install elmq@caseyWebb`. It automatically injects the guide into sessions working in Elm projects.
415
+
416
+ **Other agents**: Pipe `elmq guide` into your agent's system prompt or project instructions.
417
+
418
+ ## Roadmap
419
+
420
+ See [ROADMAP.md](ROADMAP.md) for the phased development plan.
package/elmq ADDED
Binary file
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@caseywebb/elmq-darwin-x64",
3
- "version": "0.0.0",
3
+ "version": "0.8.0",
4
4
  "description": "elmq binary for macOS x64",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/caseyWebb/elmq.git"
9
9
  },
10
- "os": ["darwin"],
11
- "cpu": ["x64"]
10
+ "os": [
11
+ "darwin"
12
+ ],
13
+ "cpu": [
14
+ "x64"
15
+ ]
12
16
  }