@volter/supercode 0.5.150 → 0.5.151
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 +6 -4
- package/bin/supercode.js +45 -24
- package/lib/commands.mjs +21 -0
- package/lib/front-door.mjs +27 -0
- package/lib/workflow.mjs +54 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -13,13 +13,15 @@ supercode login --provider # paste your OpenRouter key
|
|
|
13
13
|
supercode run "fix the failing test in src/lib.rs"
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
This package is
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
This package is supercode's front door. Commands that have moved to TypeScript are served
|
|
17
|
+
here, in Node (`supercode front-door` lists them); every other command goes to the native binary,
|
|
18
|
+
which ships as a platform-specific optional dependency (`@volter/supercode-cli-<os>-<cpu>`), so
|
|
19
|
+
`npm` downloads only the build matching your machine — no compile step, no postinstall network fetch.
|
|
19
20
|
|
|
20
21
|
Supported platforms: `darwin-arm64`, `darwin-x64`, `linux-x64`, `linux-arm64`,
|
|
21
22
|
`win32-x64`.
|
|
22
|
-
On other platforms install from source
|
|
23
|
+
On other platforms install from source
|
|
24
|
+
(`cargo install --git https://github.com/volter-ai/supercode supercode-cli`) or via
|
|
23
25
|
the [install script](https://github.com/volter-ai/supercode#install).
|
|
24
26
|
|
|
25
27
|
Full docs, the SDK, and source: <https://github.com/volter-ai/supercode>.
|
package/bin/supercode.js
CHANGED
|
@@ -1,38 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// platform-specific optional dependency
|
|
4
|
-
// (`@volter/supercode-cli-<os>-<cpu
|
|
5
|
-
//
|
|
6
|
-
// forwarding argv, stdio (so the interactive REPL/TTY works), and the exit code.
|
|
2
|
+
// The `supercode` front door. A command that has moved to TypeScript (lib/commands.mjs) is served here, in Node; every
|
|
3
|
+
// other command goes to the native binary, which ships in a platform-specific optional dependency
|
|
4
|
+
// (`@volter/supercode-cli-<os>-<cpu>`, npm installs only the one matching the host), with argv, stdio (so the
|
|
5
|
+
// interactive REPL/TTY works) and the exit code forwarded as before (arc t_08d00e09, route step 2).
|
|
7
6
|
"use strict";
|
|
8
7
|
|
|
9
8
|
const { spawnSync } = require("child_process");
|
|
9
|
+
const { pathToFileURL } = require("url");
|
|
10
|
+
const path = require("path");
|
|
10
11
|
|
|
11
12
|
const platform = process.platform; // darwin | linux | win32 | ...
|
|
12
13
|
const arch = process.arch; // arm64 | x64 | ...
|
|
13
14
|
const pkg = `@volter/supercode-cli-${platform}-${arch}`;
|
|
14
15
|
const binName = platform === "win32" ? "supercode.exe" : "supercode";
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`Otherwise install from source (cargo install supercode-cli) or via the\n` +
|
|
24
|
-
`install script: https://github.com/volter-ai/supercode#install`
|
|
25
|
-
);
|
|
26
|
-
process.exit(1);
|
|
17
|
+
/** The native binary's path, or null when no platform package is installed. */
|
|
18
|
+
function nativeBinary() {
|
|
19
|
+
try {
|
|
20
|
+
return require.resolve(`${pkg}/bin/${binName}`);
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
27
24
|
}
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
function runNative(args) {
|
|
27
|
+
const binPath = nativeBinary();
|
|
28
|
+
if (!binPath) {
|
|
29
|
+
console.error(
|
|
30
|
+
`supercode: no prebuilt binary for ${platform}-${arch}.\n` +
|
|
31
|
+
`Supported via npm: darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64.\n` +
|
|
32
|
+
`Otherwise install from source (cargo install --git https://github.com/volter-ai/supercode supercode-cli)\n` +
|
|
33
|
+
`or via the install script: https://github.com/volter-ai/supercode#install`
|
|
34
|
+
);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const result = spawnSync(binPath, args, { stdio: "inherit" });
|
|
38
|
+
if (result.error) {
|
|
39
|
+
console.error(result.error.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (result.signal) process.exit(1);
|
|
43
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
33
44
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
process.
|
|
45
|
+
|
|
46
|
+
async function main() {
|
|
47
|
+
const args = process.argv.slice(2);
|
|
48
|
+
const { route } = await import(pathToFileURL(path.join(__dirname, "..", "lib", "commands.mjs")).href);
|
|
49
|
+
const served = route(args);
|
|
50
|
+
if (!served) return runNative(args);
|
|
51
|
+
const command = await import(pathToFileURL(path.join(__dirname, "..", "lib", served.module)).href);
|
|
52
|
+
const code = await command.run(served.rest, { native: { path: nativeBinary(), package: pkg, run: runNative } });
|
|
53
|
+
process.exit(typeof code === "number" ? code : 0);
|
|
37
54
|
}
|
|
38
|
-
|
|
55
|
+
|
|
56
|
+
main().catch((error) => {
|
|
57
|
+
console.error(`supercode: ${error && error.message ? error.message : error}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
package/lib/commands.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The commands the front door serves in TypeScript (arc t_08d00e09). Each row is a command path, the leading words of
|
|
2
|
+
// argv, and the module under lib/ that serves it; a module exports `run(rest, context) -> exit code`. Any argv whose
|
|
3
|
+
// leading words match no row goes to the native binary untouched, so a command not listed here answers as before.
|
|
4
|
+
// The longest matching path wins, so one verb of a command can move before its siblings (`message send` before
|
|
5
|
+
// `message watch`). Global options before the command (`supercode --quiet message send`) are not parsed here: such a
|
|
6
|
+
// line goes to the native binary, which still understands every command.
|
|
7
|
+
export const COMMANDS = Object.freeze([
|
|
8
|
+
{ path: ['front-door'], module: 'front-door.mjs', summary: 'What this front door serves in TypeScript, and which native binary serves the rest' },
|
|
9
|
+
{ path: ['workflow'], module: 'workflow.mjs', summary: 'A board verb called on a board by its address (--at): the whole answer on the call; any other workflow line goes to the native binary' },
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
/** The row serving `args` and the arguments after its path, or null for the native binary. */
|
|
13
|
+
export function route(args) {
|
|
14
|
+
let best = null;
|
|
15
|
+
for (const row of COMMANDS) {
|
|
16
|
+
if (row.path.length > args.length) continue;
|
|
17
|
+
if (!row.path.every((word, index) => args[index] === word)) continue;
|
|
18
|
+
if (!best || row.path.length > best.path.length) best = row;
|
|
19
|
+
}
|
|
20
|
+
return best ? { ...best, rest: args.slice(best.path.length) } : null;
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// `supercode front-door [--json]`: the commands this launcher serves in TypeScript, and the native binary that serves
|
|
2
|
+
// every other command (its package, path and version).
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { COMMANDS } from './commands.mjs';
|
|
8
|
+
|
|
9
|
+
export async function run(rest, { native }) {
|
|
10
|
+
const own = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
|
|
11
|
+
const version = native.path ? spawnSync(native.path, ['--version'], { encoding: 'utf8', timeout: 5_000 }).stdout?.trim() || null : null;
|
|
12
|
+
const report = {
|
|
13
|
+
launcher: { package: own.name, version: own.version },
|
|
14
|
+
native: { package: native.package, path: native.path, version },
|
|
15
|
+
typescript: COMMANDS.map(({ path, summary }) => ({ command: path.join(' '), summary })),
|
|
16
|
+
};
|
|
17
|
+
if (rest.includes('--json')) {
|
|
18
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
process.stdout.write(`${report.launcher.package} ${report.launcher.version}\n`);
|
|
22
|
+
process.stdout.write(`native: ${native.path ? `${version ?? 'version unreadable'} (${native.path})` : `none installed (${native.package})`}\n`);
|
|
23
|
+
process.stdout.write('served in TypeScript:\n');
|
|
24
|
+
for (const row of report.typescript) process.stdout.write(` supercode ${row.command} ${row.summary}\n`);
|
|
25
|
+
process.stdout.write('every other command goes to the native binary.\n');
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
package/lib/workflow.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// `supercode workflow <verb> … --at sc:<machine>:board:<name>`: the verb called on that board, wherever the board is,
|
|
2
|
+
// and its whole answer (exit code, stdout, stderr) on this same call (D152 row 2). It goes to this machine's daemon
|
|
3
|
+
// through its board door, which names the calling session from this process itself (the kernel's peer, not anything
|
|
4
|
+
// this command says) and reaches the board's machine through Teams; there the verb runs as that session, with the
|
|
5
|
+
// board's own checks, the dispatcher running or not. Any other `workflow` line goes to the native binary.
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
/** The Teams CLI: SUPERCODE_TEAMS_ENTRY, the Teams package installed beside this one, or this checkout's sdk/teams. */
|
|
13
|
+
function teamsEntry() {
|
|
14
|
+
if (process.env.SUPERCODE_TEAMS_ENTRY && existsSync(process.env.SUPERCODE_TEAMS_ENTRY)) return process.env.SUPERCODE_TEAMS_ENTRY;
|
|
15
|
+
try { return createRequire(import.meta.url).resolve('@volter/supercode-teams/bin'); } catch { /* not installed beside */ }
|
|
16
|
+
const checkout = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'sdk', 'teams', 'bin', 'teams.mjs');
|
|
17
|
+
return existsSync(checkout) ? checkout : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function run(rest, { native }) {
|
|
21
|
+
const at = rest.findIndex((arg) => arg === '--at' || arg.startsWith('--at='));
|
|
22
|
+
if (at < 0) {
|
|
23
|
+
// The orchestrator the native binary runs hands the line to the one the home's record names (its board/cli.mjs
|
|
24
|
+
// handOff): the one place that is decided.
|
|
25
|
+
return native.run(['workflow', ...rest]);
|
|
26
|
+
}
|
|
27
|
+
const board = rest[at].startsWith('--at=') ? rest[at].slice('--at='.length) : rest[at + 1];
|
|
28
|
+
const argv = rest.filter((_, index) => index !== at && (rest[at].startsWith('--at=') || index !== at + 1));
|
|
29
|
+
if (!board || !/^sc:[^:\s]+:board:[^:\s]+$/.test(board)) {
|
|
30
|
+
process.stderr.write('Error: --at names the board\'s address (sc:<machine>:board:<name>)\n');
|
|
31
|
+
return 2;
|
|
32
|
+
}
|
|
33
|
+
const entry = teamsEntry();
|
|
34
|
+
if (!entry) {
|
|
35
|
+
process.stderr.write('Error: the Teams package is not installed, so no board can be called by its address\n');
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
const child = spawn(process.execPath, [entry, 'board'], { stdio: ['pipe', 'pipe', 'inherit'] });
|
|
39
|
+
let out = '';
|
|
40
|
+
child.stdout.on('data', (chunk) => { out += chunk; });
|
|
41
|
+
child.stdin.end(JSON.stringify({ board, argv }));
|
|
42
|
+
const code = await new Promise((resolve) => { child.on('error', () => resolve(1)); child.on('close', resolve); });
|
|
43
|
+
let answer;
|
|
44
|
+
try { answer = JSON.parse(out.trim().split('\n').pop()); } catch { answer = null; }
|
|
45
|
+
if (!answer || typeof answer.code !== 'number') {
|
|
46
|
+
process.stderr.write(`Error: ${board} did not answer${out.trim() ? `: ${out.trim().slice(0, 500)}` : ` (exit ${code})`}\n`);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
// Returned only once written: the front door exits on return, and a pipe takes 64 KiB at a time.
|
|
50
|
+
const written = (out, text) => new Promise((resolve) => (text ? out.write(text, resolve) : resolve()));
|
|
51
|
+
await written(process.stdout, answer.stdout);
|
|
52
|
+
await written(process.stderr, answer.stderr);
|
|
53
|
+
return answer.code;
|
|
54
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.151",
|
|
4
4
|
"description": "Volter Harness: a lightweight, customizable AI coding agent CLI — any model via OpenRouter; natively continues Claude Code and Codex sessions.",
|
|
5
5
|
"repository": { "type": "git", "url": "git+https://github.com/volter-ai/supercode.git" },
|
|
6
6
|
"homepage": "https://github.com/volter-ai/supercode#readme",
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"license": "MIT OR Apache-2.0",
|
|
9
9
|
"keywords": ["ai", "agent", "llm", "coding", "cli", "openrouter", "claude", "codex"],
|
|
10
10
|
"bin": { "supercode": "bin/supercode.js" },
|
|
11
|
-
"files": ["bin/"],
|
|
11
|
+
"files": ["bin/", "lib/"],
|
|
12
12
|
"engines": { "node": ">=16" },
|
|
13
13
|
"optionalDependencies": {
|
|
14
|
-
"@volter/supercode-cli-darwin-arm64": "0.5.
|
|
15
|
-
"@volter/supercode-cli-darwin-x64": "0.5.
|
|
16
|
-
"@volter/supercode-cli-linux-x64": "0.5.
|
|
17
|
-
"@volter/supercode-cli-linux-arm64": "0.5.
|
|
18
|
-
"@volter/supercode-cli-win32-x64": "0.5.
|
|
14
|
+
"@volter/supercode-cli-darwin-arm64": "0.5.151",
|
|
15
|
+
"@volter/supercode-cli-darwin-x64": "0.5.151",
|
|
16
|
+
"@volter/supercode-cli-linux-x64": "0.5.151",
|
|
17
|
+
"@volter/supercode-cli-linux-arm64": "0.5.151",
|
|
18
|
+
"@volter/supercode-cli-win32-x64": "0.5.151"
|
|
19
19
|
}
|
|
20
20
|
}
|