@johnhenry/objectify-cli 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 objectify contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @johnhenry/objectify-cli
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40johnhenry%2Fobjectify-cli.svg)](https://www.npmjs.com/package/@johnhenry/objectify-cli)
4
+
5
+ `objectify` — persistent, versioned JSON objects backed by SQLite. A stateful,
6
+ agent-friendly CLI: `create` an object, `use` it to read/write state, `log` /
7
+ `diff` / `rewind` through its version history, `fork` an independent copy.
8
+
9
+ Full CLI reference, architecture notes, and "designed for agents" docs live at
10
+ **https://opensource.johnhenry.me/objectify/**.
11
+
12
+ > **This is the first npm distribution of the `objectify` CLI.** The CLI has
13
+ > existed as a `cargo build --release` / GitHub-release binary before now —
14
+ > this package (and its five per-platform siblings) is a new packaging story,
15
+ > not an import of a previously-published npm package. Versioning starts at
16
+ > `0.0.0`, matching this project's usual convention for a package's first
17
+ > appearance under the `@johnhenry` scope, extended here to cover "first npm
18
+ > appearance at all," since there's no prior npm version to restart from.
19
+ > Named `objectify-cli` rather than plain `objectify` because
20
+ > [`@johnhenry/objectify`](https://www.npmjs.com/package/@johnhenry/objectify)
21
+ > is this project's TypeScript adapter package — the CLI command you actually
22
+ > run is still `objectify`, only the npm package name differs.
23
+
24
+ ## Install
25
+
26
+ ```sh
27
+ npm install -g @johnhenry/objectify-cli
28
+ ```
29
+
30
+ or run it without installing:
31
+
32
+ ```sh
33
+ npx @johnhenry/objectify-cli --help
34
+ ```
35
+
36
+ ## How this works
37
+
38
+ This package is a thin ~100-line Node.js shim (`bin/objectify.js`). It ships
39
+ no compiled code itself — it detects your OS/architecture at runtime and
40
+ delegates to the real binary, which lives in one of five tiny per-platform
41
+ packages:
42
+
43
+ | Package | Platform |
44
+ |---|---|
45
+ | `@johnhenry/objectify-cli-darwin-arm64` | macOS, Apple Silicon |
46
+ | `@johnhenry/objectify-cli-darwin-x64` | macOS, Intel |
47
+ | `@johnhenry/objectify-cli-linux-x64` | Linux, x64 (glibc) |
48
+ | `@johnhenry/objectify-cli-linux-arm64` | Linux, arm64 (glibc) |
49
+ | `@johnhenry/objectify-cli-win32-x64` | Windows, x64 |
50
+
51
+ `npm install` only downloads the one matching your machine — it's listed as
52
+ an `optionalDependency` with `os`/`cpu` fields, which is how npm decides which
53
+ optional dependencies to actually fetch. This is the same pattern used by
54
+ `esbuild`, `@swc/core`, and `turbo`. No postinstall script runs and no network
55
+ request happens beyond npm's own package resolution — see
56
+ [`bin/objectify.js`](./bin/objectify.js) for the full resolution logic and
57
+ error messages if the right platform package didn't get installed.
58
+
59
+ ## Platform support
60
+
61
+ Linux `x64`/`arm64` builds target glibc; there is currently no separate
62
+ `musl` build (e.g. for Alpine-based Docker images). If you need one, please
63
+ open an issue.
64
+
65
+ ## Integrity
66
+
67
+ Every package published from CI carries an [npm provenance
68
+ attestation](https://docs.npmjs.com/generating-provenance-statements)
69
+ (Sigstore-backed, tying the published package back to the exact GitHub
70
+ Actions run, commit, and source repo that built it) — check with
71
+ `npm audit signatures` after installing.
72
+
73
+ On top of that, this package ships a `checksums.json` manifest pinning the
74
+ expected SHA-256 of each platform binary for this version. Before executing
75
+ anything, `bin/objectify.js` hashes the resolved binary and compares it
76
+ against the pinned value, refusing to run on a mismatch. This is
77
+ defense-in-depth on top of provenance, not a replacement for it — see
78
+ [`bin/objectify.js`](./bin/objectify.js) (`verifyChecksum`) for details.
79
+
80
+ ## License
81
+
82
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Platform-detection shim for the `objectify` CLI.
6
+ *
7
+ * The real compiled binary lives in one of five tiny per-platform npm
8
+ * packages (each published from CI, one per Rust build target) and is
9
+ * installed via `optionalDependencies` — npm only installs the ones whose
10
+ * `os`/`cpu` fields match the current machine, so exactly one (usually)
11
+ * ends up on disk. This script finds it, verifies its checksum against the
12
+ * value pinned in this package's checksums.json (see verifyChecksum below),
13
+ * and execs it, passing through argv/stdio/exit code unchanged.
14
+ *
15
+ * Deliberately does NOT do what esbuild's install.js / turbo's bin/turbo do:
16
+ * no postinstall network download, no automatic "npm install" repair
17
+ * attempt if the optional dependency didn't land. If the right platform
18
+ * package is missing, this prints a clear, actionable error instead of
19
+ * silently reaching out to the network. See objectify's npm/README (or
20
+ * LESSONS.md in the adopt-library skill) for why that's a first-pass
21
+ * simplification, not a permanent design decision.
22
+ */
23
+
24
+ const { spawnSync } = require('child_process');
25
+ const { createHash } = require('crypto');
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+
29
+ // Escape hatch for local development / testing against a freshly-built
30
+ // binary without publishing a platform package first.
31
+ const OBJECTIFY_BINARY_PATH = process.env.OBJECTIFY_BINARY_PATH;
32
+
33
+ const PACKAGES = {
34
+ 'darwin arm64': '@johnhenry/objectify-cli-darwin-arm64',
35
+ 'darwin x64': '@johnhenry/objectify-cli-darwin-x64',
36
+ 'linux arm64': '@johnhenry/objectify-cli-linux-arm64',
37
+ 'linux x64': '@johnhenry/objectify-cli-linux-x64',
38
+ 'win32 x64': '@johnhenry/objectify-cli-win32-x64',
39
+ };
40
+
41
+ function binSubpath(platform) {
42
+ return platform === 'win32' ? 'bin/objectify.exe' : 'bin/objectify';
43
+ }
44
+
45
+ // Resolves to { binaryPath, platformName } where platformName is the
46
+ // hyphenated platform identifier (e.g. "darwin-arm64") used as the key into
47
+ // checksums.json — or platformName: null when OBJECTIFY_BINARY_PATH is used,
48
+ // since a locally-built binary has no pinned checksum to verify against.
49
+ function resolveBinaryPath() {
50
+ if (OBJECTIFY_BINARY_PATH) {
51
+ return { binaryPath: OBJECTIFY_BINARY_PATH, platformName: null };
52
+ }
53
+
54
+ const platform = process.platform;
55
+ const arch = process.arch;
56
+ const key = `${platform} ${arch}`;
57
+ const pkg = PACKAGES[key];
58
+
59
+ if (!pkg) {
60
+ fail(
61
+ `Unsupported platform: ${key}\n\n` +
62
+ `objectify currently ships prebuilt binaries for:\n` +
63
+ Object.keys(PACKAGES)
64
+ .map((k) => ` - ${k}`)
65
+ .join('\n') +
66
+ `\n\nIf you're on a platform not listed here, please open an issue:\n` +
67
+ ` https://github.com/johnhenry/objectify/issues`,
68
+ );
69
+ }
70
+
71
+ const platformName = pkg.replace('@johnhenry/objectify-cli-', '');
72
+
73
+ try {
74
+ const binaryPath = require.resolve(`${pkg}/${binSubpath(platform)}`);
75
+ return { binaryPath, platformName };
76
+ } catch (e) {
77
+ fail(
78
+ `Could not find the objectify binary for your platform (${key}).\n\n` +
79
+ `Expected it in the optional dependency "${pkg}", which npm should\n` +
80
+ `have installed automatically alongside "@johnhenry/objectify-cli".\n\n` +
81
+ `This usually means the optional dependency failed to install or was\n` +
82
+ `skipped. Try:\n\n` +
83
+ ` npm install --include=optional @johnhenry/objectify-cli\n\n` +
84
+ `If you're using a package manager other than npm, make sure it\n` +
85
+ `doesn't skip optional dependencies (some configurations of pnpm/\n` +
86
+ `Yarn need "supportedArchitectures" set explicitly).\n\n` +
87
+ `Underlying error: ${e && e.message}`,
88
+ );
89
+ }
90
+ }
91
+
92
+ // checksums.json (published as part of this package, see .github/workflows/
93
+ // release.yml) pins the expected sha256 of each platform's binary at the
94
+ // version this package was published with. Verifying it here means a
95
+ // compromised npm token, CI runner, or registry mirror can't silently swap
96
+ // in a different binary for one of the five platform packages without also
97
+ // tripping this check (short of also compromising the main package's
98
+ // checksums.json in the same way, which `npm publish --provenance` in the
99
+ // release workflow independently guards against).
100
+ function loadChecksums() {
101
+ const checksumsPath = path.join(__dirname, '..', 'checksums.json');
102
+ try {
103
+ return JSON.parse(fs.readFileSync(checksumsPath, 'utf8'));
104
+ } catch (e) {
105
+ if (e && e.code === 'ENOENT') {
106
+ // Published before checksums.json existed, or a non-npm install layout.
107
+ // Fail open rather than breaking installs — this is a defense-in-depth
108
+ // check, not the primary integrity mechanism (that's --provenance).
109
+ return null;
110
+ }
111
+ fail(`Failed to read checksums.json: ${e && e.message}`);
112
+ }
113
+ }
114
+
115
+ function sha256File(filePath) {
116
+ const hash = createHash('sha256');
117
+ hash.update(fs.readFileSync(filePath));
118
+ return hash.digest('hex');
119
+ }
120
+
121
+ function verifyChecksum(binaryPath, platformName) {
122
+ if (platformName === null) {
123
+ return; // OBJECTIFY_BINARY_PATH escape hatch — nothing pinned to check.
124
+ }
125
+
126
+ const checksums = loadChecksums();
127
+ if (!checksums) {
128
+ return;
129
+ }
130
+
131
+ const expected = checksums[platformName];
132
+ if (!expected) {
133
+ // checksums.json exists but doesn't cover this platform — don't block
134
+ // execution over a manifest gap, but don't pretend we verified it either.
135
+ return;
136
+ }
137
+
138
+ const actual = sha256File(binaryPath);
139
+ if (actual !== expected) {
140
+ fail(
141
+ `Checksum mismatch for the objectify binary (${platformName}).\n\n` +
142
+ ` expected: ${expected}\n` +
143
+ ` actual: ${actual}\n\n` +
144
+ `This means the installed binary does not match the one published by\n` +
145
+ `objectify's release CI for this version. It may have been tampered\n` +
146
+ `with, corrupted, or come from an untrusted registry mirror. Refusing\n` +
147
+ `to execute it.\n\n` +
148
+ `Try reinstalling: npm install --include=optional @johnhenry/objectify-cli\n` +
149
+ `If the mismatch persists, please open an issue:\n` +
150
+ ` https://github.com/johnhenry/objectify/issues`,
151
+ );
152
+ }
153
+ }
154
+
155
+ function fail(message) {
156
+ console.error(`[objectify] ${message}`);
157
+ process.exit(1);
158
+ }
159
+
160
+ function main() {
161
+ const { binaryPath, platformName } = resolveBinaryPath();
162
+ verifyChecksum(binaryPath, platformName);
163
+
164
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
165
+ stdio: 'inherit',
166
+ });
167
+
168
+ if (result.error) {
169
+ fail(`Failed to run "${path.basename(binaryPath)}": ${result.error.message}`);
170
+ }
171
+
172
+ if (result.signal) {
173
+ // Re-raise the same signal so the parent shell sees the expected
174
+ // "killed by signal" behavior rather than a plain exit code.
175
+ process.kill(process.pid, result.signal);
176
+ return;
177
+ }
178
+
179
+ process.exit(result.status === null ? 1 : result.status);
180
+ }
181
+
182
+ main();
package/checksums.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "linux-arm64": "05836ebdd234e42c5ca98b19f0a8fd266852975b7c00eb93f8b233bce80e7a77",
3
+ "linux-x64": "46467922b9fb2293398986f54e499cdd88384949dc75e131a653ed78b307f24a",
4
+ "win32-x64": "df1a4c7ab8b9bda2270ff8f8a6d450271a027efe7323ec79ed5cd268dbadeec2"
5
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@johnhenry/objectify-cli",
3
+ "version": "0.0.0",
4
+ "description": "Persistent, versioned JSON objects backed by SQLite — a stateful, agent-friendly CLI.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/johnhenry/objectify.git",
8
+ "directory": "npm/objectify-cli"
9
+ },
10
+ "homepage": "https://opensource.johnhenry.me/objectify/",
11
+ "bugs": "https://github.com/johnhenry/objectify/issues",
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "cli",
15
+ "sqlite",
16
+ "versioning",
17
+ "state",
18
+ "json",
19
+ "agents",
20
+ "rust"
21
+ ],
22
+ "bin": {
23
+ "objectify": "bin/objectify.js"
24
+ },
25
+ "files": ["bin", "checksums.json"],
26
+ "os": ["darwin", "linux", "win32"],
27
+ "engines": {
28
+ "node": ">=26.0.0"
29
+ },
30
+ "optionalDependencies": {
31
+ "@johnhenry/objectify-cli-darwin-arm64": "0.0.0",
32
+ "@johnhenry/objectify-cli-darwin-x64": "0.0.0",
33
+ "@johnhenry/objectify-cli-linux-x64": "0.0.0",
34
+ "@johnhenry/objectify-cli-linux-arm64": "0.0.0",
35
+ "@johnhenry/objectify-cli-win32-x64": "0.0.0"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }