{"_id":"@ademu/adc-client","_rev":"2-656cc68b1982cb2cbb94cd0f6f0b7def","name":"@ademu/adc-client","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@ademu/adc-client","version":"0.1.0","author":{"url":"https://ademu.com","name":"Ademú","email":"npm@ademu.com"},"license":"(MIT OR Apache-2.0)","_id":"@ademu/adc-client@0.1.0","maintainers":[{"name":"marios_ademu","email":"npm@ademu.com"}],"homepage":"https://ademu.com","dist":{"shasum":"a3937b44950bc19a3d8a63b5e8bc8d4a68207d05","tarball":"https://registry.npmjs.org/@ademu/adc-client/-/adc-client-0.1.0.tgz","fileCount":50,"integrity":"sha512-4S5IgIStV9o5U28ZV+djJw7DvD9eNkMEFAysxv3acaONpjWQGT1pfcDuSqkO+QIvYykjeGgGdP3nFo3iKb9sqA==","signatures":[{"sig":"MEYCIQCazBWdGpHNl29D7nYpoTFkWp8ylu15Tf86vORR9BtM8wIhAKW7ua79iMUB5KCD8US3GgqKS3uO/hGd72hssrDYe33Q","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":240495},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./internal":{"types":"./dist/internal.d.ts","import":"./dist/internal.js"}},"gitHead":"8e0c1ca4510920122e2abbd2360f9ae25677b7fc","scripts":{"test":"tsc && tsc -p tsconfig.typetests.json && tsc -p tsconfig.examples.json && node --test test/*.test.mjs","build":"tsc","prepack":"cp ../../PROTOCOL.md ./PROTOCOL.md","build:examples":"tsc -p tsconfig.examples.json --noEmit false --outDir examples-dist"},"_npmUser":{"name":"marios_ademu","email":"npm@ademu.com"},"_npmVersion":"11.19.0","description":"TypeScript session client for the ADC daemon's device-session protocol (PROTOCOL.md, Part I — shipped in this tarball) — the mind-side library.","directories":{},"_nodeVersion":"24.20.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.2","@types/node":"^20.19.0"},"_npmOperationalInternal":{"tmp":"tmp/adc-client_0.1.0_1788444801726_0.8942544773745862","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ademu/adc-client","version":"0.1.1","description":"TypeScript session client for the ADC daemon's device-session protocol (PROTOCOL.md, Part I — shipped in this tarball) — the mind-side library.","type":"module","license":"(MIT OR Apache-2.0)","author":{"name":"Ademú","email":"npm@ademu.com","url":"https://ademu.com"},"homepage":"https://ademu.com","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./internal":{"types":"./dist/internal.d.ts","import":"./dist/internal.js"}},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build":"tsc","build:examples":"tsc -p tsconfig.examples.json --noEmit false --outDir examples-dist","prepack":"cp ../../PROTOCOL.md ./PROTOCOL.md","test":"tsc && tsc -p tsconfig.typetests.json && tsc -p tsconfig.examples.json && node --test test/*.test.mjs"},"devDependencies":{"@types/node":"^20.19.0","typescript":"^5.9.2"},"_id":"@ademu/adc-client@0.1.1","_integrity":"sha512-gPBlHh9poHsp6IDUwArQ0EOH+zNuInHKIY7cNoLksHt10rOov/F0A4V70qYvgRHbgVg2pYFw5uyElIrQbjJYvQ==","_resolved":"/home/runner/work/_temp/tarballs/ademu-adc-client-0.1.1.tgz","_from":"file:/home/runner/work/_temp/tarballs/ademu-adc-client-0.1.1.tgz","_nodeVersion":"24.20.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-gPBlHh9poHsp6IDUwArQ0EOH+zNuInHKIY7cNoLksHt10rOov/F0A4V70qYvgRHbgVg2pYFw5uyElIrQbjJYvQ==","shasum":"21ad94e1a1f369efa1582188762f5990e952e265","tarball":"https://registry.npmjs.org/@ademu/adc-client/-/adc-client-0.1.1.tgz","fileCount":50,"unpackedSize":240495,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQClwrr3nFS5upvkqsu2XXkgri9tCQQv+4tOjY9sZgPraAIhAKgAfyGz35mbJ8IhNqT5gBAun/bY/uYd6+U7uHHUfF/J"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:87e2a1af-1992-46f6-b28b-13ae14c70f5c"}},"directories":{},"maintainers":[{"name":"marios_ademu","email":"npm@ademu.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/adc-client_0.1.1_1788446995667_0.021129915815011113"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T14:13:21.429Z","modified":"2026-09-03T14:49:55.946Z","0.1.0":"2026-09-03T14:13:21.863Z","0.1.1":"2026-09-03T14:49:55.804Z"},"author":{"name":"Ademú","email":"npm@ademu.com","url":"https://ademu.com"},"license":"(MIT OR Apache-2.0)","homepage":"https://ademu.com","description":"TypeScript session client for the ADC daemon's device-session protocol (PROTOCOL.md, Part I — shipped in this tarball) — the mind-side library.","maintainers":[{"name":"marios_ademu","email":"npm@ademu.com"}],"readme":"# @ademu/adc-client\n\nThe TypeScript session client for the ADC daemon's device-session protocol — the mind-side\nlibrary. **`PROTOCOL.md` (Part I; shipped alongside this README in the tarball, `adc/PROTOCOL.md`\nin the repository) is the contract; this library is one consumer of it and cites it, never\nsubstitutes for it.** It is conformance-tested against the same golden fixture\nthat pins the daemon (`adc/adc-proto/tests/fixtures/ipc_v1.ndjson`), so it structurally cannot\ndrift.\n\nZero runtime dependencies (node stdlib only), ESM, strict TypeScript, `engines.node >= 20`.\n\n## Install\n\n```sh\nnpm i @ademu/adc-client\n```\n\nPublished on npm from a private monorepo, so the tarball is self-sufficient: `dist/` (ESM +\n`.d.ts` + source maps), `src/` (the TypeScript the maps point at), `PROTOCOL.md` (the contract\nthis README cites — Part I is the session protocol), `README.md`, `LICENSE-MIT` + `LICENSE-APACHE`.\nReleases are cut by tag (`clients-v<semver>`) and published by CI via npm Trusted Publishing — no\nstored or long-lived npm token exists anywhere. Verify a tarball's contents with `npm pack @ademu/adc-client && tar tzf\nademu-adc-client-*.tgz`. Release procedure for maintainers: `docs/RELEASING_NPM.md`.\n\n## Quickstart\n\n```ts\nimport { connect } from '@ademu/adc-client';\n\nconst client = await connect({ token: process.env.ADC_TOKEN! });\nconsole.log(client.hello.device_id, client.hello.last_acked_seq);\n\nfor await (const ev of client.events()) {\n  if (ev.known && ev.event === 'message_received') {\n    await client.sendText({ group_id: ev.group_id, body: `echo: ${ev.body}` });\n    client.ackThrough(ev); // ONLY after your handling durably succeeded\n  } else {\n    client.ackThrough(ev);\n  }\n}\n```\n\n`examples/echo.ts` is the runnable version (`npm run build:examples`, then\n`ADC_TOKEN='adc1_…' node examples-dist/examples/echo.js`).\n\n## Acks carry read-receipt weight — there is no auto-ack\n\nAn `ack {seq}` cumulatively marks every durable event ≤ `seq` as handed off, and handed-off\n**fires read receipts to the humans in the conversation** (PROTOCOL.md §The seq/ack contract,\nrider R3 — agents have no read-receipt opt-out). That is why this library never acks on its own\nand never will: call `ack(seq)` / `ackThrough(event)` yourself, after YOUR handling durably\nsucceeded — not on receipt. The cursor lives daemon-side (`hello.last_acked_seq`); the client\npersists nothing.\n\n## Requests, and the ambiguous-outcome discipline\n\n`request(op, params?, {timeoutMs})` correlates replies strictly by id (pipelining is legal);\nthe twelve typed wrappers (`sendText` … `searchMessages`) are TRANSPARENT — each only names the\nop, types the params/reply, and delegates, enforced by test. `request()` stays public as the\nforward-compatibility escape hatch: the surface is additive-forever and this client is a\nsnapshot — a newer daemon's ops are reachable via `request` + a `client.capabilities.has(op)`\ncheck without waiting for a package update. Wrappers do NOT pre-check capabilities (no hidden\nlogic).\n\n**A rejected command promise does not mean the command failed.** A command can become durable\nbefore its reply is written, so `DetachedError` and `RequestTimeoutError` are OUTCOME-UNKNOWN:\nreconcile via queries (`getMessages`, `getMessageStatus`) before retrying side-effecting ops, and\nnever blind-auto-retry commands. The daemon silently drops malformed/unknown requests (no error\nreply — PROTOCOL.md §Commands and queries), so a timeout's likeliest causes are an op this daemon\ndoesn't serve (check `capabilities`) or a malformed request shape.\n\n## Reconnect semantics\n\n`reconnect: 'auto'` (the default) survives daemon restarts: on post-seat EOF the client backs off\n(full jitter, 200 ms base, 5 s cap), re-resolves the socket path (an explicit `socketPath` stays\npinned verbatim), re-authenticates, and the daemon replays un-acked durable events into the SAME\n`events()` stream. `ECONNREFUSED` and `ENOENT` are both transient (the restart window —\nPROTOCOL.md §Reconnect & liveness). Terminal: `invalid_token`, `device_not_ready`, and\n`already_attached` (the last after a bounded grace of 3 fixed-delay retries, because a fast\nre-attach can race the daemon's EOF processing of your old channel).\n\n**Takeover is one-shot.** `takeover: true` applies to the initial `connect()` only; reconnects\nalways re-auth with `takeover: false` — a displaced client must not evict the newer legitimate\nholder (and two auto-reconnecting takeover clients would ping-pong forever). The wedged-holder\nrecipe (RUNBOOK §Token lifecycle): start a NEW client with `takeover: true`; the wedged holder\nsees plain EOF.\n\nNo heartbeat exists and none should be added — liveness is \"read until EOF\". The client reads\neagerly and buffers events in memory without bound: the daemon auto-detaches a mind whose socket\nstays blocked for 5 s, so pacing socket reads by consumer pull would be strictly worse; pace your\nHANDLING (and thus your acks), not the reads.\n\n## Socket path resolution\n\nThe daemon's hardened ladder, ported exactly (PROTOCOL.md §Resolving the session socket path):\n`$ADC_SESSION_SOCKET_PATH` → gated `$XDG_RUNTIME_DIR` (never on macOS) → `$ADC_DATA_DIR` verbatim\n→ the XDG data chain. Never probes candidates; joins verbatim. **Deliberately omitted:** the two\nconfig-file rungs (`[daemon] session_socket_path` and `[daemon] data_dir`) — this library is\nzero-dependency and parses no TOML. If your daemon's socket moved via config, pass `socketPath`\nor set `ADC_SESSION_SOCKET_PATH`; a reachable daemon's `daemon_info.session_socket_path` is\nalways the authority (`adc doctor` prints it).\n\n## `@ademu/adc-client/internal` — for sibling packages only\n\nThe `./internal` subpath export carries the NDJSON framing layer (`LineDecoder`, `encodeFrame`,\nthe two byte caps) for sibling `@ademu` packages — today `@ademu/adc-control`. It is **internal\nand semver-exempt**: anything there may change or vanish in any release without a major bump.\nApplications import from the root export only. The framing errors (`LineTooLongError`,\n`ProtocolViolationError`) stay on the root export so `instanceof` identity is shared everywhere.\n\n## Error taxonomy\n\n| Error | When | Terminal for auto-reconnect? |\n| --- | --- | --- |\n| `InvalidTokenError` | reject `invalid_token` (deliberately undifferentiated — no oracle) | yes |\n| `DeviceNotReadyError` | reject `device_not_ready`: the device is not `enrolled`. Tokens can exist for a not-yet-enrolled device — if enrollment is mid-flight, retry with a fresh `connect()` after `adc agent add` completes. | yes (fail-fast by design) |\n| `AlreadyAttachedError` | reject `already_attached` with `takeover:false` | initial: immediately; reconnect: after the bounded grace |\n| `HandshakeClosedError` | EOF before the hello, no reject line (timeout/oversize/internal — ambiguous BY DESIGN) | transient |\n| `HandshakeTimeoutError` | no hello within 10 s. Attachment outcome UNKNOWN: the daemon may still process the queued attach late; a fresh connect may briefly see `already_attached`. | transient |\n| `DetachedError` | the session ended (`reason: 'eof' | 'closed' | 'reconnecting'`); carries `{op, id}` for in-flight requests — outcome unknown | n/a |\n| `RequestError` | an `ok:false` reply; branch on `.code`. The daemon's debug text is a deliberate read via non-enumerable `.detail` — it never reaches `err.message`, `JSON.stringify`, or `util.inspect` | n/a |\n| `RequestTimeoutError` | no reply within the deadline (default 30 s) — outcome unknown | n/a |\n| `LineTooLongError` | outbound: refused pre-write (the daemon reads ≤ 1 MiB/line); inbound: over the 64 MiB library safety guard | inbound: yes |\n| `ProtocolViolationError` | the peer sent what a correct daemon never sends (malformed JSON, illegal root, invalid UTF-8) | yes — it may not be the daemon at all |\n\n## Testing\n\n`npm test` = strict compile + compile-time type fixtures (`test/types/`) + example type-check +\n`node:test` suites, including the golden-fixture conformance suite (`test/fixture.test.mjs`) —\nevery mind-facing fixture line, decode and reproduce classes, unknown-tolerance legs. CI:\n`.github/workflows/js.yml` (node 20 + current LTS). The manual live-daemon lane is\n`integration/live-daemon.sh` (deliberately outside `test/`).\n","readmeFilename":"README.md"}