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 +23 -0
- package/bin/gophermind.js +27 -0
- package/package.json +48 -0
- package/scripts/download.js +110 -0
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();
|