coordigent 0.1.0 → 0.1.3
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 +21 -0
- package/README.md +46 -11
- package/bin/coord-mcp.js +6 -0
- package/bin/coord.js +6 -0
- package/bin/coordigent.js +54 -11
- package/package.json +19 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Coordigent, Inc.
|
|
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
CHANGED
|
@@ -1,26 +1,54 @@
|
|
|
1
1
|
# Coordigent npm launcher
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Coordigent's `coord` CLI and `coord-mcp` MCP server, from npm:
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
npm i -g coordigent
|
|
7
|
+
coord connect
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
`npm i -g coordigent` puts three commands on `PATH`: `coord` runs `coord`, `coord-mcp` runs
|
|
11
|
+
`coord-mcp`, and `coordigent` runs `coord` (or `coord-mcp` with `mcp` first, below). So every
|
|
12
|
+
`coord …` command in the docs works as written. Without installing: `npx coordigent connect`.
|
|
13
|
+
|
|
14
|
+
As an MCP server (stdio), for any MCP client, and the npm entry of the
|
|
15
|
+
[MCP Registry listing](../../docs/operations.md#mcp-registry):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{ "mcpServers": { "coordigent": { "command": "npx", "args": ["-y", "coordigent", "mcp"] } } }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`coord-mcp [args]`, and `coordigent mcp [args]`, run `coord-mcp [args]` after the same first-run
|
|
22
|
+
download and checks. Everything the launcher prints goes to stderr, so stdout stays the MCP
|
|
23
|
+
channel. `coord-mcp` reads the login from `~/.tower/config.json` (`npx coordigent login`) and the
|
|
24
|
+
repo from the folder it starts in, or `COORDIGENT_REPO`.
|
|
12
25
|
|
|
13
26
|
The package holds one Node file and no binaries. On first run it downloads `coord` and
|
|
14
27
|
`coord-mcp` for this machine from the server's `/install/<artifact>`, checks each against the
|
|
15
28
|
SHA-256 published in `/install/version`, and puts them where the installers do. After that, and on
|
|
16
|
-
every later run, it runs `coord` with the same arguments and exits with its exit
|
|
29
|
+
every later run, it runs `coord` (or `coord-mcp`) with the same arguments and exits with its exit
|
|
30
|
+
code. Because the
|
|
17
31
|
binaries live where `install.sh` puts them, `coord update` and every MCP config keep working
|
|
18
32
|
unchanged.
|
|
19
33
|
|
|
20
34
|
- **Platforms:** macOS arm64 and x64 (an x64 Node under Rosetta gets the arm64 build), glibc Linux
|
|
21
35
|
x64 and arm64, Windows x64. Anything else, and Alpine/musl, exits 1 before downloading.
|
|
22
36
|
- **Where:** `~/.tower/bin`, or `%LOCALAPPDATA%\Coordigent\bin` on Windows (as `install.ps1`).
|
|
23
|
-
`TOWER_BIN_DIR` overrides both. The
|
|
37
|
+
`TOWER_BIN_DIR` overrides both. The launcher never edits `PATH`: npm's global bin folder, already
|
|
38
|
+
on it, holds the `coord`, `coord-mcp` and `coordigent` commands, which run the binaries there.
|
|
39
|
+
- **Which bin runs what:** each bin is its own file: `bin/coord.js` always runs `coord`,
|
|
40
|
+
`bin/coord-mcp.js` always runs `coord-mcp`, and `bin/coordigent.js` (the launcher itself) reads
|
|
41
|
+
`mcp` from its first argument. Not one file checking the name it was run as: on Windows npm's
|
|
42
|
+
`.cmd` shim runs `node <bin file>`, so the file is all that says which command was typed.
|
|
43
|
+
- **Next to `install.sh`:** a `coord` from the installer (`~/.tower/bin`) and one from npm can
|
|
44
|
+
both be on `PATH`. Whichever comes first starts, and both run the same `~/.tower/bin/coord`, so
|
|
45
|
+
it does not matter which. An npm global prefix of `~/.tower` would link npm's `coord` into the
|
|
46
|
+
folder the binaries go in; the launcher refuses that with a message rather than run itself.
|
|
47
|
+
- **Updating and removing:** `coord update` updates the binaries, as for any install;
|
|
48
|
+
`npm update -g coordigent` updates only this launcher. To remove everything, `coord uninstall`
|
|
49
|
+
first (binaries, hooks, `~/.tower`), then `npm rm -g coordigent`. Removing only the package
|
|
50
|
+
leaves the binaries in place, and running npm's `coord` after `coord uninstall` downloads them
|
|
51
|
+
again.
|
|
24
52
|
- **Which server:** `COORDIGENT_SERVER_URL`, then `TOWER_SERVER_URL`, then the `serverUrl` saved in
|
|
25
53
|
`~/.tower/config.json`, then `https://coordigent.com`: the order `coord` itself uses. A machine
|
|
26
54
|
with no config yet gets one naming that server, with no token, as `install.sh` writes.
|
|
@@ -36,8 +64,11 @@ unchanged.
|
|
|
36
64
|
|
|
37
65
|
Tests: `bun test packaging/npm` from the repo root (a local fake server stands in for
|
|
38
66
|
`/install`). CI runs `npm pack --dry-run` on it (`.github/workflows/ci.yml`, job `npm-package`)
|
|
39
|
-
and fails if the tarball holds anything but `bin/coordigent.js`, `
|
|
40
|
-
|
|
67
|
+
and fails if the tarball holds anything but `bin/coordigent.js`, `bin/coord.js`, `bin/coord-mcp.js`,
|
|
68
|
+
`LICENSE` (MIT), `README.md` and `package.json`, if `bin` does not map `coord`, `coord-mcp` and
|
|
69
|
+
`coordigent` to those three files, if any of them is not executable, or if it gains an
|
|
70
|
+
install-time script. The tests also pack the package and `npm i -g` the tarball into a scratch
|
|
71
|
+
prefix, then run each linked command. Both that check and the release checks are
|
|
41
72
|
`scripts/release-checks.js`, which is not shipped.
|
|
42
73
|
|
|
43
74
|
## Publishing
|
|
@@ -45,11 +76,13 @@ or gains an install-time script. Both that check and the release checks are
|
|
|
45
76
|
`.github/workflows/publish-npm.yml` publishes on a tag `npm-v<version>` (the `v*` tags publish the
|
|
46
77
|
container image and never touch npm), or by hand from Actions with an existing tag. It uses npm
|
|
47
78
|
trusted publishing: no `NPM_TOKEN`; npm trades the job's GitHub OIDC token for a one-time
|
|
48
|
-
credential, and `npm publish --
|
|
79
|
+
credential, and `npm publish --access public` publishes it (no provenance: npm only attests public source repos, and this repo is private). Before
|
|
49
80
|
publishing, `scripts/release-checks.js release <tag>` refuses, with the reason, when:
|
|
50
81
|
|
|
51
82
|
- the tag is not exactly `npm-v` plus `package.json`'s `version`;
|
|
52
83
|
- the name is not `coordigent`;
|
|
84
|
+
- `mcpName` is not `com.coordigent/coordigent`, which the MCP Registry reads from the published
|
|
85
|
+
version to accept the listing's npm entry;
|
|
53
86
|
- `package.json` still has `"private": true`. It stays until the steps below are done, so
|
|
54
87
|
until then every run of the workflow fails at that check and publishes nothing.
|
|
55
88
|
|
|
@@ -73,4 +106,6 @@ publishing, `scripts/release-checks.js release <tag>` refuses, with the reason,
|
|
|
73
106
|
`git tag npm-v<version> <commit> && git push origin npm-v<version>`. The workflow publishes;
|
|
74
107
|
the version page on npmjs.com then shows its provenance, linked to that run.
|
|
75
108
|
|
|
76
|
-
Each later release: bump `version` in a PR, merge, push `npm-v<version>`.
|
|
109
|
+
Each later release: bump `version` in a PR, merge, push `npm-v<version>`. Bump `version` and
|
|
110
|
+
`packages[0].version` in the root `server.json` in the same PR (a test holds them equal), and
|
|
111
|
+
after npm has published, publish the listing (docs/operations.md, "MCP Registry").
|
package/bin/coord-mcp.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `coord-mcp <args>` after `npm i -g coordigent`: the launcher, always running coord-mcp, the
|
|
3
|
+
// stdio MCP server (bin/coordigent.js). Nothing but coord-mcp writes to stdout.
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
require("./coordigent.js").main(process.argv.slice(2), process.env, "coord-mcp");
|
package/bin/coord.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `coord <args>` after `npm i -g coordigent`: the launcher, always running coord
|
|
3
|
+
// (bin/coordigent.js). Everything is passed through, `mcp` included.
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
require("./coordigent.js").main(process.argv.slice(2), process.env, "coord");
|
package/bin/coordigent.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// The npm launcher: `npx coordigent <args
|
|
2
|
+
// The npm launcher: `npx coordigent <args>`, or after `npm i -g coordigent`, `coord <args>`,
|
|
3
|
+
// `coord-mcp <args>` and `coordigent <args>`.
|
|
3
4
|
//
|
|
4
5
|
// It ships no binaries. On first run it downloads coord and coord-mcp for this
|
|
5
6
|
// machine from the server's /install/<artifact>, checks each against the SHA-256
|
|
@@ -8,18 +9,29 @@
|
|
|
8
9
|
// and on every later run, it runs `coord <args>`. Because the binaries live where
|
|
9
10
|
// the installers put them, `coord update` and every MCP config keep working.
|
|
10
11
|
//
|
|
12
|
+
// `coordigent mcp [args]` runs coord-mcp instead: the stdio MCP server, for an MCP
|
|
13
|
+
// client configured with `npx -y coordigent mcp` (the MCP Registry's npm entry,
|
|
14
|
+
// server.json). Its stdout is the MCP channel, so the launcher writes only to stderr.
|
|
15
|
+
//
|
|
16
|
+
// The package's `coord` and `coord-mcp` bins are bin/coord.js and bin/coord-mcp.js, which
|
|
17
|
+
// call main() here with the binary fixed. Separate files, not a check of the name this was
|
|
18
|
+
// invoked as: on Windows npm's .cmd shim runs `node <bin file>`, so the file is all that
|
|
19
|
+
// says which command was typed.
|
|
20
|
+
//
|
|
11
21
|
// Plain Node with no dependencies and no install scripts: the download happens at
|
|
12
22
|
// run time, so `npm i --ignore-scripts` installs a working launcher.
|
|
13
23
|
"use strict";
|
|
14
24
|
|
|
15
25
|
const { spawn, execFileSync } = require("node:child_process");
|
|
16
26
|
const { createHash } = require("node:crypto");
|
|
17
|
-
const { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } = require("node:fs");
|
|
18
27
|
const { homedir } = require("node:os");
|
|
19
|
-
const {
|
|
28
|
+
const { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } = require("node:fs");
|
|
29
|
+
const { join, dirname } = require("node:path");
|
|
20
30
|
|
|
21
31
|
const HOSTED_SERVER_URL = "https://coordigent.com";
|
|
22
32
|
const BINARIES = ["coord", "coord-mcp"];
|
|
33
|
+
/** The first argument that runs coord-mcp rather than coord. coord has no `mcp` command. */
|
|
34
|
+
const MCP_MODE = "mcp";
|
|
23
35
|
|
|
24
36
|
/** A failure the person can act on: printed as one message, exit 1, no stack. */
|
|
25
37
|
class LauncherError extends Error {}
|
|
@@ -133,7 +145,7 @@ function downloadFailure(response, url, platform) {
|
|
|
133
145
|
return new LauncherError(`could not download ${url}\nWindows build not available yet.`);
|
|
134
146
|
}
|
|
135
147
|
return new LauncherError(
|
|
136
|
-
`could not download ${url} (HTTP ${response.status})\nThe server may not be publishing binaries. See docs/
|
|
148
|
+
`could not download ${url} (HTTP ${response.status})\nThe server may not be publishing binaries. See https://coordigent.com/docs/get-started/install.`
|
|
137
149
|
);
|
|
138
150
|
}
|
|
139
151
|
|
|
@@ -187,13 +199,36 @@ function rememberServer(env, server) {
|
|
|
187
199
|
writeFileSync(config, `{\n "serverUrl": "${server}"\n}\n`, { mode: 0o600, flag: "wx" });
|
|
188
200
|
}
|
|
189
201
|
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Which binary to run, and what to pass it. The `coord` and `coord-mcp` bins fix the binary and
|
|
204
|
+
* pass every argument through. `coordigent` reads it from the arguments: `mcp …` is coord-mcp,
|
|
205
|
+
* anything else coord.
|
|
206
|
+
*/
|
|
207
|
+
function resolveCommand(args, fixed) {
|
|
208
|
+
if (BINARIES.includes(fixed)) return { name: fixed, args };
|
|
209
|
+
return args[0] === MCP_MODE ? { name: "coord-mcp", args: args.slice(1) } : { name: "coord", args };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* True when `target` is one of this package's own bins rather than a binary: what npm leaves in
|
|
214
|
+
* ~/.tower/bin when its global prefix is ~/.tower. Running it would start this launcher again,
|
|
215
|
+
* forever.
|
|
216
|
+
*/
|
|
217
|
+
function isLauncherItself(target) {
|
|
218
|
+
try {
|
|
219
|
+
return dirname(realpathSync(target)) === realpathSync(__dirname);
|
|
220
|
+
} catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function run(binary, args) {
|
|
226
|
+
const child = spawn(binary, args, { stdio: "inherit" });
|
|
192
227
|
// Ctrl-C reaches coord from the terminal already; stay alive until it exits.
|
|
193
228
|
process.on("SIGINT", () => {});
|
|
194
229
|
for (const signal of ["SIGTERM", "SIGHUP"]) process.on(signal, () => child.kill(signal));
|
|
195
230
|
child.on("error", (error) => {
|
|
196
|
-
process.stderr.write(`coordigent: could not run ${
|
|
231
|
+
process.stderr.write(`coordigent: could not run ${binary}: ${error.message}\n`);
|
|
197
232
|
process.exit(1);
|
|
198
233
|
});
|
|
199
234
|
child.on("exit", (code, signal) => {
|
|
@@ -205,14 +240,22 @@ function run(coord, args) {
|
|
|
205
240
|
});
|
|
206
241
|
}
|
|
207
242
|
|
|
208
|
-
|
|
243
|
+
/** `fixed` is "coord" or "coord-mcp" from those bins; absent for `coordigent`. */
|
|
244
|
+
async function main(args = process.argv.slice(2), env = process.env, fixed = undefined) {
|
|
209
245
|
const log = (line) => process.stderr.write(`${line}\n`);
|
|
210
246
|
try {
|
|
211
247
|
const binDir = resolveBinDir(env);
|
|
212
248
|
// The platform is resolved before anything is fetched or written, like install.sh.
|
|
213
249
|
const platform = resolvePlatform();
|
|
214
250
|
const suffix = exeSuffix(platform);
|
|
215
|
-
const
|
|
251
|
+
const command = resolveCommand(args, fixed);
|
|
252
|
+
const binary = join(binDir, `${command.name}${suffix}`);
|
|
253
|
+
if (isLauncherItself(binary)) {
|
|
254
|
+
throw new LauncherError(
|
|
255
|
+
`${binary} is this npm launcher, not the ${command.name} binary: npm's global prefix is the folder\n` +
|
|
256
|
+
"the binaries go in. Install with another npm prefix, or set TOWER_BIN_DIR to another folder."
|
|
257
|
+
);
|
|
258
|
+
}
|
|
216
259
|
if (!BINARIES.every((name) => existsSync(join(binDir, `${name}${suffix}`)))) {
|
|
217
260
|
const server = resolveServer(env);
|
|
218
261
|
await install({ server, binDir, platform, fetchImpl: fetch, log });
|
|
@@ -222,7 +265,7 @@ async function main(args = process.argv.slice(2), env = process.env) {
|
|
|
222
265
|
// Optional, as in install.sh: coord login records the server too.
|
|
223
266
|
}
|
|
224
267
|
}
|
|
225
|
-
run(
|
|
268
|
+
run(binary, command.args);
|
|
226
269
|
} catch (error) {
|
|
227
270
|
if (!(error instanceof LauncherError)) throw error;
|
|
228
271
|
log(`coordigent: ${error.message}`);
|
|
@@ -230,6 +273,6 @@ async function main(args = process.argv.slice(2), env = process.env) {
|
|
|
230
273
|
}
|
|
231
274
|
}
|
|
232
275
|
|
|
233
|
-
module.exports = { resolvePlatform, resolveServer, resolveBinDir };
|
|
276
|
+
module.exports = { main, resolvePlatform, resolveServer, resolveBinDir, resolveCommand };
|
|
234
277
|
|
|
235
278
|
if (require.main === module) main();
|
package/package.json
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coordigent",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Coordigent's coord and coord-mcp commands: downloads the binaries for this machine on first run, checks their SHA-256, and runs them. `npx coordigent` and `npx coordigent mcp` work too.",
|
|
5
5
|
"homepage": "https://coordigent.com",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"mcpName": "com.coordigent/coordigent",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"mcp-server",
|
|
11
|
+
"coding-agents",
|
|
12
|
+
"multi-agent",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"codex",
|
|
15
|
+
"cursor",
|
|
16
|
+
"coordination",
|
|
17
|
+
"developer-tools"
|
|
18
|
+
],
|
|
6
19
|
"repository": {
|
|
7
20
|
"type": "git",
|
|
8
21
|
"url": "git+https://github.com/startupproj/coordigent.git",
|
|
9
22
|
"directory": "packaging/npm"
|
|
10
23
|
},
|
|
11
24
|
"bin": {
|
|
25
|
+
"coord": "bin/coord.js",
|
|
26
|
+
"coord-mcp": "bin/coord-mcp.js",
|
|
12
27
|
"coordigent": "bin/coordigent.js"
|
|
13
28
|
},
|
|
14
29
|
"files": [
|
|
30
|
+
"bin/coord.js",
|
|
31
|
+
"bin/coord-mcp.js",
|
|
15
32
|
"bin/coordigent.js"
|
|
16
33
|
],
|
|
17
34
|
"engines": {
|