overlord-cli 3.20.0 → 3.22.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 +6 -1
- package/bin/_cli/cli-update.mjs +119 -0
- package/bin/_cli/index.mjs +35 -1
- package/bin/_cli/setup.mjs +20 -32
- package/bin/_cli/version.mjs +2 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ Install it globally so the `ovld` and `overlord` commands are available on your
|
|
|
12
12
|
npm install -g overlord-cli
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
Use Node.js 20 or newer for every CLI install or update.
|
|
16
|
+
Run `ovld update` any time you want to refresh the global npm install to the latest release.
|
|
17
|
+
|
|
15
18
|
## Usage
|
|
16
19
|
|
|
17
20
|
```bash
|
|
@@ -29,6 +32,7 @@ ovld auth login
|
|
|
29
32
|
ovld attach
|
|
30
33
|
ovld create "Investigate the failing build"
|
|
31
34
|
ovld prompt "Draft a fix for the onboarding flow"
|
|
35
|
+
ovld update
|
|
32
36
|
ovld setup codex
|
|
33
37
|
ovld setup cursor
|
|
34
38
|
ovld setup gemini
|
|
@@ -38,7 +42,7 @@ ovld doctor
|
|
|
38
42
|
|
|
39
43
|
## Requirements
|
|
40
44
|
|
|
41
|
-
- Node.js
|
|
45
|
+
- Node.js 20 or newer
|
|
42
46
|
- Access to an Overlord instance when using authenticated commands
|
|
43
47
|
|
|
44
48
|
## Commands
|
|
@@ -52,6 +56,7 @@ ovld doctor
|
|
|
52
56
|
- `protocol` - run ticket lifecycle commands
|
|
53
57
|
- `connect`, `restart`, `run`, `resume`, `context` - launch or resume an agent session
|
|
54
58
|
- `setup` - install the Overlord connector or plugin bundle for a supported agent
|
|
59
|
+
- `update` - install the latest CLI release from npm
|
|
55
60
|
- `doctor` - verify installed agent connectors and check whether a newer CLI version is available
|
|
56
61
|
|
|
57
62
|
## License
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const cliPackage = require('../../package.json');
|
|
8
|
+
|
|
9
|
+
const CURRENT_CLI_VERSION = typeof cliPackage.version === 'string' ? cliPackage.version : '0.0.0';
|
|
10
|
+
const CLI_PACKAGE_NAME =
|
|
11
|
+
typeof cliPackage.name === 'string' && cliPackage.name ? cliPackage.name : 'overlord-cli';
|
|
12
|
+
|
|
13
|
+
const ORANGE = '\x1b[38;5;208m';
|
|
14
|
+
const RESET = '\x1b[0m';
|
|
15
|
+
|
|
16
|
+
function colorizeOrange(text) {
|
|
17
|
+
return `${ORANGE}${text}${RESET}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getCurrentCliVersion() {
|
|
21
|
+
return CURRENT_CLI_VERSION;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getCliPackageName() {
|
|
25
|
+
return CLI_PACKAGE_NAME;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function fetchLatestCliVersion({
|
|
29
|
+
fetchImpl = fetch,
|
|
30
|
+
packageName = CLI_PACKAGE_NAME,
|
|
31
|
+
timeoutMs = 2500
|
|
32
|
+
} = {}) {
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetchImpl(`https://registry.npmjs.org/${packageName}/latest`, {
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
headers: { Accept: 'application/json' }
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!response.ok) return null;
|
|
43
|
+
|
|
44
|
+
const payload = await response.json();
|
|
45
|
+
return typeof payload?.version === 'string' ? payload.version : null;
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
} finally {
|
|
49
|
+
clearTimeout(timeout);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function checkForCliUpdate(options = {}) {
|
|
54
|
+
const currentVersion = options.currentVersion ?? CURRENT_CLI_VERSION;
|
|
55
|
+
const latestVersion = await fetchLatestCliVersion(options);
|
|
56
|
+
if (!latestVersion || latestVersion === currentVersion) return null;
|
|
57
|
+
return latestVersion;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function formatCliUpdateNotice(latestVersion, { currentVersion = CURRENT_CLI_VERSION } = {}) {
|
|
61
|
+
return `New Overlord CLI version available: v${latestVersion} (installed v${currentVersion}). Run \`ovld update\` to update via npm.`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function printCliUpdateNotice(
|
|
65
|
+
latestVersion,
|
|
66
|
+
{ currentVersion = CURRENT_CLI_VERSION, stream = process.stderr } = {}
|
|
67
|
+
) {
|
|
68
|
+
if (!latestVersion) return false;
|
|
69
|
+
stream.write(`${colorizeOrange(formatCliUpdateNotice(latestVersion, { currentVersion }))}\n`);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function runCliUpdateCommand({
|
|
74
|
+
currentVersion = CURRENT_CLI_VERSION,
|
|
75
|
+
fetchLatestVersionFn = fetchLatestCliVersion,
|
|
76
|
+
logger = console,
|
|
77
|
+
npmCommand = 'npm',
|
|
78
|
+
packageName = CLI_PACKAGE_NAME,
|
|
79
|
+
spawnSyncImpl = spawnSync
|
|
80
|
+
} = {}) {
|
|
81
|
+
const latestVersion = await fetchLatestVersionFn({ currentVersion, packageName });
|
|
82
|
+
|
|
83
|
+
if (latestVersion && latestVersion === currentVersion) {
|
|
84
|
+
logger.log(`Overlord CLI ${currentVersion} is already the latest version.`);
|
|
85
|
+
return { alreadyLatest: true, currentVersion, latestVersion };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const target = `${packageName}@latest`;
|
|
89
|
+
if (latestVersion) {
|
|
90
|
+
logger.log(`Updating Overlord CLI ${currentVersion} -> ${latestVersion} via npm...`);
|
|
91
|
+
} else {
|
|
92
|
+
logger.log(`Updating Overlord CLI via npm...`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const result = spawnSyncImpl(npmCommand, ['install', '-g', target], {
|
|
96
|
+
env: process.env,
|
|
97
|
+
stdio: 'inherit'
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (result.error) {
|
|
101
|
+
throw result.error;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (typeof result.status === 'number' && result.status !== 0) {
|
|
105
|
+
throw new Error(`\`${npmCommand} install -g ${target}\` exited with status ${result.status}.`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof result.signal === 'string') {
|
|
109
|
+
throw new Error(`\`${npmCommand} install -g ${target}\` was terminated by ${result.signal}.`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (latestVersion) {
|
|
113
|
+
logger.log(`Overlord CLI updated to v${latestVersion}.`);
|
|
114
|
+
} else {
|
|
115
|
+
logger.log('Overlord CLI update complete. Run `ovld version` to confirm the installed version.');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { alreadyLatest: false, currentVersion, latestVersion, result };
|
|
119
|
+
}
|
package/bin/_cli/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { runAttachCommand } from './attach.mjs';
|
|
4
4
|
import { runAuthCommand } from './auth.mjs';
|
|
5
|
+
import { checkForCliUpdate, printCliUpdateNotice, runCliUpdateCommand } from './cli-update.mjs';
|
|
5
6
|
import { runLauncherCommand } from './launcher.mjs';
|
|
6
7
|
import { runProtocolCommand } from './protocol.mjs';
|
|
7
8
|
import { runDoctorCommand, runSetupCommand } from './setup.mjs';
|
|
@@ -9,6 +10,18 @@ import { runTicketCommand } from './ticket.mjs';
|
|
|
9
10
|
import { runTicketsCommand } from './tickets.mjs';
|
|
10
11
|
import { runVersionCommand } from './version.mjs';
|
|
11
12
|
|
|
13
|
+
const MIN_NODE_MAJOR = 20;
|
|
14
|
+
|
|
15
|
+
function assertSupportedNodeVersion() {
|
|
16
|
+
const major = Number.parseInt(process.versions.node.split('.')[0] ?? '', 10);
|
|
17
|
+
if (Number.isNaN(major) || major < MIN_NODE_MAJOR) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Overlord CLI requires Node.js ${MIN_NODE_MAJOR} or newer. Found ${process.version}.\n` +
|
|
20
|
+
`Update Node before running \`ovld\`. If you installed the desktop wrapper, you can also point it at a newer runtime with \`OVLD_NODE_BIN=/path/to/node\`.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
12
25
|
function printHelp(primaryCommand) {
|
|
13
26
|
console.log(`Overlord CLI
|
|
14
27
|
|
|
@@ -26,6 +39,7 @@ Usage:
|
|
|
26
39
|
${primaryCommand} restart <agent> Resume an agent session
|
|
27
40
|
${primaryCommand} context Print ticket context (requires TICKET_ID)
|
|
28
41
|
${primaryCommand} setup <agent|all> Install Overlord agent connector
|
|
42
|
+
${primaryCommand} update Install the latest CLI version from npm
|
|
29
43
|
${primaryCommand} doctor Validate installed agent connectors and check for CLI updates
|
|
30
44
|
${primaryCommand} version Show the installed CLI version
|
|
31
45
|
${primaryCommand} help Show this help message
|
|
@@ -52,7 +66,17 @@ Run a subcommand with --help for more detail.
|
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
export async function runCli({ primaryCommand }) {
|
|
69
|
+
assertSupportedNodeVersion();
|
|
55
70
|
const [command, ...rest] = process.argv.slice(2);
|
|
71
|
+
const shouldCheckForUpdate =
|
|
72
|
+
Boolean(process.stdout.isTTY || process.stderr.isTTY) &&
|
|
73
|
+
command !== 'doctor' &&
|
|
74
|
+
command !== 'update';
|
|
75
|
+
const latestCliVersion = shouldCheckForUpdate ? await checkForCliUpdate() : null;
|
|
76
|
+
|
|
77
|
+
if (latestCliVersion && command !== 'doctor' && command !== 'update') {
|
|
78
|
+
printCliUpdateNotice(latestCliVersion);
|
|
79
|
+
}
|
|
56
80
|
|
|
57
81
|
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
58
82
|
printHelp(primaryCommand);
|
|
@@ -106,8 +130,18 @@ export async function runCli({ primaryCommand }) {
|
|
|
106
130
|
return;
|
|
107
131
|
}
|
|
108
132
|
|
|
133
|
+
if (command === 'update') {
|
|
134
|
+
if (rest[0] === '--help' || rest[0] === '-h' || rest[0] === 'help') {
|
|
135
|
+
console.log(`Usage:
|
|
136
|
+
${primaryCommand} update Install the latest CLI version from npm`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
await runCliUpdateCommand();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
109
143
|
if (command === 'doctor') {
|
|
110
|
-
await runDoctorCommand();
|
|
144
|
+
await runDoctorCommand({ latestCliVersion });
|
|
111
145
|
return;
|
|
112
146
|
}
|
|
113
147
|
|
package/bin/_cli/setup.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import fs from 'node:fs';
|
|
|
12
12
|
import os from 'node:os';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { checkForCliUpdate, getCurrentCliVersion, printCliUpdateNotice } from './cli-update.mjs';
|
|
15
16
|
|
|
16
17
|
const BUNDLE_VERSION = '1.8.0';
|
|
17
18
|
const MD_MARKER_START = '<!-- overlord:managed:start -->';
|
|
@@ -32,6 +33,7 @@ const CODEX_TARGET_RULES = path.join(os.homedir(), '.codex', 'rules', 'default.r
|
|
|
32
33
|
const CODEX_LEGACY_AGENTS = path.join(os.homedir(), '.codex', 'AGENTS.md');
|
|
33
34
|
const CODEX_RULES_START = '# overlord:permissions:start';
|
|
34
35
|
const CODEX_RULES_END = '# overlord:permissions:end';
|
|
36
|
+
const REQUIRED_NODE_MAJOR = 20;
|
|
35
37
|
|
|
36
38
|
const supportedAgents = ['claude', 'codex', 'cursor', 'gemini', 'opencode'];
|
|
37
39
|
|
|
@@ -279,11 +281,6 @@ function readJsonFileOrNull(filePath) {
|
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
function localCliVersion() {
|
|
283
|
-
const cliPackage = readJsonFileOrNull(path.resolve(__dirname, '..', '..', 'package.json'));
|
|
284
|
-
return typeof cliPackage?.version === 'string' ? cliPackage.version : null;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
284
|
function writeJsonFile(filePath, data) {
|
|
288
285
|
const dir = path.dirname(filePath);
|
|
289
286
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
@@ -482,28 +479,6 @@ function currentContentHashForAgent(agent) {
|
|
|
482
479
|
);
|
|
483
480
|
}
|
|
484
481
|
|
|
485
|
-
async function checkForCliUpdate() {
|
|
486
|
-
const currentVersion = localCliVersion();
|
|
487
|
-
if (!currentVersion) return null;
|
|
488
|
-
const controller = new AbortController();
|
|
489
|
-
const timeout = setTimeout(() => controller.abort(), 2500);
|
|
490
|
-
try {
|
|
491
|
-
const response = await fetch('https://registry.npmjs.org/overlord-cli/latest', {
|
|
492
|
-
signal: controller.signal,
|
|
493
|
-
headers: { Accept: 'application/json' }
|
|
494
|
-
});
|
|
495
|
-
if (!response.ok) return null;
|
|
496
|
-
const payload = await response.json();
|
|
497
|
-
const latestVersion = typeof payload?.version === 'string' ? payload.version : null;
|
|
498
|
-
if (!latestVersion) return null;
|
|
499
|
-
return latestVersion === currentVersion ? null : latestVersion;
|
|
500
|
-
} catch {
|
|
501
|
-
return null;
|
|
502
|
-
} finally {
|
|
503
|
-
clearTimeout(timeout);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
482
|
function codexSourcePluginDir() {
|
|
508
483
|
if (fs.existsSync(PACKAGE_PLUGIN_DIR)) return PACKAGE_PLUGIN_DIR;
|
|
509
484
|
if (fs.existsSync(REPO_PLUGIN_DIR)) return REPO_PLUGIN_DIR;
|
|
@@ -971,6 +946,10 @@ function doctorAgent(agent) {
|
|
|
971
946
|
return true;
|
|
972
947
|
}
|
|
973
948
|
|
|
949
|
+
function currentNodeMajor() {
|
|
950
|
+
return Number.parseInt(process.versions.node.split('.')[0] ?? '', 10);
|
|
951
|
+
}
|
|
952
|
+
|
|
974
953
|
// ---------------------------------------------------------------------------
|
|
975
954
|
// Public API
|
|
976
955
|
// ---------------------------------------------------------------------------
|
|
@@ -1030,22 +1009,31 @@ export async function runSetupCommand(args) {
|
|
|
1030
1009
|
}
|
|
1031
1010
|
}
|
|
1032
1011
|
|
|
1033
|
-
export async function runDoctorCommand() {
|
|
1012
|
+
export async function runDoctorCommand({ latestCliVersion = null } = {}) {
|
|
1034
1013
|
console.log('Overlord agent bundle status:\n');
|
|
1035
1014
|
let allOk = true;
|
|
1015
|
+
const nodeMajor = currentNodeMajor();
|
|
1016
|
+
if (Number.isNaN(nodeMajor) || nodeMajor < REQUIRED_NODE_MAJOR) {
|
|
1017
|
+
console.log(
|
|
1018
|
+
` ✗ node: unsupported runtime (${process.version}; requires Node.js ${REQUIRED_NODE_MAJOR}+)`
|
|
1019
|
+
);
|
|
1020
|
+
allOk = false;
|
|
1021
|
+
} else {
|
|
1022
|
+
console.log(` ✓ node: ${process.version}`);
|
|
1023
|
+
}
|
|
1024
|
+
console.log();
|
|
1036
1025
|
for (const agent of supportedAgents) {
|
|
1037
1026
|
if (!doctorAgent(agent)) allOk = false;
|
|
1038
1027
|
}
|
|
1039
|
-
const
|
|
1028
|
+
const updateVersion = latestCliVersion ?? (await checkForCliUpdate());
|
|
1040
1029
|
console.log();
|
|
1041
1030
|
if (allOk) {
|
|
1042
1031
|
console.log('All bundles are up to date.');
|
|
1043
1032
|
} else {
|
|
1044
1033
|
console.log('Run `ovld setup <agent>` or `ovld setup all` to install/repair.');
|
|
1045
1034
|
}
|
|
1046
|
-
if (
|
|
1035
|
+
if (updateVersion) {
|
|
1047
1036
|
console.log();
|
|
1048
|
-
|
|
1049
|
-
console.log('Run `npm install -g overlord-cli@latest` to update.');
|
|
1037
|
+
printCliUpdateNotice(updateVersion, { currentVersion: getCurrentCliVersion(), stream: process.stdout });
|
|
1050
1038
|
}
|
|
1051
1039
|
}
|
package/bin/_cli/version.mjs
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const require = createRequire(import.meta.url);
|
|
6
|
-
const { version } = require('../../package.json');
|
|
3
|
+
import { getCurrentCliVersion } from './cli-update.mjs';
|
|
7
4
|
|
|
8
5
|
export function runVersionCommand() {
|
|
9
|
-
console.log(`Overlord CLI ${
|
|
6
|
+
console.log(`Overlord CLI ${getCurrentCliVersion()}`);
|
|
10
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overlord-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.22.0",
|
|
4
4
|
"description": "Overlord CLI — launch AI agents on tickets from anywhere",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"plugins/"
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=20"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"overlord",
|