@copilot-datagate/cli 0.4.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 +22 -0
- package/bin/copilot-datagate.js +145 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @copilot-datagate/cli
|
|
2
|
+
|
|
3
|
+
Thin npm wrapper for DataGate. The canonical binaries are published in GitHub
|
|
4
|
+
Releases; this package exists for MCP clients and editors that prefer an `npx`
|
|
5
|
+
install path.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx -y @copilot-datagate/cli mcp stdio
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The wrapper downloads the matching GitHub Release binary for the host platform
|
|
12
|
+
and dispatches arguments to it.
|
|
13
|
+
|
|
14
|
+
## Environment
|
|
15
|
+
|
|
16
|
+
- `COPILOT_DATAGATE_BIN`: use an already installed binary instead of downloading.
|
|
17
|
+
- `COPILOT_DATAGATE_VERSION`: override the wrapper package version when selecting
|
|
18
|
+
the release tag.
|
|
19
|
+
- `COPILOT_DATAGATE_CACHE`: override the binary cache directory.
|
|
20
|
+
|
|
21
|
+
Database credentials are not handled by this package. Configure DataGate through
|
|
22
|
+
project-local `.datagate/datagate.toml` and environment variables.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const childProcess = require('node:child_process');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const https = require('node:https');
|
|
7
|
+
const os = require('node:os');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
|
|
10
|
+
const REPOSITORY = 'afurlane/copilot-datagate';
|
|
11
|
+
|
|
12
|
+
function platformName(platform = process.platform, arch = process.arch) {
|
|
13
|
+
const archName = arch === 'x64' ? 'x86_64' : arch === 'arm64' ? 'aarch64' : null;
|
|
14
|
+
if (!archName) {
|
|
15
|
+
throw new Error(`unsupported architecture: ${arch}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (platform === 'linux') return `linux-${archName}`;
|
|
19
|
+
if (platform === 'darwin') return `macos-${archName}`;
|
|
20
|
+
if (platform === 'win32') return `windows-${archName}`;
|
|
21
|
+
throw new Error(`unsupported platform: ${platform}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function packageVersion() {
|
|
25
|
+
if (process.env.COPILOT_DATAGATE_VERSION) return process.env.COPILOT_DATAGATE_VERSION;
|
|
26
|
+
const packageJson = require('../package.json');
|
|
27
|
+
return packageJson.version;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function releaseTag(version = packageVersion()) {
|
|
31
|
+
return version.startsWith('copilot-datagate-v') ? version : `copilot-datagate-v${version}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function archiveExtension(platform = process.platform) {
|
|
35
|
+
return platform === 'win32' ? 'zip' : 'tar.gz';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function archiveName(version = packageVersion(), platform = process.platform, arch = process.arch) {
|
|
39
|
+
const tag = releaseTag(version);
|
|
40
|
+
return `copilot-datagate-${tag}-${platformName(platform, arch)}.${archiveExtension(platform)}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function archiveUrl(version = packageVersion(), platform = process.platform, arch = process.arch) {
|
|
44
|
+
const tag = releaseTag(version);
|
|
45
|
+
return `https://github.com/${REPOSITORY}/releases/download/${tag}/${archiveName(version, platform, arch)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cacheRoot() {
|
|
49
|
+
return process.env.COPILOT_DATAGATE_CACHE || path.join(os.homedir(), '.cache', 'copilot-datagate');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function executableName(platform = process.platform) {
|
|
53
|
+
return platform === 'win32' ? 'copilot-datagate.exe' : 'copilot-datagate';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function cachedBinaryPath(version = packageVersion(), platform = process.platform, arch = process.arch) {
|
|
57
|
+
return path.join(cacheRoot(), releaseTag(version), platformName(platform, arch), executableName(platform));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function download(url, destination) {
|
|
61
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const request = https.get(url, response => {
|
|
64
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
65
|
+
response.resume();
|
|
66
|
+
download(response.headers.location, destination).then(resolve, reject);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (response.statusCode !== 200) {
|
|
70
|
+
response.resume();
|
|
71
|
+
reject(new Error(`download failed with status ${response.statusCode}: ${url}`));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const file = fs.createWriteStream(destination);
|
|
75
|
+
response.pipe(file);
|
|
76
|
+
file.on('finish', () => file.close(resolve));
|
|
77
|
+
file.on('error', reject);
|
|
78
|
+
});
|
|
79
|
+
request.on('error', reject);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function extract(archivePath, destination) {
|
|
84
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
85
|
+
childProcess.execFileSync('tar', ['-xf', archivePath, '-C', destination], { stdio: 'inherit' });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function ensureBinary() {
|
|
89
|
+
if (process.env.COPILOT_DATAGATE_BIN) return process.env.COPILOT_DATAGATE_BIN;
|
|
90
|
+
|
|
91
|
+
const binaryPath = cachedBinaryPath();
|
|
92
|
+
if (fs.existsSync(binaryPath)) return binaryPath;
|
|
93
|
+
|
|
94
|
+
const archivePath = path.join(cacheRoot(), releaseTag(), archiveName());
|
|
95
|
+
const extractDir = path.dirname(binaryPath);
|
|
96
|
+
await download(archiveUrl(), archivePath);
|
|
97
|
+
extract(archivePath, extractDir);
|
|
98
|
+
|
|
99
|
+
const nestedBinary = findBinary(extractDir);
|
|
100
|
+
if (!nestedBinary) {
|
|
101
|
+
throw new Error(`unable to find ${executableName()} in downloaded archive`);
|
|
102
|
+
}
|
|
103
|
+
if (nestedBinary !== binaryPath) {
|
|
104
|
+
fs.renameSync(nestedBinary, binaryPath);
|
|
105
|
+
}
|
|
106
|
+
if (process.platform !== 'win32') {
|
|
107
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
108
|
+
}
|
|
109
|
+
return binaryPath;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function findBinary(root) {
|
|
113
|
+
const pending = [root];
|
|
114
|
+
while (pending.length > 0) {
|
|
115
|
+
const current = pending.pop();
|
|
116
|
+
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
117
|
+
const fullPath = path.join(current, entry.name);
|
|
118
|
+
if (entry.isDirectory()) pending.push(fullPath);
|
|
119
|
+
if (entry.isFile() && entry.name === executableName()) return fullPath;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function main() {
|
|
126
|
+
const binary = await ensureBinary();
|
|
127
|
+
const result = childProcess.spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
128
|
+
if (result.error) throw result.error;
|
|
129
|
+
process.exit(result.status ?? 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (require.main === module) {
|
|
133
|
+
main().catch(error => {
|
|
134
|
+
console.error(error.message);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = {
|
|
140
|
+
archiveName,
|
|
141
|
+
archiveUrl,
|
|
142
|
+
platformName,
|
|
143
|
+
releaseTag,
|
|
144
|
+
executableName,
|
|
145
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@copilot-datagate/cli",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Policy-driven, read-only MCP server for safe database access from AI tools.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/afurlane/copilot-datagate.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/afurlane/copilot-datagate",
|
|
11
|
+
"mcpName": "io.github.afurlane/copilot-datagate",
|
|
12
|
+
"bin": {
|
|
13
|
+
"copilot-datagate": "bin/copilot-datagate.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "node test/platform.test.js"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
}
|
|
25
|
+
}
|