{"_id":"@action-state-group/cll","_rev":"4-d6f1407e9bd018b8d55403fe13256a92","name":"@action-state-group/cll","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@action-state-group/cll","version":"0.1.0","license":"Apache-2.0","_id":"@action-state-group/cll@0.1.0","maintainers":[{"name":"actionstategroup","email":"npm@actionstate.ai"}],"homepage":"https://github.com/action-state-group/cll-ts#readme","bugs":{"url":"https://github.com/action-state-group/cll-ts/issues"},"dist":{"shasum":"1ddb37f81aa5def84a99f16c9d4e9aa9bcbc0f87","tarball":"https://registry.npmjs.org/@action-state-group/cll/-/cll-0.1.0.tgz","fileCount":54,"integrity":"sha512-oR1s3SiBoTMUkwA3WyKW0G1lzf2PjHW0rzd2ejdj/2WlHxbbO580V/Lmw6r5TSibC9VEORMf2Lp5HYvOb492Wg==","signatures":[{"sig":"MEQCIE6OApBW2eVDM78H2KtzIejliostnCCtzz1WsbkV76wOAiAqg2hLzyY6aCKD3bmFoDXZhRhOw3o6GWjcm7fwRUa8jg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":307152},"type":"module","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./jsonl":{"types":"./dist/jsonl.d.ts","import":"./dist/jsonl.js"},"./mysql":{"types":"./dist/mysql.d.ts","import":"./dist/mysql.js"},"./sqlite":{"types":"./dist/sqlite.d.ts","import":"./dist/sqlite.js"}},"gitHead":"633c6e1f19e0ac2b14f4583ec516df9d8f86ce11","scripts":{"lint":"oxlint src test","test":"vitest run --coverage","build":"tsup && tsc -p tsconfig.build.json","check":"npm run format:check && npm run lint && npm run typecheck && npm test","format":"prettier --write .","typecheck":"tsc --noEmit","format:check":"prettier --check ."},"_npmUser":{"name":"actionstategroup","email":"npm@actionstate.ai"},"repository":{"url":"git+https://github.com/action-state-group/cll-ts.git","type":"git"},"_npmVersion":"11.17.0","description":"Generic TypeScript Checkpointed Local Log with MMR proofs, checkpoints, witnesses, and durable backends","directories":{},"_nodeVersion":"26.5.0","dependencies":{"cborg":"6.1.2","fs-ext":"2.1.1","mysql2":"3.24.3","better-sqlite3":"13.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","oxlint":"1.81.0","vitest":"4.1.11","prettier":"3.6.2","typescript":"7.0.2","@types/node":"24.3.0","@types/fs-ext":"2.0.3","@vitest/coverage-v8":"4.1.11","@testcontainers/mysql":"11.7.2","@types/better-sqlite3":"7.6.13"},"_npmOperationalInternal":{"tmp":"tmp/cll_0.1.0_1788406668811_0.22312697345406685","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@action-state-group/cll","version":"0.1.1","license":"Apache-2.0","_id":"@action-state-group/cll@0.1.1","maintainers":[{"name":"actionstategroup","email":"npm@actionstate.ai"}],"homepage":"https://github.com/action-state-group/cll-ts#readme","bugs":{"url":"https://github.com/action-state-group/cll-ts/issues"},"dist":{"shasum":"92509e8f7f01c1aaf037be59834e23ad4126b400","tarball":"https://registry.npmjs.org/@action-state-group/cll/-/cll-0.1.1.tgz","fileCount":54,"integrity":"sha512-e6Rn6rDUa/o8TIE31aPOdm6K4r9FXfMgmBLMGD6X/ouiaHH8OAu8UdUMsUV2j4c2REbjvTKznUUWPW+CEV17JQ==","signatures":[{"sig":"MEYCIQCyfyO+SNbqXbFNxeFycKv/CsIpeE2CtKmQpJ+JCq+YvgIhAI8oS2W78KjpSTKc5ExSkNgTUQww0g5XqnGjFAuF3JYi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@action-state-group%2fcll@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":307985},"type":"module","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./jsonl":{"types":"./dist/jsonl.d.ts","import":"./dist/jsonl.js"},"./mysql":{"types":"./dist/mysql.d.ts","import":"./dist/mysql.js"},"./sqlite":{"types":"./dist/sqlite.d.ts","import":"./dist/sqlite.js"}},"gitHead":"5383999b293d8a15bb25bfdadb0e0a82efe8133e","scripts":{"lint":"oxlint src test","test":"vitest run --coverage","build":"tsup && tsc -p tsconfig.build.json","check":"npm run format:check && npm run lint && npm run typecheck && npm test","format":"prettier --write .","typecheck":"tsc --noEmit","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:950e6c90-6c64-4a7a-b1fb-b2980e717efe"}},"repository":{"url":"git+https://github.com/action-state-group/cll-ts.git","type":"git"},"_npmVersion":"11.17.0","description":"Generic TypeScript Checkpointed Local Log with MMR proofs, checkpoints, witnesses, and durable backends","directories":{},"_nodeVersion":"24.19.0","dependencies":{"cborg":"6.1.2","fs-ext":"2.1.1","mysql2":"3.24.3","better-sqlite3":"13.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","oxlint":"1.81.0","vitest":"4.1.11","prettier":"3.6.2","typescript":"7.0.2","@types/node":"24.3.0","@types/fs-ext":"2.0.3","@vitest/coverage-v8":"4.1.11","@testcontainers/mysql":"11.7.2","@types/better-sqlite3":"7.6.13"},"_npmOperationalInternal":{"tmp":"tmp/cll_0.1.1_1788409102643_0.023081014530239807","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@action-state-group/cll","version":"0.1.2","license":"Apache-2.0","_id":"@action-state-group/cll@0.1.2","maintainers":[{"name":"actionstategroup","email":"npm@actionstate.ai"}],"homepage":"https://github.com/action-state-group/cll-ts#readme","bugs":{"url":"https://github.com/action-state-group/cll-ts/issues"},"dist":{"shasum":"6e5cdad8c8c6c1c8ac6f7cb5a01c3f432f8c7b8e","tarball":"https://registry.npmjs.org/@action-state-group/cll/-/cll-0.1.2.tgz","fileCount":58,"integrity":"sha512-A86OKpvbAGG/JW36fwjvrvbPwBJed5y5FYf3Lr287ulGiyPATEMkaaooYWVIRzcWXaadLDw9VNqYPPe5FQ4dbw==","signatures":[{"sig":"MEUCIB7jJQmOR7Mp0fGhj/2wgTlZjFx+nHCAbOFBVa2p31cQAiEA34lTWAumf7o8irf58gH3ThXQoNkuR7XKnbDdaEx1Dsw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@action-state-group%2fcll@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":346785},"type":"module","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./jsonl":{"types":"./dist/jsonl.d.ts","import":"./dist/jsonl.js"},"./mysql":{"types":"./dist/mysql.d.ts","import":"./dist/mysql.js"},"./sqlite":{"types":"./dist/sqlite.d.ts","import":"./dist/sqlite.js"}},"gitHead":"91b88ca17e452eeb5994bd98bd514db7f02db814","scripts":{"lint":"oxlint src test","test":"vitest run --coverage","build":"tsup && tsc -p tsconfig.build.json","check":"npm run format:check && npm run lint && npm run typecheck && npm test","format":"prettier --write .","typecheck":"tsc --noEmit","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:950e6c90-6c64-4a7a-b1fb-b2980e717efe"}},"repository":{"url":"git+https://github.com/action-state-group/cll-ts.git","type":"git"},"_npmVersion":"11.17.0","description":"Generic TypeScript Checkpointed Local Log with MMR proofs, checkpoints, witnesses, and durable backends","directories":{},"_nodeVersion":"24.19.0","dependencies":{"cborg":"6.1.2","fs-ext":"2.1.1","mysql2":"3.24.3","better-sqlite3":"13.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.5.1","oxlint":"1.81.0","vitest":"4.1.11","prettier":"3.6.2","typescript":"7.0.2","@types/node":"24.3.0","@types/fs-ext":"2.0.3","@vitest/coverage-v8":"4.1.11","@testcontainers/mysql":"11.7.2","@types/better-sqlite3":"7.6.13"},"_npmOperationalInternal":{"tmp":"tmp/cll_0.1.2_1788455263136_0.7474904720128028","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@action-state-group/cll","version":"0.1.3","license":"Apache-2.0","description":"Generic TypeScript Checkpointed Local Log with MMR proofs, checkpoints, witnesses, and durable backends","type":"module","repository":{"type":"git","url":"git+https://github.com/action-state-group/cll-ts.git"},"homepage":"https://github.com/action-state-group/cll-ts#readme","bugs":{"url":"https://github.com/action-state-group/cll-ts/issues"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./jsonl":{"types":"./dist/jsonl.d.ts","import":"./dist/jsonl.js"},"./sqlite":{"types":"./dist/sqlite.d.ts","import":"./dist/sqlite.js"},"./mysql":{"types":"./dist/mysql.d.ts","import":"./dist/mysql.js"}},"engines":{"node":">=22"},"publishConfig":{"access":"public"},"scripts":{"build":"tsup && tsc -p tsconfig.build.json","format":"prettier --write .","format:check":"prettier --check .","lint":"oxlint src test","typecheck":"tsc --noEmit","test":"vitest run --coverage","check":"npm run format:check && npm run lint && npm run typecheck && npm test"},"dependencies":{"better-sqlite3":"13.0.3","cborg":"6.1.2","fs-ext":"2.1.1","mysql2":"3.24.3"},"devDependencies":{"@testcontainers/mysql":"11.7.2","@types/better-sqlite3":"7.6.13","@types/fs-ext":"2.0.3","@types/node":"22.20.2","@vitest/coverage-v8":"4.1.11","oxlint":"1.81.0","prettier":"3.6.2","tsup":"8.5.1","typescript":"7.0.2","vitest":"4.1.11"},"gitHead":"470d10257ec588a8e7689121cc435971673d4ad9","_id":"@action-state-group/cll@0.1.3","_nodeVersion":"24.20.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-CV/LLZ2cZst872fdVubxgFm6GriuXZzkwAMd/GjwavB4H5+x9Snrnmoff6EwwUsIOTN3Dw+L5gw/mu7DFDMMzw==","shasum":"1d315263668ea4cc2bb409cc94e5b336f2fc1d6c","tarball":"https://registry.npmjs.org/@action-state-group/cll/-/cll-0.1.3.tgz","fileCount":58,"unpackedSize":351206,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@action-state-group%2fcll@0.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCJgxAX+16yhUTO1yFM8SqoAUkPD9UVH/rw30y7OxCwJAIhAK/R85jun+0FN3cunEsO5IK1L6lGhlSZc+DcKFSObv3L"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:950e6c90-6c64-4a7a-b1fb-b2980e717efe"}},"directories":{},"maintainers":[{"name":"actionstategroup","email":"npm@actionstate.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cll_0.1.3_1789151901280_0.9701503801003872"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T03:37:48.657Z","modified":"2026-09-11T18:38:21.908Z","0.1.0":"2026-09-03T03:37:48.961Z","0.1.1":"2026-09-03T04:18:22.784Z","0.1.2":"2026-09-03T17:07:43.257Z","0.1.3":"2026-09-11T18:38:21.499Z"},"bugs":{"url":"https://github.com/action-state-group/cll-ts/issues"},"license":"Apache-2.0","homepage":"https://github.com/action-state-group/cll-ts#readme","repository":{"type":"git","url":"git+https://github.com/action-state-group/cll-ts.git"},"description":"Generic TypeScript Checkpointed Local Log with MMR proofs, checkpoints, witnesses, and durable backends","maintainers":[{"name":"actionstategroup","email":"npm@actionstate.ai"}],"readme":"# @action-state-group/cll\n\nA generic TypeScript implementation of a Checkpointed Local Log (CLL). It\nstores opaque 32-byte entry values, builds an append-only Merkle Mountain Range,\nsigns checkpoints, and delivers them to witnesses. It does not interpret the\nrecords whose identities are appended.\n\n## Install\n\nNode.js 22 or newer is required.\n\n```sh\nnpm install @action-state-group/cll\n```\n\nInstall only the database driver path you use. The root import does not load\nSQLite or MySQL native modules.\n\n## Append and checkpoint\n\n```ts\nimport {\n  CheckpointRunner,\n  MemoryStore,\n  createCheckpointIdentity,\n} from \"@action-state-group/cll\";\n\nconst backend = new MemoryStore();\nconst recordIdentity = new Uint8Array(32); // digest or another opaque identity\n\nconst result = await backend.append({\n  value: recordIdentity,\n  appendedAt: new Date(),\n});\n\nconsole.log(result.entry.seq, result.outcome); // 1n, \"inserted\"\n\nconst runner = new CheckpointRunner(backend, {\n  logId: \"example-log\",\n  identity: createCheckpointIdentity(\n    crypto.getRandomValues(new Uint8Array(32)),\n  ),\n  entryCadence: 100,\n  ageCadenceMs: 15 * 60_000,\n  scanLimit: 100,\n});\n\nawait runner.runOnce();\nrunner.notify(); // wake runner.run(signal) after a new append\n```\n\nAppending the same 32-byte value again is idempotent. It returns the original\nentry and does not change its sequence or append time. Sequences are dense and\n1-based.\n\n## Witness delivery\n\nEvery ID in `CheckpointRunner.witnessIds` needs both a `WitnessClient` and a\n`ReceiptVerification` entry under the same ID. Missing local configuration is\nretryable and fails closed; receipt bytes are persisted as success only after\nthe configured verifier accepts them. A rejected or corrupt receipt is marked\npermanent so polling does not repeatedly submit the same checkpoint.\n\n```ts\nimport {\n  HttpWitnessClient,\n  ReceiptVerifier,\n  WitnessDeliveryRunner,\n} from \"@action-state-group/cll\";\n\nconst witness = new HttpWitnessClient(\n  \"public-witness\",\n  new URL(\"https://witness.example\"),\n);\nconst delivery = new WitnessDeliveryRunner(\n  backend,\n  new Map([[witness.id, witness]]),\n  {\n    verifiers: new Map([\n      [witness.id, new ReceiptVerifier(pinnedWitnessEd25519PublicKey)],\n    ]),\n    baseBackoffMs: 1_000,\n    maxBackoffMs: 60 * 60_000,\n    jitter: false,\n  },\n);\nawait delivery.runOnce();\n```\n\n`HttpWitnessClient` sends the raw checkpoint COSE bytes to `POST /checkpoints`\nwith content type `application/cll-checkpoint+cbor`. It expects JSON containing\n`receipt_b64`, `entry_hash_scheme: \"legacy\"`, a lowercase 64-hex `entry_hash`,\nand integer `leaf_index` and `tree_size`. `ReceiptVerifier` validates that RFC\n9162-style receipt against a pinned Ed25519 authority key. Other witness\nprotocols implement `WitnessClient` and `ReceiptVerification`; their receipt may\ncontain only opaque `bytes`.\n\nAfter correcting an external condition that caused a permanent failure, an\noperator may load the row with `getWitness` and reset it with `commitWitness`\nusing its current `attempts` value as the compare-and-swap token.\n\n## Backends\n\nAll included backends implement `CllBackend` directly and run the same contract\nsuite.\n\n```ts\nimport { MemoryStore } from \"@action-state-group/cll\";\nimport { JsonlStore } from \"@action-state-group/cll/jsonl\";\nimport { SqliteStore } from \"@action-state-group/cll/sqlite\";\nimport { MysqlStore } from \"@action-state-group/cll/mysql\";\n\nconst memory = new MemoryStore();\nconst jsonl = await JsonlStore.open(\"./events.jsonl\");\nconst sqlite = SqliteStore.open(\"./cll.sqlite\", \"example-log\");\nconst mysql = await MysqlStore.open(process.env.MYSQL_URL!, \"example-log\");\n```\n\n- Memory is process-local and intended for tests or ephemeral use.\n- JSONL is single-writer, append-only, fsyncs complete events, truncates an\n  incomplete tail after a crash, and rejects version 3 files.\n- SQLite uses WAL and serializes writes across handles for the same file/log.\n- MySQL uses InnoDB transactions and locks the log metadata row while assigning\n  sequences or updating checkpoint state.\n\n### SQLite and MySQL tables\n\n`SqliteStore.open()` and `MysqlStore.open()` create the same four\nlibrary-owned tables when they do not already exist:\n\n| Table           | Purpose                                                 |\n| --------------- | ------------------------------------------------------- |\n| `cll_meta`      | Log-level serialized checkpoint and control state       |\n| `cll_entries`   | Ordered 32-byte record identities and append timestamps |\n| `cll_nodes`     | Merkle Mountain Range nodes used by checkpoints         |\n| `cll_witnesses` | Durable witness delivery attempts and receipt state     |\n\nEvery table is scoped by `log_id`, so one database can hold multiple independent\nlogs. The caller must provide an existing database and credentials allowed to\ncreate and access these tables. They do not contain full application records,\nCapsules, or Producer Envelopes; the application persists those separately.\n\nSQLite and MySQL validate the complete selected log when opening it. Normal\nentry lookup, bounded scans, appends, witness lookup, and witness CAS use indexed\nqueries without rebuilding the log. `loadCll()` and `commitCll()` read metadata,\nMMR nodes, and witnesses as one consistent CLL snapshot, but do not read record\nentries.\n\n## MMR and checkpoint inspection\n\nGo and TypeScript expose the same core MMR and checkpoint capabilities using\nlanguage-idiomatic names and types:\n\n```ts\nimport {\n  MmrTree,\n  checkpointEntryHash,\n  checkpointMetadata,\n  verifyHexInclusion,\n} from \"@action-state-group/cll\";\n\nconst tree = new MmrTree();\nconst identity = \"ab\".repeat(32);\ntree.appendHexIdentity(identity);\nconst proof = tree.inclusionProof(0n);\nverifyHexInclusion(tree.root(), tree.size, 0n, identity, proof);\n\nconst metadata = checkpointMetadata(signedCheckpointBytes);\nconst witnessEntryHash = checkpointEntryHash(signedCheckpointBytes);\n```\n\n`checkpointMetadata` returns data only after complete checkpoint shape,\ncommitment, consistency-proof, and signature verification. The entry hash is\nthe RFC 9162 checkpoint entry identity used by witness receipts.\n\n## Compose with capsule-emit\n\nAAC is one possible application of CLL. The two packages are independent. The\napplication verifies and stores the full application record, then appends only\nits verified 32-byte identity to CLL.\n\n```ts\nimport { build, verifyCapsule } from \"@action-state-group/capsule-emit\";\nimport { MysqlStore } from \"@action-state-group/cll/mysql\";\n\nconst built = build({\n  actionId: \"deploy-42\",\n  actionType: \"fyi\",\n  operator: \"matt\",\n  developer: \"example@v1\",\n  timestamp: new Date(),\n});\n\nverifyCapsule(built.json); // returns verified metadata or throws\n\n// The application persists built.json and any Producer Envelope separately.\nconst cll = await MysqlStore.open(process.env.MYSQL_URL!, \"application-log\");\nawait cll.append({\n  value: Buffer.from(built.capsuleId, \"hex\"),\n  appendedAt: new Date(),\n});\n```\n\nNeither package imports the other at runtime. A project that needs both installs\nboth explicitly.\n\n## Implement another backend\n\nTypeScript interfaces are structural. A class does not need to extend an SDK\nbase class; it must implement every operation with the documented semantics.\n\n```ts\nimport type {\n  AppendInput,\n  AppendResult,\n  CllBackend,\n  CllEntry,\n  CllState,\n  WitnessState,\n} from \"@action-state-group/cll\";\n\nexport class PostgresBackend implements CllBackend {\n  append(input: AppendInput): Promise<AppendResult> {\n    throw new Error(\"implement atomically\");\n  }\n  getEntry(value: Uint8Array): Promise<CllEntry> {\n    throw new Error(\"implement\");\n  }\n  scanEntries(afterSeq: bigint, limit: number): Promise<readonly CllEntry[]> {\n    throw new Error(\"implement\");\n  }\n  loadCll(): Promise<CllState> {\n    throw new Error(\"implement from one consistent snapshot\");\n  }\n  commitCll(\n    expectedSize: bigint,\n    expectedCheckpoint: Uint8Array | undefined,\n    next: CllState,\n  ): Promise<void> {\n    throw new Error(\"implement append-only compare-and-swap\");\n  }\n  pendingWitnesses(now: Date, limit: number): Promise<readonly WitnessState[]> {\n    throw new Error(\"implement\");\n  }\n  getWitness(id: string, size: bigint): Promise<WitnessState | undefined> {\n    throw new Error(\"implement\");\n  }\n  commitWitness(expectedAttempts: number, next: WitnessState): Promise<void> {\n    throw new Error(\"implement compare-and-swap\");\n  }\n  close(): Promise<void> {\n    throw new Error(\"implement idempotently\");\n  }\n}\n```\n\nRun the repository's\n[backend contract](https://github.com/action-state-group/cll-ts/blob/main/test/backend-contract.ts)\nunchanged against the new backend. Durable implementations must persist every mutation, return defensive\ncopies, allocate dense sequences transactionally, provide consistent reads,\nenforce checkpoint and witness compare-and-swap, detect corrupt state, and make\n`close()` idempotent.\n\nSee [DESIGN.md](DESIGN.md) for state and durability invariants.\n\n## Release\n\nReleases are published from `main` with the manual\n[Publish npm package](https://github.com/action-state-group/cll-ts/actions/workflows/publish.yml)\nGitHub Action:\n\n1. Update `version` in `package.json` and `package-lock.json`, commit the change,\n   and wait for `main` CI to pass.\n2. In GitHub, open the workflow, choose **Run workflow**, and select `main`.\n3. Verify the workflow published `@action-state-group/cll` and created the\n   `v<version>` GitHub release and tag on the published commit.\n\nThe npm package must have a GitHub Actions trusted publisher configured for\nthe `action-state-group/cll-ts` repository and\n`.github/workflows/publish.yml`. No long-lived npm token is required. Re-running\nthe workflow is safe: it skips an existing npm version and verifies that its\nGit tag points to the `gitHead` recorded by npm.\n\nIf npm contains the version but its tag is missing after this workflow has\nchanged, GitHub may reject recovery with the workflow's `GITHUB_TOKEN`. A\nmaintainer with `workflow` scope must create the tag at the npm `gitHead`, then\nrerun the workflow to verify the tag and create any missing GitHub release:\n\n```sh\nversion=0.1.1\ngit_head=$(npm view \"@action-state-group/cll@$version\" gitHead)\ngit fetch origin --tags\ngit tag -a \"v$version\" \"$git_head\" -m \"Release v$version\"\ngit push origin \"refs/tags/v$version\"\n```\n","readmeFilename":"README.md"}