declick 0.5.0
Every item the 0.3.0 gap audit deferred except the macOS/Linux desktop backend. 566 tests pass.
compose, a tenth engine: a chain of verbs from adapters you already built becomes one verb with one envelope, so an agent stops re-deriving the same two or three calls every session.declick add compose:./chain.json --name ops, ordeclick compose ops --steps ./chain.json(-reads stdin and keeps a copy the adapter owns, sodeclick build opsstill works);declick compose opsprints the chain step by step. A chain file is{"compose": true, "verbs": [{name, description, args, flags, steps, returns}]}; a step is{"run": "<adapter> <verb> {arg}", "as": "name", "optional": false}withruna shell-style string or an argv array. Templates read the composite's arguments and flags ({id}) and earlier steps' data ({pet.owner.name}). Every step runs as its owndeclickcommand in a child process, so it keeps its own governance decision, credentials, flag defaults and audit line; a mutating chain is put to DashClaw once for the composite and once per mutating step.declick addrefuses a chain naming an adapter or verb that is not there, a template that names nothing, or areturnsthat points at no step. A failing step stops the chain with that step's exit code andstep <i> (<adapter> <verb>): <error>, withdata.stepscarrying everything that already ran;--dry-runpreviews every step and sends nothing; a chain that calls itself stops at eight levels deep.--each <file|->on any verb: run it once per item in a file of inputs, sequentially, and get one envelope back. NDJSON, a JSON array, or stdin; an item is{"args": [...], "flags": {...}}or a flat object of the verb's arg and flag names. Command-line args and flags are the default for every item and the item overrides per key, except--dry-run, which an item may turn on and never off.datais one entry per item (input,ok,exit,dataorerror) in input order, each shaped by its own--fields,--limitand--rows;metacarriescount,failedandeach: true. Every item is guarded on its own; a failing item does not stop the rest, a blocked item does (the entries behind it readnot run: item N was blocked, exit 3). Exit 0 when every item is ok, otherwise the first failing item's code. A missing file, a line that is not JSON or an item that is neither shape is exit 1 naming the line, and nothing runs.- Per-adapter flag defaults in
~/.declick/<name>/defaults.json:{"*": {"limit": 20, "fields": "id,name"}, "find-pets-by-status": {"status": "sold"}}. The*scope applies to every verb, a verb scope wins over*, a flag typed on the command line wins over both; values are parsed exactly like the tokens they stand for.meta.defaultslists the keys a run took from the file anddeclick describeprints them on one line. The file sits besidemanifest.json, sodeclick buildnever clobbers it. A key the verb does not accept is exit 1 naming the file and the key; a file that is not valid JSON is exit 1 naming the--clearthat fixes it, and leavesdescribe,lintandbuildworking.declick defaults <name> [--verb v] [--set k=v] [--unset k] [--clear] [--dry-run]prints or edits it, and every--setis checked against the flags that scope accepts.--no-defaultsandDECLICK_DEFAULTS=offskip the file. policy.json: a local per-verb policy that needs no service.$DECLICK_HOME/policy.json(orDECLICK_POLICY) holdsrules, each anadapterglob, averbglob, an optionalmutatingfilter, adecisionofallow,warnorblockand an optionalreason. First match wins; no file and no match are both allow. Ablockis exit 3 withblocked by policy: <reason>before anything is sent, including on read-only verbs, which never reached the guard before. Awarnwrites one stderr line and runs, and still defers to DashClaw when a key is set.--dry-runnever consults it. The file fails closed: unreadable JSON, a bad decision, arulesthat is not an array or an unknown field makes every run exit 1 naming the file.declick policy [--check <adapter> <verb>] [--example]shows the rules, which one wins for a verb, and an example file.meta.governance.sourceis"policy"when the local file decided, on the envelope and the audit line.declick web text <url> [--selector css] [--grep re] [--limit N]: the page's visible text as numbered lines, so "does the page say X" is one call with an exit code (2 when nothing matches) instead of a page dump.declick web treetakes the same--grep, tested againstrole:nameandhref. The setup rules block and the Claude Code hook now point at it instead ofcurl | grep -c.- An openapi verb whose response is
text/event-streamis read as it arrives instead of buffered whole:datais an array of parsed events ({event?, id?, data}, JSON payloads parsed) andmeta.streamcarries{events, complete, truncatedByTimeout, ms}. When the timeout budget runs out mid-stream, the events already received come back withmeta.truncated: trueand exit 0 instead of a timeout with nothing. declick setupnever overwrites an adapter that already exists under the name it would pick: a server whose plain name collides falls back to<name>-mcponly when that name is free, otherwise it is skipped naming the adapter and its source. A bearer needed on the fallback attempt is reported asneeds <TOKEN> in the vault, not as a collision. The bin dir lands on the running process's PATH once installed, so setup no longer printsadd to PATH oncefor every adapter it builds.- The runtime's per-invocation work (flag check, policy, governance, credential scoping, the engine call) moved into one function, so
--eachand compose steps run the identical path. No change to what a single run answers.eachanddefaultsare reserved flag names now: a verb parameter called either is renamedparam-each/param-defaultson the next build.
Install: npm i -g declick@0.5.0 · npm · declick.dev