auxly-cli 1.0.21

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/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # auxly-cli
2
+
3
+ Local-first unified memory system for AI agents. This package downloads the
4
+ prebuilt [`auxly`](https://auxly.io) binary for your platform and verifies it
5
+ against the project's **minisign-signed** checksum manifest before installing.
6
+
7
+ ```bash
8
+ npm install -g auxly-cli
9
+ auxly --help
10
+ ```
11
+
12
+ ## How it works
13
+
14
+ - On install, a `postinstall` step downloads `auxly-<os>-<arch>` from the GitHub
15
+ release matching this package's version.
16
+ - It fetches the signed `auxly-<version>-checksums.txt` + `.minisig`, verifies the
17
+ **minisign signature** against the pinned public key (compiled into the Go binary
18
+ too), and checks the binary's **SHA-256** against the signed manifest.
19
+ - The verified binary is vendored locally and exposed as the `auxly` command.
20
+
21
+ Set `AUXLY_REQUIRE_SIGNATURE=1` to hard-fail if a signed manifest is unavailable
22
+ (by default, an unsigned legacy release installs over HTTPS without verification).
23
+
24
+ Supported: macOS / Linux / Windows on x64 / arm64. Node ≥ 16.
25
+
26
+ License: MIT · <https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli>
package/bin/auxly.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+ // Thin shim: exec the vendored auxly binary, forwarding args + stdio + exit code.
4
+ const path = require('path')
5
+ const { spawnSync } = require('child_process')
6
+
7
+ const ext = process.platform === 'win32' ? '.exe' : ''
8
+ const bin = path.join(__dirname, '..', 'vendor', `auxly${ext}`)
9
+
10
+ const res = spawnSync(bin, process.argv.slice(2), { stdio: 'inherit' })
11
+ if (res.error) {
12
+ if (res.error.code === 'ENOENT') {
13
+ console.error('auxly: binary not found — reinstall with `npm rebuild auxly-cli` or `npm i -g auxly-cli`')
14
+ } else {
15
+ console.error(`auxly: ${res.error.message}`)
16
+ }
17
+ process.exit(1)
18
+ }
19
+ process.exit(res.status === null ? 1 : res.status)
package/install.js ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+ // postinstall: download the matching auxly binary for this platform from the
4
+ // GitHub release that corresponds to THIS package version, verify it against the
5
+ // minisign-signed checksum manifest (pinned key), and drop it in vendor/.
6
+ //
7
+ // Pure Node stdlib — no dependencies. Mirrors the security posture of
8
+ // scripts/install.sh + internal/update/verify.go (SHA-256 integrity + minisign).
9
+
10
+ const fs = require('fs')
11
+ const os = require('os')
12
+ const path = require('path')
13
+ const https = require('https')
14
+ const { sha256Hex, manifestHasHash, verifyMinisign } = require('./lib/verify')
15
+
16
+ const REPO = 'Tzamun-Arabia-IT-Co/auxly-memory-cli'
17
+ const { version } = require('./package.json')
18
+
19
+ function target() {
20
+ const platform = { darwin: 'darwin', linux: 'linux', win32: 'windows' }[os.platform()]
21
+ const arch = { x64: 'amd64', arm64: 'arm64' }[os.arch()]
22
+ if (!platform || !arch) {
23
+ throw new Error(`unsupported platform/arch: ${os.platform()}/${os.arch()}`)
24
+ }
25
+ const ext = platform === 'windows' ? '.exe' : ''
26
+ return { platform, arch, ext, binName: `auxly-${platform}-${arch}${ext}` }
27
+ }
28
+
29
+ // GET with redirect following (GitHub release assets redirect to a CDN). Returns a Buffer.
30
+ function fetchBuffer(url, redirects = 0) {
31
+ return new Promise((resolve, reject) => {
32
+ if (redirects > 8) return reject(new Error('too many redirects'))
33
+ https
34
+ .get(url, { headers: { 'User-Agent': 'auxly-npm-installer' } }, (res) => {
35
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
36
+ res.resume()
37
+ const next = new URL(res.headers.location, url).toString()
38
+ return resolve(fetchBuffer(next, redirects + 1))
39
+ }
40
+ if (res.statusCode !== 200) {
41
+ res.resume()
42
+ return reject(new Error(`HTTP ${res.statusCode} for ${url}`))
43
+ }
44
+ const chunks = []
45
+ res.on('data', (c) => chunks.push(c))
46
+ res.on('end', () => resolve(Buffer.concat(chunks)))
47
+ })
48
+ .on('error', reject)
49
+ })
50
+ }
51
+
52
+ async function main() {
53
+ const { binName, ext } = target()
54
+ const base = `https://github.com/${REPO}/releases/download/v${version}`
55
+ const manifestName = `auxly-${version}-checksums.txt`
56
+
57
+ console.log(`auxly: downloading ${binName} (v${version})…`)
58
+ const bin = await fetchBuffer(`${base}/${binName}`)
59
+
60
+ // Integrity + authenticity. Every release this package targets (it is version-
61
+ // locked to a release tag) ships a signed manifest, so verification is REQUIRED
62
+ // by default — a missing or junk manifest aborts rather than silently installing
63
+ // an unverified binary. AUXLY_ALLOW_UNSIGNED=1 relaxes this for emergencies.
64
+ const allowUnsigned = process.env.AUXLY_ALLOW_UNSIGNED === '1'
65
+ let manifest, sig
66
+ try {
67
+ manifest = (await fetchBuffer(`${base}/${manifestName}`)).toString('utf8')
68
+ sig = (await fetchBuffer(`${base}/${manifestName}.minisig`)).toString('utf8')
69
+ } catch (e) {
70
+ if (!allowUnsigned) {
71
+ throw new Error(
72
+ `signed manifest unavailable (${e.message}) and verification is required ` +
73
+ '— set AUXLY_ALLOW_UNSIGNED=1 only if you accept an unverified install'
74
+ )
75
+ }
76
+ console.warn(`auxly: AUXLY_ALLOW_UNSIGNED=1 — installing without verification (${e.message})`)
77
+ return writeBinary(bin)
78
+ }
79
+
80
+ if (!/^[0-9a-f]{64}\s+\S/m.test(manifest)) {
81
+ if (!allowUnsigned) {
82
+ throw new Error('fetched manifest is not a checksums file — refusing to install')
83
+ }
84
+ console.warn('auxly: AUXLY_ALLOW_UNSIGNED=1 — manifest is not a checksums file; installing unverified')
85
+ return writeBinary(bin)
86
+ }
87
+
88
+ verifyMinisign(Buffer.from(manifest, 'utf8'), sig) // throws on failure
89
+ if (!manifestHasHash(manifest, sha256Hex(bin))) {
90
+ throw new Error('downloaded binary SHA-256 is not in the signed manifest — refusing to install')
91
+ }
92
+ console.log('auxly: signature + checksum verified ✔')
93
+ return writeBinary(bin)
94
+ }
95
+
96
+ function writeBinary(bin) {
97
+ const { ext } = target()
98
+ const vendorDir = path.join(__dirname, 'vendor')
99
+ fs.mkdirSync(vendorDir, { recursive: true })
100
+ const dest = path.join(vendorDir, `auxly${ext}`)
101
+ fs.writeFileSync(dest, bin, { mode: 0o755 })
102
+ console.log(`auxly: installed -> ${dest}`)
103
+ }
104
+
105
+ main().catch((err) => {
106
+ console.error(`\nauxly install failed: ${err.message}`)
107
+ console.error('You can install manually from https://github.com/' + REPO + '/releases')
108
+ process.exit(1)
109
+ })
package/lib/verify.js ADDED
@@ -0,0 +1,91 @@
1
+ 'use strict'
2
+ // Minisign verification for the auxly npm wrapper.
3
+ //
4
+ // The auxly release CI signs the checksum manifest with minisign (prehashed
5
+ // "ED" mode: ed25519 over BLAKE2b-512 of the file). This module verifies that
6
+ // signature against the PINNED public key — the same key compiled into the Go
7
+ // binary (internal/update/verify.go) — plus the SHA-256 integrity of the
8
+ // downloaded binary against the signed manifest. Pure Node stdlib, no deps:
9
+ // crypto.createHash('blake2b512') + crypto.verify(null, …, ed25519).
10
+
11
+ const crypto = require('crypto')
12
+
13
+ // Pinned minisign public key (base64). MUST match internal/update/verify.go.
14
+ const PUBKEY_B64 = 'RWQfIGHWpXR4MtPvcbWwN1J7mx9FGsCaHMmdIpGMZAKDvmILC2Of5Q/K'
15
+
16
+ // SPKI DER prefix for a raw 32-byte Ed25519 public key.
17
+ const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex')
18
+
19
+ function sha256Hex(buf) {
20
+ return crypto.createHash('sha256').update(buf).digest('hex')
21
+ }
22
+
23
+ // True if hashHex appears as the first whitespace-delimited field of any manifest
24
+ // line (mirrors manifestHasHash in internal/update/verify.go — a full field match,
25
+ // never a substring).
26
+ function manifestHasHash(manifestText, hashHex) {
27
+ const want = hashHex.toLowerCase()
28
+ return manifestText.split('\n').some((line) => {
29
+ const first = line.trim().split(/\s+/)[0]
30
+ return first && first.toLowerCase() === want
31
+ })
32
+ }
33
+
34
+ function ed25519PublicKey(raw32) {
35
+ const der = Buffer.concat([ED25519_SPKI_PREFIX, raw32])
36
+ return crypto.createPublicKey({ key: der, format: 'der', type: 'spki' })
37
+ }
38
+
39
+ // Verify a minisign signature (.minisig text) over fileBuf using the pinned key.
40
+ // Verifies BOTH the file signature and the global (trusted-comment) signature,
41
+ // exactly as the minisign CLI does. Throws on any failure.
42
+ function verifyMinisign(fileBuf, minisigText) {
43
+ const pub = Buffer.from(PUBKEY_B64, 'base64') // [2 algo][8 keyid][32 key]
44
+ if (pub.length !== 42) throw new Error('pinned public key malformed')
45
+ const pubKeyId = pub.subarray(2, 10)
46
+ const key = ed25519PublicKey(pub.subarray(10, 42))
47
+
48
+ // .minisig layout (4 meaningful lines):
49
+ // 0: untrusted comment: …
50
+ // 1: base64( [2 algo][8 keyid][64 sig] )
51
+ // 2: trusted comment: <text>
52
+ // 3: base64( [64 global sig] ) — ed25519 over (sig || trusted-comment text)
53
+ const lines = minisigText.split('\n')
54
+ const sigLine = (lines[1] || '').trim()
55
+ const trustedLine = (lines[2] || '')
56
+ const globalLine = (lines[3] || '').trim()
57
+ if (!sigLine || !globalLine) throw new Error('minisig truncated')
58
+
59
+ const sigBlob = Buffer.from(sigLine, 'base64')
60
+ if (sigBlob.length !== 74) throw new Error('minisig signature block malformed')
61
+ const algo = sigBlob.subarray(0, 2).toString('latin1')
62
+ const sigKeyId = sigBlob.subarray(2, 10)
63
+ const sig = sigBlob.subarray(10, 74)
64
+ if (!sigKeyId.equals(pubKeyId)) throw new Error('minisign key id mismatch')
65
+
66
+ let message
67
+ if (algo === 'ED') {
68
+ message = crypto.createHash('blake2b512').update(fileBuf).digest() // prehashed
69
+ } else if (algo === 'Ed') {
70
+ message = fileBuf // legacy
71
+ } else {
72
+ throw new Error('unsupported minisign algorithm: ' + algo)
73
+ }
74
+ if (!crypto.verify(null, message, key, sig)) {
75
+ throw new Error('minisign file signature is INVALID')
76
+ }
77
+
78
+ // Global signature binds the trusted comment to the signature.
79
+ const prefix = 'trusted comment:'
80
+ const idx = trustedLine.indexOf(prefix)
81
+ const trustedComment = idx >= 0 ? trustedLine.slice(idx + prefix.length).replace(/^\s/, '') : ''
82
+ const globalSig = Buffer.from(globalLine, 'base64')
83
+ if (globalSig.length !== 64) throw new Error('minisig global signature malformed')
84
+ const globalMsg = Buffer.concat([sig, Buffer.from(trustedComment, 'utf8')])
85
+ if (!crypto.verify(null, globalMsg, key, globalSig)) {
86
+ throw new Error('minisign trusted-comment signature is INVALID')
87
+ }
88
+ return { trustedComment }
89
+ }
90
+
91
+ module.exports = { sha256Hex, manifestHasHash, verifyMinisign, PUBKEY_B64 }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "auxly-cli",
3
+ "version": "1.0.21",
4
+ "description": "Local-first unified memory system for AI agents — installs the prebuilt, signature-verified auxly binary.",
5
+ "keywords": [
6
+ "auxly",
7
+ "ai",
8
+ "memory",
9
+ "mcp",
10
+ "cli",
11
+ "agents"
12
+ ],
13
+ "homepage": "https://auxly.io",
14
+ "bugs": "https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli/issues",
15
+ "license": "MIT",
16
+ "author": "Tzamun Arabia IT Co. <hi@auxly.io>",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/Tzamun-Arabia-IT-Co/auxly-memory-cli.git",
20
+ "directory": "npm"
21
+ },
22
+ "bin": {
23
+ "auxly": "bin/auxly.js"
24
+ },
25
+ "scripts": {
26
+ "postinstall": "node install.js"
27
+ },
28
+ "files": [
29
+ "install.js",
30
+ "bin/auxly.js",
31
+ "lib/verify.js",
32
+ "README.md"
33
+ ],
34
+ "engines": {
35
+ "node": ">=16"
36
+ },
37
+ "os": [
38
+ "darwin",
39
+ "linux",
40
+ "win32"
41
+ ],
42
+ "cpu": [
43
+ "x64",
44
+ "arm64"
45
+ ]
46
+ }