@openagents-org/agent-launcher 0.2.175 → 0.2.177
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/icons/codebuddy.svg +3 -0
- package/icons/kimi.svg +5 -10
- package/icons/openworker.svg +3 -0
- package/package.json +1 -1
- package/registry.json +271 -1
- package/src/adapters/codebuddy-stream.js +497 -0
- package/src/adapters/codebuddy.js +913 -0
- package/src/adapters/index.js +6 -1
- package/src/adapters/openworker-runtime.js +572 -0
- package/src/adapters/openworker.js +921 -0
- package/src/adapters/workspace-prompt.js +33 -0
- package/src/install-preflight.js +84 -6
- package/src/paths.js +20 -8
- package/src/registry.js +12 -2
|
@@ -1021,6 +1021,38 @@ function buildPiSystemPrompt({ agentName, workspaceId, channelName, endpoint, to
|
|
|
1021
1021
|
return identity + directive + '\n' + collab + '\n' + modePrompt + '\n' + api + '\n' + buildGuardrails();
|
|
1022
1022
|
}
|
|
1023
1023
|
|
|
1024
|
+
/**
|
|
1025
|
+
* Build the workspace briefing that seeds an OpenWorker session.
|
|
1026
|
+
*
|
|
1027
|
+
* Shape mirrors buildPiSystemPrompt — identity, browser directive,
|
|
1028
|
+
* collaboration, mode, then the REST block — because OpenWorker reaches the
|
|
1029
|
+
* workspace the same way: its own shell tool plus curl, with no MCP wiring from
|
|
1030
|
+
* our side (registering an MCP server there writes into the user's global
|
|
1031
|
+
* OpenWorker config, which is not ours to edit).
|
|
1032
|
+
*
|
|
1033
|
+
* Two differences from every other builder here, both forced by OpenWorker
|
|
1034
|
+
* having no system-prompt hook at all:
|
|
1035
|
+
*
|
|
1036
|
+
* - `execTool` is `run_shell`, the actual name of its shell tool. Naming a
|
|
1037
|
+
* tool the agent does not have is how a model ends up printing curl
|
|
1038
|
+
* commands as text instead of running them.
|
|
1039
|
+
* - This is prepended to the first USER message of a session rather than
|
|
1040
|
+
* installed as a system prompt. That makes it part of the persisted
|
|
1041
|
+
* conversation, so it is sent once and still in context on every later turn
|
|
1042
|
+
* — which is why it must read as a briefing, not as a system directive.
|
|
1043
|
+
*/
|
|
1044
|
+
function buildOpenWorkerSystemPrompt({ agentName, workspaceId, channelName, endpoint, token, mode = 'execute', disabledModules, browserEnabled = false }) {
|
|
1045
|
+
const identity = buildWorkspaceIdentity(agentName, workspaceId, channelName, mode, 'skills');
|
|
1046
|
+
const directive = buildBrowserDirective(browserEnabled);
|
|
1047
|
+
const collab = buildCollaborationPrompt('skills', workspaceSkillName(agentName));
|
|
1048
|
+
const modePrompt = buildModePrompt(mode);
|
|
1049
|
+
const api = buildApiSkillsPrompt({
|
|
1050
|
+
endpoint, workspaceId, token, agentName, channelName, disabledModules, mode,
|
|
1051
|
+
execTool: 'run_shell',
|
|
1052
|
+
});
|
|
1053
|
+
return identity + directive + '\n' + collab + '\n' + modePrompt + '\n' + api + '\n' + buildGuardrails();
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1024
1056
|
/**
|
|
1025
1057
|
* Build the task FILE contents for the DeepSeek Harness adapter.
|
|
1026
1058
|
*
|
|
@@ -1223,6 +1255,7 @@ module.exports = {
|
|
|
1223
1255
|
buildOpenCodeSkillMd,
|
|
1224
1256
|
buildCommandCodeSkillMd,
|
|
1225
1257
|
buildPiSystemPrompt,
|
|
1258
|
+
buildOpenWorkerSystemPrompt,
|
|
1226
1259
|
buildDeepSeekTaskFile,
|
|
1227
1260
|
buildClaudeSkillMd,
|
|
1228
1261
|
buildCursorSkillMd,
|
package/src/install-preflight.js
CHANGED
|
@@ -29,11 +29,10 @@
|
|
|
29
29
|
'use strict';
|
|
30
30
|
|
|
31
31
|
const fs = require('fs');
|
|
32
|
+
const os = require('os');
|
|
32
33
|
const path = require('path');
|
|
33
34
|
const { execFileSync } = require('child_process');
|
|
34
35
|
|
|
35
|
-
const IS_MACOS = process.platform === 'darwin';
|
|
36
|
-
|
|
37
36
|
/** Directories on PATH, minus any the caller wants skipped. */
|
|
38
37
|
function pathDirs(exclude = []) {
|
|
39
38
|
const raw = process.env.PATH || '';
|
|
@@ -154,30 +153,106 @@ function probeGit(deps = {}) {
|
|
|
154
153
|
|
|
155
154
|
/**
|
|
156
155
|
* How the user fixes each missing dependency, phrased for the install screen.
|
|
157
|
-
*
|
|
158
|
-
*
|
|
156
|
+
*
|
|
157
|
+
* `action` is a hint the launcher UI can turn into a button. `summaryKey` and
|
|
158
|
+
* `alternativeKind` are the same thing for text: the launcher is translated
|
|
159
|
+
* and this package is not, so it looks up its own wording by those keys and
|
|
160
|
+
* keeps `summary` only as the fallback — which is also what the CLI and the
|
|
161
|
+
* install log print. `alternativeKind` in particular has to be carried rather
|
|
162
|
+
* than guessed: the alternative is Homebrew only on macOS, and a UI that
|
|
163
|
+
* labels every alternative "if you use Homebrew" is wrong on two of the three
|
|
164
|
+
* platforms we ship.
|
|
165
|
+
*
|
|
166
|
+
* @param {string} [platform] - seam for tests; production passes nothing.
|
|
159
167
|
*/
|
|
160
|
-
function gitRemedy() {
|
|
161
|
-
if (
|
|
168
|
+
function gitRemedy(platform = process.platform) {
|
|
169
|
+
if (platform === 'darwin') {
|
|
162
170
|
return {
|
|
163
171
|
name: 'git',
|
|
164
172
|
action: 'install-xcode-clt',
|
|
173
|
+
summaryKey: 'gitXcodeClt',
|
|
165
174
|
summary: 'Git is required, and it comes with the Xcode Command Line Tools.',
|
|
166
175
|
command: 'xcode-select --install',
|
|
167
176
|
alternative: 'brew install git',
|
|
177
|
+
alternativeKind: 'homebrew',
|
|
168
178
|
};
|
|
169
179
|
}
|
|
170
180
|
return {
|
|
171
181
|
name: 'git',
|
|
172
182
|
action: null,
|
|
183
|
+
summaryKey: 'git',
|
|
173
184
|
summary: 'Git is required to download this agent.',
|
|
174
185
|
command: 'sudo apt install git # or dnf / pacman, per your distro',
|
|
175
186
|
alternative: null,
|
|
187
|
+
alternativeKind: null,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Is `uv` on PATH?
|
|
193
|
+
*
|
|
194
|
+
* Unlike git, nothing provisions uv for us: an agent whose install command IS
|
|
195
|
+
* `uv tool install …` and whose machine has no uv gets the shell's own
|
|
196
|
+
* "command not found" buried in installer output, several seconds after
|
|
197
|
+
* pressing Install. The probe is a plain filesystem check — running `uv
|
|
198
|
+
* --version` would be the same answer at the cost of a process spawn, and uv
|
|
199
|
+
* has no shim behaviour to catch out the way macOS's /usr/bin/git does.
|
|
200
|
+
*
|
|
201
|
+
* Also checks uv's own default install location, which its installer script
|
|
202
|
+
* adds to PATH via a shell profile a running GUI/daemon never re-read.
|
|
203
|
+
*/
|
|
204
|
+
function probeUv(deps = {}) {
|
|
205
|
+
const platform = deps.platform || process.platform;
|
|
206
|
+
const exists = deps.exists || ((p) => fs.existsSync(p));
|
|
207
|
+
const home = deps.home || os.homedir();
|
|
208
|
+
const isWindows = platform === 'win32';
|
|
209
|
+
const search = deps.dirs || [
|
|
210
|
+
...pathDirs(),
|
|
211
|
+
path.join(home, '.local', 'bin'),
|
|
212
|
+
path.join(home, '.cargo', 'bin'),
|
|
213
|
+
...(isWindows ? [] : ['/opt/homebrew/bin', '/usr/local/bin']),
|
|
214
|
+
];
|
|
215
|
+
const found = existsIn(search, 'uv', exists, isWindows);
|
|
216
|
+
return found ? { ok: true, detail: found } : { ok: false };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** @param {string} [platform] - seam for tests; production passes nothing. */
|
|
220
|
+
function uvRemedy(platform = process.platform) {
|
|
221
|
+
const summary = 'uv is required to install this agent (it is a Python tool).';
|
|
222
|
+
|
|
223
|
+
if (platform === 'win32') {
|
|
224
|
+
return {
|
|
225
|
+
name: 'uv',
|
|
226
|
+
action: null,
|
|
227
|
+
summaryKey: 'uv',
|
|
228
|
+
summary,
|
|
229
|
+
// Spelled out instead of a bare `irm … | iex`, because "run this in a
|
|
230
|
+
// terminal" on Windows lands in cmd.exe as often as in PowerShell, and
|
|
231
|
+
// the bare form is a syntax error there.
|
|
232
|
+
command:
|
|
233
|
+
'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"',
|
|
234
|
+
// pipx is the obvious parallel to Homebrew, but a machine with no uv
|
|
235
|
+
// seldom has pipx either — whereas winget ships with Windows.
|
|
236
|
+
alternative: 'winget install --id=astral-sh.uv -e',
|
|
237
|
+
alternativeKind: 'winget',
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const viaHomebrew = platform === 'darwin';
|
|
242
|
+
return {
|
|
243
|
+
name: 'uv',
|
|
244
|
+
action: null,
|
|
245
|
+
summaryKey: 'uv',
|
|
246
|
+
summary,
|
|
247
|
+
command: 'curl -LsSf https://astral.sh/uv/install.sh | sh',
|
|
248
|
+
alternative: viaHomebrew ? 'brew install uv' : 'pipx install uv',
|
|
249
|
+
alternativeKind: viaHomebrew ? 'homebrew' : 'pipx',
|
|
176
250
|
};
|
|
177
251
|
}
|
|
178
252
|
|
|
179
253
|
const PROBES = {
|
|
180
254
|
git: { probe: probeGit, remedy: gitRemedy },
|
|
255
|
+
uv: { probe: probeUv, remedy: uvRemedy },
|
|
181
256
|
};
|
|
182
257
|
|
|
183
258
|
/**
|
|
@@ -230,4 +305,7 @@ module.exports = {
|
|
|
230
305
|
checkInstallPrereqs,
|
|
231
306
|
missingPrereqError,
|
|
232
307
|
probeGit,
|
|
308
|
+
probeUv,
|
|
309
|
+
gitRemedy,
|
|
310
|
+
uvRemedy,
|
|
233
311
|
};
|
package/src/paths.js
CHANGED
|
@@ -58,11 +58,13 @@ function getExtraBinDirs() {
|
|
|
58
58
|
// CLIs whose own installer script picks a directory of its own.
|
|
59
59
|
_addAgentInstallerPaths(dirs);
|
|
60
60
|
|
|
61
|
-
//
|
|
61
|
+
// CLIs installed with `uv tool install` — the executable honors XDG_BIN_HOME /
|
|
62
62
|
// XDG_DATA_HOME/../bin / ~/.local/bin and also always lands in the uv tools
|
|
63
63
|
// venv. A GUI/daemon process won't see the installer's PATH edit, so add the
|
|
64
64
|
// real install dirs explicitly (filtered to existing dirs by the caller).
|
|
65
|
+
// `coworker` is OpenWorker's distribution name — see uvToolBinDirs.
|
|
65
66
|
for (const d of aiderBinDirs()) _push(dirs, d);
|
|
67
|
+
for (const d of uvToolBinDirs('coworker')) _push(dirs, d);
|
|
66
68
|
|
|
67
69
|
// Also add the directory containing the current node binary
|
|
68
70
|
try {
|
|
@@ -787,19 +789,23 @@ function primeBinaryLookup() {
|
|
|
787
789
|
}
|
|
788
790
|
|
|
789
791
|
/**
|
|
790
|
-
* Directories where
|
|
791
|
-
*
|
|
792
|
-
* detection matches reality on every platform:
|
|
792
|
+
* Directories where a `uv tool install`-ed CLI can land, in the SAME priority uv
|
|
793
|
+
* itself uses, so detection matches reality on every platform:
|
|
793
794
|
* 1. $XDG_BIN_HOME
|
|
794
795
|
* 2. $XDG_DATA_HOME/../bin
|
|
795
796
|
* 3. ~/.local/bin (the default uv-tool / pipx / pip --user bin)
|
|
796
|
-
* 4. the uv tools venv for
|
|
797
|
+
* 4. the uv tools venv for `pkg` (Scripts on Windows, bin on Unix) — the
|
|
797
798
|
* executable always lands here on a successful `uv tool install`, even if
|
|
798
799
|
* the bin-dir copy/PATH edit didn't happen.
|
|
800
|
+
*
|
|
801
|
+
* `pkg` is the DISTRIBUTION name uv keys its tool dir by, which is not always
|
|
802
|
+
* the command name: aider's CLI is `aider` from `aider-chat`, and OpenWorker's
|
|
803
|
+
* is `openworker-server` from `coworker`.
|
|
804
|
+
*
|
|
799
805
|
* Uses os.homedir()/live env so it reflects the current process (test-friendly).
|
|
800
806
|
* Returns directories only; callers join the platform binary names.
|
|
801
807
|
*/
|
|
802
|
-
function
|
|
808
|
+
function uvToolBinDirs(pkg) {
|
|
803
809
|
const home = os.homedir();
|
|
804
810
|
const dirs = [];
|
|
805
811
|
if (process.env.XDG_BIN_HOME) dirs.push(process.env.XDG_BIN_HOME);
|
|
@@ -808,17 +814,22 @@ function aiderBinDirs() {
|
|
|
808
814
|
if (IS_WINDOWS) {
|
|
809
815
|
const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
|
|
810
816
|
const uvTools = process.env.UV_TOOL_DIR || path.join(appData, 'uv', 'tools');
|
|
811
|
-
dirs.push(path.join(uvTools,
|
|
817
|
+
dirs.push(path.join(uvTools, pkg, 'Scripts'));
|
|
812
818
|
dirs.push(path.join(home, 'bin'));
|
|
813
819
|
} else {
|
|
814
820
|
const uvTools = process.env.UV_TOOL_DIR
|
|
815
821
|
|| path.join(home, '.local', 'share', 'uv', 'tools');
|
|
816
|
-
dirs.push(path.join(uvTools,
|
|
822
|
+
dirs.push(path.join(uvTools, pkg, 'bin'));
|
|
817
823
|
dirs.push(path.join(home, 'bin'), '/usr/local/bin', '/opt/homebrew/bin');
|
|
818
824
|
}
|
|
819
825
|
return dirs;
|
|
820
826
|
}
|
|
821
827
|
|
|
828
|
+
/** Aider's CLI, installed by aider.chat/install.{sh,ps1} → `uv tool install`. */
|
|
829
|
+
function aiderBinDirs() {
|
|
830
|
+
return uvToolBinDirs('aider-chat');
|
|
831
|
+
}
|
|
832
|
+
|
|
822
833
|
/** Executable suffixes to try for a bare binary name, per platform. */
|
|
823
834
|
const BIN_EXTS = IS_WINDOWS ? ['.cmd', '.exe', '.bat', ''] : [''];
|
|
824
835
|
|
|
@@ -889,6 +900,7 @@ module.exports = {
|
|
|
889
900
|
getCorePrefix,
|
|
890
901
|
defaultAgentWorkdir,
|
|
891
902
|
aiderBinDirs,
|
|
903
|
+
uvToolBinDirs,
|
|
892
904
|
IS_WINDOWS,
|
|
893
905
|
IS_MACOS,
|
|
894
906
|
SEP,
|
package/src/registry.js
CHANGED
|
@@ -101,7 +101,16 @@ class Registry {
|
|
|
101
101
|
// day-old) cached remote copy, same as install.
|
|
102
102
|
if (b.resolve_env) entry.resolve_env = b.resolve_env;
|
|
103
103
|
if (b.install) entry.install = { ...b.install };
|
|
104
|
-
|
|
104
|
+
// check_ready is the auth/readiness contract of the adapter shipping in
|
|
105
|
+
// THIS core, so the bundled fields win over a remote copy that may be a
|
|
106
|
+
// release behind — the same rule as install, and for the same reason.
|
|
107
|
+
// Kimi is what proved it: the CLI rewrite added `login_command: kimi
|
|
108
|
+
// login`, but the server was still serving the API-key-only entry, and
|
|
109
|
+
// "fill it in only when absent" meant the sign-in never appeared.
|
|
110
|
+
// Spread rather than replace so anything the server adds on its own
|
|
111
|
+
// (auth_detected_labels and friends) survives.
|
|
112
|
+
if (b.check_ready)
|
|
113
|
+
entry.check_ready = { ...(entry.check_ready || {}), ...b.check_ready };
|
|
105
114
|
if (!entry.launch && b.launch) entry.launch = b.launch;
|
|
106
115
|
if (!entry.probe && b.probe) entry.probe = b.probe;
|
|
107
116
|
// Always take featured/order/support from bundled (source of truth for ordering)
|
|
@@ -148,7 +157,8 @@ class Registry {
|
|
|
148
157
|
const b = bundled.find((e) => e.name === agentType);
|
|
149
158
|
if (b) {
|
|
150
159
|
if (b.install) entry.install = { ...b.install };
|
|
151
|
-
if (
|
|
160
|
+
if (b.check_ready)
|
|
161
|
+
entry.check_ready = { ...(entry.check_ready || {}), ...b.check_ready };
|
|
152
162
|
if (!entry.launch && b.launch) entry.launch = b.launch;
|
|
153
163
|
if (!entry.probe && b.probe) entry.probe = b.probe;
|
|
154
164
|
if ((!entry.env_config || !entry.env_config.length) && b.env_config?.length) entry.env_config = b.env_config;
|