{"_id":"@adhd/sox-registry","_rev":"2-871c150e0effaac3a642dfc9c2a6c994","name":"@adhd/sox-registry","dist-tags":{"latest":"0.2.1"},"versions":{"0.2.0":{"name":"@adhd/sox-registry","version":"0.2.0","license":"MIT","_id":"@adhd/sox-registry@0.2.0","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"715d2d61c69836a9deed4b588d9832c9078f1a1f","tarball":"https://registry.npmjs.org/@adhd/sox-registry/-/sox-registry-0.2.0.tgz","fileCount":6,"integrity":"sha512-Hj7wtGCFKXl4Jzvy5gMEQq0SdMM/qNgWXZhWQfmnqMf+K5v98hZCkuiPmorecjN1kzR5iAeA/9tMJMutwb7k0A==","signatures":[{"sig":"MEUCIHjfYkGxO4+m9FNdZOgizu02Q3/63b4Ui45QKbMseLJSAiEAnmZnJkIyYPgB6daGUoh9rZQkOVOndrmJoJsP2ogMlcA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":18313},"main":"./dist/index.js","_from":"file:adhd-sox-registry-0.2.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/1c381ab8815a2e9c6dc0d08fac9950a2/adhd-sox-registry-0.2.0.tgz","_integrity":"sha512-Hj7wtGCFKXl4Jzvy5gMEQq0SdMM/qNgWXZhWQfmnqMf+K5v98hZCkuiPmorecjN1kzR5iAeA/9tMJMutwb7k0A==","_npmVersion":"11.6.2","description":"Sox registry — drift gate, index, checksum","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sox-registry_0.2.0_1782451185761_0.14805394522882076","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@adhd/sox-registry","version":"0.2.1","description":"Sox registry — drift gate, index, checksum","license":"MIT","publishConfig":{"access":"public"},"engines":{"node":">=20"},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"keywords":["registry","drift","index","checksum","typescript"],"repository":{"type":"git","url":"git+https://github.com/PseudoSky/adhd.git"},"homepage":"https://github.com/PseudoSky/adhd","_id":"@adhd/sox-registry@0.2.1","bugs":{"url":"https://github.com/PseudoSky/adhd/issues"},"_integrity":"sha512-4ky3eWt9Udm7Eew2S5Pv0Qe/wXlQhys1TdU49pC6DAALsHhWq5/FByADE1jwk8+YYNWXMGJUfbu3ZQr/nhDhAQ==","_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/49a1fde2071b68ba83136745f50ae15f/adhd-sox-registry-0.2.1.tgz","_from":"file:adhd-sox-registry-0.2.1.tgz","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-4ky3eWt9Udm7Eew2S5Pv0Qe/wXlQhys1TdU49pC6DAALsHhWq5/FByADE1jwk8+YYNWXMGJUfbu3ZQr/nhDhAQ==","shasum":"9e77bc321414c1d4e2f3f9cd51dce0d1e54432ba","tarball":"https://registry.npmjs.org/@adhd/sox-registry/-/sox-registry-0.2.1.tgz","fileCount":8,"unpackedSize":25299,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHg5GXX/SEbUGU3I55Tp54R38ikywxaF6DZB62MfrtbMAiEAhP6tI7BMw2lhYmMt2nFzZRLSagi6JOswU4hdiNi0FZ8="}]},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"directories":{},"maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sox-registry_0.2.1_1788566487785_0.06592800139028099"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-26T05:19:45.642Z","modified":"2026-09-05T00:01:28.089Z","0.2.0":"2026-06-26T05:19:45.879Z","0.2.1":"2026-09-05T00:01:27.927Z"},"license":"MIT","description":"Sox registry — drift gate, index, checksum","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"readme":"# @adhd/sox-registry\n\nDrift detection for a JSON extension index. It loads `registry/index.json` from a repo root, compares it against the extension manifests actually found on disk, and reports three kinds of mismatch — entries that were removed without a rebuild (**stale**), entries that were added without a rebuild (**unindexed**), and entries whose source file changed without a checksum update (**mutated**). It also ships the sha256 checksum helpers the index itself is built from.\n\n```bash\npnpm add @adhd/sox-registry\n```\n\n## Quick start\n\n```typescript\nimport { detectDrift, assertNoDrift } from '@adhd/sox-registry';\n\n// Non-throwing: inspect the report yourself.\nconst report = detectDrift('/path/to/repo');\nif (!report.ok) {\n  console.log('stale:', report.stale);         // in index, not on disk\n  console.log('unindexed:', report.unindexed); // on disk, not in index\n  console.log('mutated:', report.mutated);     // checksum mismatch\n}\n\n// Throwing: use directly as a CI gate.\nassertNoDrift('/path/to/repo');\n// throws Error('[registry] Drift detected — re-run ... ') when out of sync\n```\n\n## What it expects on disk\n\n`detectDrift(root)` reads two things under `root`:\n\n- **`registry/index.json`** — an array of `RegistryIndexEntry`, loaded via `loadIndex()`.\n- **`extensions/<type-dir>/<id>/extension.json`** — one manifest per extension. `<type-dir>` must be one of `agents`, `skills`, `mcp-servers`, `prompts`, `hooks`, `commands`, `bundles`; each manifest needs an `id` field (manifests with `private: true` are skipped, and manifests missing or with unparseable JSON are silently skipped rather than treated as drift).\n\nChecksum drift is only checked for entries whose `source` starts with `file://` — directory-sourced entries have no per-file checksum to compare.\n\n## API reference\n\n### Drift gate\n\n```typescript\ninterface DriftReport {\n  ok: boolean;           // true when stale/unindexed/mutated are all empty\n  stale: string[];       // extension ids in the index but not found on disk\n  unindexed: string[];   // extension ids on disk but not in the index\n  mutated: string[];     // extension ids whose disk checksum no longer matches the index\n}\n\nfunction detectDrift(root: string): DriftReport;\nfunction assertNoDrift(root: string): void; // throws a formatted Error when detectDrift(root).ok is false\n```\n\n### Index I/O\n\n```typescript\nfunction loadIndex(root: string): RegistryIndexEntry[];               // [] if registry/index.json doesn't exist\nfunction writeIndex(root: string, entries: RegistryIndexEntry[]): void; // creates registry/ if missing\n\ninterface RegistryIndexEntry {\n  id: string;\n  type: string;\n  version: string;\n  title: string;\n  description: string;\n  source: string;          // e.g. \"file:///abs/path/to/entry\" or a directory URI\n  checksum: string;         // \"sha256:<hex>\"\n  compatibility: { host: string };\n  requires?: {\n    tool_calling?: boolean;\n    structured_output?: boolean;\n    min_context_tokens?: number;\n  };\n  members?: Array<{ id: string }>;\n}\n```\n\n### Checksums\n\n```typescript\nfunction computeChecksum(data: Buffer | string): string;       // \"sha256:<hex>\"\nfunction computeFileChecksum(filePath: string): string;        // reads the file, then computeChecksum\nfunction verifyChecksum(filePath: string, expectedChecksum: string): boolean; // false if the file is missing\n```\n\n## Using it as a CI gate\n\n```typescript\nimport { assertNoDrift } from '@adhd/sox-registry';\n\n// e.g. in a build/lint script — exits non-zero (via the thrown Error) if\n// registry/index.json has fallen out of sync with extensions/ on disk.\nassertNoDrift(process.cwd());\n```\n\n## Building the index yourself\n\n`writeIndex` and `computeFileChecksum` are the two calls a build-index script needs — read each `extension.json`, checksum its source file, and assemble `RegistryIndexEntry[]`:\n\n```typescript\nimport { writeIndex, computeFileChecksum, type RegistryIndexEntry } from '@adhd/sox-registry';\n\nconst entries: RegistryIndexEntry[] = [\n  {\n    id: 'my-agent',\n    type: 'agent',\n    version: '0.1.0',\n    title: 'My Agent',\n    description: 'A test agent',\n    source: 'file:///abs/path/to/extensions/agents/my-agent/extension.json',\n    checksum: computeFileChecksum('/abs/path/to/extensions/agents/my-agent/extension.json'),\n    compatibility: { host: '>=1.0.0' },\n  },\n];\n\nwriteIndex('/path/to/repo', entries);\n```\n\n## Gotchas\n\n- `loadIndex` and `writeIndex` never throw on their own — a missing or malformed `registry/index.json` is treated as an empty index (`[]`), not an error.\n- `detectDrift` silently skips any `extension.json` that fails to parse, rather than reporting it as a distinct error class — a malformed manifest simply won't count toward `onDiskIds`, and its absence from the index (if it's already indexed) surfaces as `stale` instead.\n- Checksum drift detection only applies to `file://`-sourced entries; directory-sourced entries are excluded from the `mutated` check entirely.\n","readmeFilename":"README.md","homepage":"https://github.com/PseudoSky/adhd","keywords":["registry","drift","index","checksum","typescript"],"repository":{"type":"git","url":"git+https://github.com/PseudoSky/adhd.git"},"bugs":{"url":"https://github.com/PseudoSky/adhd/issues"}}