declick 0.3.0
remove <name> <verb>now resolves the verb before touching disk: exit 2 for an unknown verb, exit 1 for a spec-backed engine (openapi verbs come from the spec, not per-verb files; rebuild with--verbsinstead), and--forceis required to delete the last desktop recipe (it would otherwise delete the whole adapter silently). The response for the last-verb case carriesadapterRemoved: true.--dry-runworks on every management command that writes:add,build,accept,import,skill,remove,path --install,desk arm|disarm. It compiles, lints and previews without writing anything, and setsmeta.dryRun: true.author,repairanduihave no preview (they drive a live app or a server) and refuse--dry-runwith an error, as doesadd --goalwithout--recipes.- Row projection:
--rows <path>unwraps a dotted array inside a response object (meta.rowsnames the path used,meta.extracarries the sibling fields such as a cursor or total). Without--rows, a verb whose spec says where its rows live (returns.rowsPath) auto-unwraps them when--fieldsor--limitis passed;describe,manifestand other non-verb payloads are never auto-unwrapped. --fieldsnow takes dotted paths (--fields error.code,items.0.name) resolved per row. A field list that matches nothing on any row is exit 1 naming the available top-level keys; a partial miss is reported inmeta.unknownFieldsinstead of failing.- openapi verbs carry a compiled
verb.returns({shape: 'array'|'object'|'scalar'|'none', fields, rowsPath?}) read from the first 2xx (ordefault) JSON response schema, capped at 30 fields withtruncated: true.describe --fullprints it as a->line;describe --jsonincludes it on every verb (nullwhen the spec has no response schema). Desktop verbs get a minimalreturns: {shape:'text', from:<read alias>}when the recipe declares one. importrefuses to silently replace an adapter that already exists under a differentsource,engineorbaseUrl: exit 1 naming what differs (data.diff), unless--force. The whole import is transactional: a mid-import failure rolls back only what that import created, leaving a prior adapter of the same name untouched.add/buildpreflight the launcher and skill name before writing anything, for the same reason.- Manifest validation (
declick lint, and everyadd/build/import) now rejects asource,window,baseUrl, arg name/description, flag name/description,returns.rowsPath/field name, orauth.enventry that spans multiple lines, contains a backtick, starts with#, or exceeds its length bound. This is the rule already applied to verb descriptions, now applied everywhere spec or bundle text reaches an agent. - SKILL.md generation is fence-safe: any
`` in an embedded description can no longer close the surrounding fenced block.writeSelfSkillno longer overwrites a hand-written `declick` skill in a skill dir; it only writes dirs where that file is absent or already carries the `Generated by declick` marker. - Seven new engines, all built in with no new dependency:
mcp(stdio and streamable http),web(a real browser over CDP; a miss returns the page's elements, never a screenshot),graphql,postman(postman v2.1 and insomnia v4),har,sqlite(tables and views become list/get/insert/update/delete plus a parameterizedquery), andcli(compiled from a tool's own--help). Swagger 2.0 and YAML specs compile through the openapi engine.declick engines --source <x>says where a source would land before anything is written;declick addnow also takes--host(which captured host is the API) and--url(the endpoint a GraphQL schema file does not carry). - New commands:
declick commandsanddeclick <cmd> --help(one row: flags, examples, whether it previews) render from the same table that generates the shippeddeclickskill, so the skill cannot drift from the CLI;declick auditreads the run log newest first;declick desk windows|tree|read|clipboardanddeclick web treereturn the desktop and a web page as data;declick import --exampleanddeclick manifest --schemaprint a valid bundle and the manifest field reference;declick describegained--grepand--offset;declick doctorseparatesblockingfromwarningsand probes each engine's tools. - Request flags on the HTTP engines:
--header,--base-url,--server,--content-type,--body-file,--output,--retry,--timeout,--verboseand--curl, listed bydescribe --full.--retryand--timeoutnow require a value instead of silently falling back to the default. - An api key that lives in the query string is masked in
--curland--verboseon live calls, the same as a header one; only the fetch itself sees the real value.--curlon a live multipart request now carries the body and its boundary content type instead of dropping both. - The cli engine quotes every argument it hands to a
.cmdor.battool, not only the ones containing a space: a value with&,|,>,<or^used to reach cmd.exe as a second command. Same fix for the mcp client's npx/npm shell path. - sqlite:
--limitis the output contract's flag, someta.countis the true row count andmeta.truncatedsays when there is more; a column named like a contract flag (limit,fields,output) is renamedparam-<name>and still reads and writes its own column, instead of making the whole table unaddressable. - A desktop recipe's
readstep re-resolves against a fresh tree before reading a property, so a read after aset,typeorclickreports what the action did instead of the value captured atfindtime. meta.credentialsnow recordsscopedToandsentTowhen a key is released across origins (--base-urlorDECLICK_ENV_ALLOW); the refusal on the blocked path no longer names the flag that would skip it.- Desktop recipes get a much larger step vocabulary:
read-all(every match of a path as rows),wait-for/wait-for-text(poll for an element or text up to a timeout),assert(compare a live value withequals/matches),clipboard get|set,dismiss(Escape),launch(start the app inline, or frommanifest.launchwhen the window is not open),scroll,expand,collapse,select,context(right-click),set(drive a toggle to a state), andoptional: trueon any step to skip instead of fail when its element is not there.declick desk windows|tree|read|clipboardexposes the same underlying reads as CLI commands. - Governance: once
DASHCLAW_API_KEYis set, strict is now the default: an unreachable, timed-out, or non-decision guard response is exit 3, not a warn-and-proceed (DECLICK_GUARD=openrestores the old fail-open behavior).DASHCLAW_URLhas no default endpoint and is required alongside the key. Every envelope carriesmeta.governance:{enabled,decision,reason}, and every invocation appends a redacted line to~/.declick/audit.jsonl(DECLICK_AUDIT=offto disable;declick auditreads it).declick uinow requires a per-startX-Declick-Tokenon every mutating POST. - deskclaw companion: declick 0.3 needs deskclaw 0.3.0 or newer for the attributed snapshot lines (
value=,toggle=,selected=,expanded=,offscreen=) the new read/assert steps depend on.
Install: npm i -g declick@0.3.0 · npm · declick.dev