gophermind 0.1.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/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # gophermind (npm)
2
+
3
+ A tiny, hackable AI coding agent for your terminal — pointed at your own
4
+ OpenAI-compatible LLM.
5
+
6
+ ```sh
7
+ npm install -g gophermind
8
+ gophermind # first run walks you through setup, then chats
9
+ ```
10
+
11
+ This package downloads the prebuilt `gophermind` binary for your platform
12
+ (macOS / Linux / Windows, x64 / arm64) from the project's GitHub Releases on
13
+ install, and exposes it as the `gophermind` command.
14
+
15
+ - Full docs & source: **https://github.com/jbrahy/gophermind.com**
16
+ - Prefer Homebrew on macOS? `brew install jbrahy/tap/gophermind`
17
+
18
+ Environment knobs for install:
19
+
20
+ - `GOPHERMIND_SKIP_DOWNLOAD=1` — skip the binary download (e.g. CI that doesn't run it)
21
+ - `GOPHERMIND_DOWNLOAD_BASE=<url>` — override the release download base URL
22
+
23
+ MIT licensed. Startup fortunes © Brian M. Clapper, CC BY 4.0.
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Thin launcher: exec the platform binary that postinstall downloaded into
5
+ // vendor/. Forwards argv, stdio, and exit code so `npx gophermind` / a globally
6
+ // installed `gophermind` behave exactly like the native binary.
7
+ const path = require('path');
8
+ const { spawnSync } = require('child_process');
9
+
10
+ const binName = process.platform === 'win32' ? 'gophermind.exe' : 'gophermind';
11
+ const bin = path.join(__dirname, '..', 'vendor', binName);
12
+
13
+ const res = spawnSync(bin, process.argv.slice(2), { stdio: 'inherit' });
14
+
15
+ if (res.error) {
16
+ if (res.error.code === 'ENOENT') {
17
+ console.error(
18
+ 'gophermind: binary not found — the postinstall download may have failed.\n' +
19
+ 'Reinstall with: npm rebuild gophermind (or reinstall the package)'
20
+ );
21
+ } else {
22
+ console.error('gophermind: ' + res.error.message);
23
+ }
24
+ process.exit(1);
25
+ }
26
+
27
+ process.exit(res.status === null ? 1 : res.status);
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "gophermind",
3
+ "version": "0.1.0",
4
+ "description": "A tiny, hackable AI coding agent for your terminal — pointed at your own OpenAI-compatible LLM.",
5
+ "bin": {
6
+ "gophermind": "bin/gophermind.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/download.js"
10
+ },
11
+ "files": [
12
+ "bin/gophermind.js",
13
+ "scripts/download.js",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=16"
18
+ },
19
+ "os": [
20
+ "darwin",
21
+ "linux",
22
+ "win32"
23
+ ],
24
+ "cpu": [
25
+ "x64",
26
+ "arm64"
27
+ ],
28
+ "keywords": [
29
+ "ai",
30
+ "agent",
31
+ "llm",
32
+ "coding",
33
+ "cli",
34
+ "openai",
35
+ "tui",
36
+ "gopher"
37
+ ],
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/jbrahy/gophermind.com.git"
41
+ },
42
+ "homepage": "https://github.com/jbrahy/gophermind.com",
43
+ "bugs": {
44
+ "url": "https://github.com/jbrahy/gophermind.com/issues"
45
+ },
46
+ "author": "John Brahy",
47
+ "license": "MIT"
48
+ }
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Postinstall: download the gophermind binary for this platform/arch from the
5
+ // matching GitHub Release and extract it into vendor/. The release asset names
6
+ // are produced by GoReleaser (see .goreleaser.yaml archives.name_template).
7
+ //
8
+ // Env:
9
+ // GOPHERMIND_SKIP_DOWNLOAD=1 skip (e.g. CI that doesn't need the binary)
10
+ // GOPHERMIND_DOWNLOAD_BASE=url override the release base URL (testing/mirrors)
11
+
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+ const path = require('path');
15
+ const https = require('https');
16
+ const { execFileSync } = require('child_process');
17
+
18
+ const REPO = 'jbrahy/gophermind.com';
19
+ const version = require('../package.json').version;
20
+
21
+ if (process.env.GOPHERMIND_SKIP_DOWNLOAD) {
22
+ console.log('gophermind: GOPHERMIND_SKIP_DOWNLOAD set — skipping binary download.');
23
+ process.exit(0);
24
+ }
25
+
26
+ function assetName() {
27
+ const v = version;
28
+ const arch = process.arch === 'arm64' ? 'arm64' : process.arch === 'x64' ? 'amd64' : null;
29
+ switch (process.platform) {
30
+ case 'darwin':
31
+ return `gophermind_${v}_darwin_all.tar.gz`; // universal (arm64 + x64)
32
+ case 'linux':
33
+ return arch && `gophermind_${v}_linux_${arch}.tar.gz`;
34
+ case 'win32':
35
+ return arch && `gophermind_${v}_windows_${arch}.zip`;
36
+ default:
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function fail(msg) {
42
+ console.error('gophermind: ' + msg);
43
+ process.exit(1);
44
+ }
45
+
46
+ function download(url, dest, redirects) {
47
+ redirects = redirects || 0;
48
+ if (redirects > 10) return fail('too many redirects fetching ' + url);
49
+ return new Promise((resolve, reject) => {
50
+ https
51
+ .get(url, { headers: { 'User-Agent': 'gophermind-npm' } }, (res) => {
52
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
53
+ res.resume();
54
+ return resolve(download(res.headers.location, dest, redirects + 1));
55
+ }
56
+ if (res.statusCode !== 200) {
57
+ res.resume();
58
+ return reject(new Error('HTTP ' + res.statusCode + ' for ' + url));
59
+ }
60
+ const out = fs.createWriteStream(dest);
61
+ res.pipe(out);
62
+ out.on('finish', () => out.close(resolve));
63
+ out.on('error', reject);
64
+ })
65
+ .on('error', reject);
66
+ });
67
+ }
68
+
69
+ async function main() {
70
+ const asset = assetName();
71
+ if (!asset) {
72
+ fail(`unsupported platform/arch: ${process.platform}/${process.arch}`);
73
+ }
74
+ const base =
75
+ process.env.GOPHERMIND_DOWNLOAD_BASE ||
76
+ `https://github.com/${REPO}/releases/download/v${version}`;
77
+ const url = `${base}/${asset}`;
78
+
79
+ const vendor = path.join(__dirname, '..', 'vendor');
80
+ fs.mkdirSync(vendor, { recursive: true });
81
+ const tmp = path.join(os.tmpdir(), asset);
82
+
83
+ console.log(`gophermind: downloading ${asset} ...`);
84
+ try {
85
+ await download(url, tmp);
86
+ } catch (e) {
87
+ fail(`download failed (${e.message}).\n URL: ${url}`);
88
+ }
89
+
90
+ // `tar` extracts both .tar.gz (macOS/Linux) and .zip (bsdtar on Windows 10+).
91
+ try {
92
+ execFileSync('tar', ['-xf', tmp, '-C', vendor], { stdio: 'inherit' });
93
+ } catch (e) {
94
+ fail('extract failed: ' + e.message);
95
+ } finally {
96
+ try { fs.unlinkSync(tmp); } catch (_) {}
97
+ }
98
+
99
+ const binName = process.platform === 'win32' ? 'gophermind.exe' : 'gophermind';
100
+ const bin = path.join(vendor, binName);
101
+ if (!fs.existsSync(bin)) {
102
+ fail('binary not found in archive after extraction: ' + binName);
103
+ }
104
+ if (process.platform !== 'win32') {
105
+ fs.chmodSync(bin, 0o755);
106
+ }
107
+ console.log('gophermind: installed ' + binName);
108
+ }
109
+
110
+ main();