@bitmagic/cli 0.1.68-dev.4 → 0.1.68-dev.5
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 +7 -1
- package/dist/commands/event.d.ts +2 -1
- package/dist/commands/event.js +63 -10
- package/dist/commands/event.js.map +1 -1
- package/dist/event/codex-home.d.ts +7 -1
- package/dist/event/codex-home.js +17 -4
- package/dist/event/codex-home.js.map +1 -1
- package/dist/event/launch.d.ts +19 -4
- package/dist/event/launch.js +84 -18
- package/dist/event/launch.js.map +1 -1
- package/dist/event/preflight.d.ts +2 -1
- package/dist/event/preflight.js +33 -10
- package/dist/event/preflight.js.map +1 -1
- package/dist/event/resolve-agent.d.ts +8 -0
- package/dist/event/resolve-agent.js +68 -0
- package/dist/event/resolve-agent.js.map +1 -0
- package/dist/event/store.js +4 -0
- package/dist/event/store.js.map +1 -1
- package/dist/project/reference.d.ts +6 -29
- package/dist/project/reference.js +3 -25
- package/dist/project/reference.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -218,7 +218,7 @@ browser reloads itself on every change and the assets panel shows each generatio
|
|
|
218
218
|
| `bitmagic forge --prompt "..." [--city\|--dungeon\|--platformer\|--freeform] [--name <name>] [--resume <jobId>]` | Design and bake a whole playable level into `world.json`. Costs sparks, and takes many minutes — the bake alone can take twenty. `--resume <jobId>` picks a failed run back up from the last step that finished, rather than redoing the whole thing. |
|
|
219
219
|
| `bitmagic forge --edit "..." [--level <id or name>]` | Change a detail of a level this project forged — a door style, the light fixtures, a prop — without re-forging it. The stored design is patched and only what the change touches is re-made; the level is replaced in place. See [Editing a forged level](#editing-a-forged-level). |
|
|
220
220
|
| `bitmagic tools <list\|path\|install> [bundle]` | The script bundles the CLI ships for skills that drive Blender, Python or Node (`blender-level`, `unity-import`, `metahuman`): what they are, where this install keeps them, and `install` to copy one into the project's `tools/`. Local, no network, no sparks. |
|
|
221
|
-
| `bitmagic event <setup\|claude\|codex\|status\|env\|clear> ...` | **Sponsored events only.** `setup --key sk-…` stores the API key from your event card and checks it works; `claude` / `codex` start that agent pointed at the event endpoint; `status` shows what is left of your budget. Nothing you own is modified: Claude Code is configured purely through the environment of the process it starts, and Codex gets a separate profile of ours (your `~/.codex/config.toml` is untouched and still applies when you run `codex` yourself). `clear` removes both. Plain `claude` keeps using your own account — the event endpoint is only used when you start the agent through `bitmagic event`. |
|
|
221
|
+
| `bitmagic event <setup\|claude\|codex\|status\|env\|clear> ...` | **Sponsored events only.** `setup --key sk-…` stores the API key from your event card and checks it works; `claude` / `codex` start that agent pointed at the event endpoint; `status` shows what is left of your budget. Nothing you own is modified: Claude Code is configured purely through the environment of the process it starts, and Codex gets a separate profile of ours (your `~/.codex/config.toml` is untouched and still applies when you run `codex` yourself). `clear` removes both. `env` prints the variables for wiring an agent up by hand, in your shell's syntax (`--shell posix\|powershell\|cmd`). Plain `claude` keeps using your own account — the event endpoint is only used when you start the agent through `bitmagic event`. Works on macOS, Linux and native Windows; participants who have no Node or agent at all are set up in one command by the bootstrap at `portal/public/event/install.sh` (`install.ps1` on Windows). |
|
|
222
222
|
| `bitmagic levels <list\|add\|rename\|set-start\|remove> ...` | Manage the levels `forge` creates: which one boots, their names, registering a bake you already have, deleting one. Local, no network, no sparks. See **Managing levels** below. |
|
|
223
223
|
|
|
224
224
|
Every command exits non-zero on failure with a single-line message (no stack trace) and, where a
|
|
@@ -598,6 +598,12 @@ accepted reference. The same flag is on the four image generators, `cover`, and
|
|
|
598
598
|
game's look outright, accept it directly: `bitmagic reference accept ./that-photo.jpg`.
|
|
599
599
|
|
|
600
600
|
Candidates cost sparks like any image generation; `accept`, `show` and `clear` are free.
|
|
601
|
+
|
|
602
|
+
The Creator web app has the same feature (the **Reference** button beside its prompt box) and its
|
|
603
|
+
AI reads the same accepted URL — from the game's `game.json` (`referenceImage`) rather than
|
|
604
|
+
`.bitmagic/reference.json`, so a `bitmagic reference accept` is not seen by the Creator, nor the
|
|
605
|
+
Creator's accept by the CLI. Candidates are per lane too: the CLI's under `.bitmagic/reference/`,
|
|
606
|
+
the Creator's on the server.
|
|
601
607
|
`.bitmagic/` is not committed, so paste the accepted URL into `GAME-DESIGN.md` — on a fresh clone,
|
|
602
608
|
`bitmagic reference accept <url>` re-accepts the same image from that line.
|
|
603
609
|
|
package/dist/commands/event.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { CODEX_KEY_ENV } from '../event/launch.js';
|
|
1
|
+
import { CODEX_KEY_ENV, type EventAgent } from '../event/launch.js';
|
|
2
|
+
export declare function installHint(agent: EventAgent, platform?: string): string;
|
|
2
3
|
export declare const eventCommand: import("citty").CommandDef<import("citty").ArgsDef>;
|
|
3
4
|
export { CODEX_KEY_ENV };
|
package/dist/commands/event.js
CHANGED
|
@@ -26,20 +26,42 @@ import { defineCommand } from 'citty';
|
|
|
26
26
|
import { spawn } from 'node:child_process';
|
|
27
27
|
import { CliError, errnoCode } from '../errors.js';
|
|
28
28
|
import { createOutput } from '../output.js';
|
|
29
|
+
import { binInvocation } from '../project/spawn-bin.js';
|
|
29
30
|
import { fetchBudget, usd } from '../event/budget.js';
|
|
30
|
-
import { CODEX_KEY_ENV, exportLines, launchSpec } from '../event/launch.js';
|
|
31
|
+
import { CODEX_KEY_ENV, defaultEnvShell, exportLines, launchSpec, } from '../event/launch.js';
|
|
31
32
|
import { codexHomePath, ensureCodexHome, removeCodexHome } from '../event/codex-home.js';
|
|
32
33
|
import { preflight } from '../event/preflight.js';
|
|
34
|
+
import { resolveAgentBinary } from '../event/resolve-agent.js';
|
|
33
35
|
import { clearEventKey, eventKeyPath, readEventKey, writeEventKey } from '../event/store.js';
|
|
34
36
|
/** The event proxy. Hard-coded because this command is scoped to one event. */
|
|
35
37
|
const EVENT_PROXY_URL = 'https://event-proxy.bitmagic.ai';
|
|
36
38
|
const JSON_ARG = {
|
|
37
39
|
json: { type: 'boolean', description: 'Print the result as JSON on stdout; all progress goes to stderr.' },
|
|
38
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* How to install a missing agent.
|
|
43
|
+
*
|
|
44
|
+
* The vendors' own installers, not `npm install -g`, for two reasons. They need no Node, so they
|
|
45
|
+
* work for the participant who has nothing — which is exactly the participant reading this message.
|
|
46
|
+
* And on Windows they write a real `.exe` rather than the `.cmd` batch shim npm produces, which is
|
|
47
|
+
* the launch path that actually works (event/resolve-agent.ts).
|
|
48
|
+
*/
|
|
39
49
|
const INSTALL_HINT = {
|
|
40
|
-
claude:
|
|
41
|
-
|
|
50
|
+
claude: {
|
|
51
|
+
posix: 'curl -fsSL https://claude.ai/install.sh | bash',
|
|
52
|
+
windows: 'irm https://claude.ai/install.ps1 | iex',
|
|
53
|
+
},
|
|
54
|
+
codex: {
|
|
55
|
+
posix: 'curl -fsSL https://chatgpt.com/codex/install.sh | sh',
|
|
56
|
+
windows: 'irm https://chatgpt.com/codex/install.ps1 | iex',
|
|
57
|
+
},
|
|
42
58
|
};
|
|
59
|
+
export function installHint(agent, platform = process.platform) {
|
|
60
|
+
return platform === 'win32' ? INSTALL_HINT[agent].windows : INSTALL_HINT[agent].posix;
|
|
61
|
+
}
|
|
62
|
+
function agentMissing(agent, bin) {
|
|
63
|
+
return new CliError(`${bin} is not installed, or not on your PATH.\nInstall it with: ${installHint(agent)}`, 1, 'event_agent_missing');
|
|
64
|
+
}
|
|
43
65
|
function requireKey() {
|
|
44
66
|
const stored = readEventKey();
|
|
45
67
|
if (stored === null) {
|
|
@@ -70,7 +92,10 @@ const setupCommand = defineCommand({
|
|
|
70
92
|
const check = await preflight(key, EVENT_PROXY_URL);
|
|
71
93
|
writeEventKey({ baseUrl: EVENT_PROXY_URL, key, savedAt: Date.now() });
|
|
72
94
|
const budget = await fetchBudget(key, EVENT_PROXY_URL);
|
|
73
|
-
|
|
95
|
+
// The 0600/0700 modes store.ts sets are a no-op on Windows, where `chmod` only toggles the
|
|
96
|
+
// read-only bit — so the promise is not made on the platform that cannot keep it.
|
|
97
|
+
const privacy = process.platform === 'win32' ? '' : ' (readable only by you)';
|
|
98
|
+
output.info(`Key stored in ${eventKeyPath()}${privacy}.`);
|
|
74
99
|
output.info(budgetLine(budget.spend, budget.maxBudget));
|
|
75
100
|
output.info('');
|
|
76
101
|
output.info('Start your agent with:');
|
|
@@ -106,13 +131,24 @@ const statusCommand = defineCommand({
|
|
|
106
131
|
});
|
|
107
132
|
},
|
|
108
133
|
});
|
|
134
|
+
const ENV_SHELLS = ['posix', 'powershell', 'cmd'];
|
|
109
135
|
const envCommand = defineCommand({
|
|
110
136
|
meta: { name: 'env', description: 'Print the environment variables, for setting up an agent by hand.' },
|
|
111
|
-
args:
|
|
137
|
+
args: {
|
|
138
|
+
...JSON_ARG,
|
|
139
|
+
shell: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: `Which shell to print for: ${ENV_SHELLS.join(', ')}. Defaults to this machine's.`,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
112
144
|
run({ args }) {
|
|
113
145
|
const output = createOutput(args.json === true);
|
|
114
146
|
const { key, baseUrl } = requireKey();
|
|
115
|
-
const
|
|
147
|
+
const requested = args.shell === undefined ? defaultEnvShell() : String(args.shell);
|
|
148
|
+
if (!ENV_SHELLS.includes(requested)) {
|
|
149
|
+
throw new CliError(`Unknown --shell "${requested}". Expected one of: ${ENV_SHELLS.join(', ')}.`, 1, 'event_env_shell');
|
|
150
|
+
}
|
|
151
|
+
const lines = exportLines(key, baseUrl, requested);
|
|
116
152
|
// Deliberately stdout even in human mode: this output is meant to be piped or eval'd.
|
|
117
153
|
for (const line of lines)
|
|
118
154
|
console.log(line);
|
|
@@ -143,17 +179,34 @@ async function runAgent(agent, passthrough, skipCheck) {
|
|
|
143
179
|
if (!skipCheck) {
|
|
144
180
|
// Before handing the terminal over: a broken key or a degraded proxy is far cheaper to learn
|
|
145
181
|
// about here than as a wall of agent errors thirty seconds in.
|
|
146
|
-
await preflight(key, baseUrl);
|
|
182
|
+
await preflight(key, baseUrl, agent);
|
|
147
183
|
}
|
|
148
184
|
// Codex runs against a Codex home we own, rewritten here so it can never be stale. Claude
|
|
149
185
|
// Code needs no equivalent: its whole configuration is the environment.
|
|
150
186
|
const codexHome = agent === 'codex' ? ensureCodexHome(baseUrl) : codexHomePath();
|
|
151
187
|
const spec = launchSpec(agent, key, baseUrl, codexHome, passthrough);
|
|
188
|
+
// Resolve the name to a file before spawning, because on Windows `spawn('claude')` finds nothing
|
|
189
|
+
// whatever is installed — PATHEXT is not consulted. Refusing here, with the install line, beats
|
|
190
|
+
// the same discovery arriving as an errno the participant has to interpret.
|
|
191
|
+
const resolved = resolveAgentBinary(spec.bin, spec.env);
|
|
192
|
+
if (resolved === null)
|
|
193
|
+
throw agentMissing(agent, spec.bin);
|
|
194
|
+
// `binInvocation` adds `shell: true` for a `.cmd`/`.bat` shim, which cannot run without it, and
|
|
195
|
+
// leaves a real `.exe` alone — no cmd.exe wrapped around an interactive terminal UI.
|
|
196
|
+
const invocation = binInvocation(resolved, spec.argv);
|
|
152
197
|
return new Promise((_resolve, reject) => {
|
|
153
|
-
const child = spawn(
|
|
198
|
+
const child = spawn(invocation.command, invocation.args, {
|
|
199
|
+
stdio: 'inherit',
|
|
200
|
+
env: spec.env,
|
|
201
|
+
shell: invocation.shell,
|
|
202
|
+
});
|
|
154
203
|
child.on('error', (error) => {
|
|
155
|
-
|
|
156
|
-
|
|
204
|
+
// EINVAL is what Node throws for a batch file spawned without a shell (CVE-2024-27980), and
|
|
205
|
+
// ENOENT is the pre-fix form of the same thing. Both mean "could not be launched", and
|
|
206
|
+
// neither should be reported as a mystery.
|
|
207
|
+
const code = errnoCode(error);
|
|
208
|
+
if (code === 'ENOENT' || code === 'EINVAL') {
|
|
209
|
+
reject(agentMissing(agent, spec.bin));
|
|
157
210
|
return;
|
|
158
211
|
}
|
|
159
212
|
reject(new CliError(`Could not start ${spec.bin}: ${error instanceof Error ? error.message : String(error)}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/commands/event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,
|
|
1
|
+
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/commands/event.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,5 +8,11 @@ export declare function renderCodexConfig(baseUrl: string): string;
|
|
|
8
8
|
* days, and a stale file would point at a proxy that no longer answers while looking fine.
|
|
9
9
|
*/
|
|
10
10
|
export declare function ensureCodexHome(baseUrl: string, baseDir?: string): string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Removed by `bitmagic event clear`, so nothing of ours outlives the event.
|
|
13
|
+
*
|
|
14
|
+
* A failure here is reported as a CliError rather than thrown raw: on Windows a Codex still holding
|
|
15
|
+
* the directory open makes `rmSync` throw EBUSY/EPERM, and `clear` is the command someone runs when
|
|
16
|
+
* things have already gone wrong. It must not add a stack trace to their day.
|
|
17
|
+
*/
|
|
12
18
|
export declare function removeCodexHome(baseDir?: string): boolean;
|
package/dist/event/codex-home.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import * as fs from 'fs';
|
|
28
28
|
import * as path from 'path';
|
|
29
29
|
import { CliError } from '../errors.js';
|
|
30
|
-
import { CODEX_KEY_ENV, openAiBaseUrl } from './launch.js';
|
|
30
|
+
import { CODEX_KEY_ENV, CODEX_MODEL, openAiBaseUrl } from './launch.js';
|
|
31
31
|
import { defaultBaseDir } from './store.js';
|
|
32
32
|
const DIR_MODE = 0o700;
|
|
33
33
|
export function codexHomePath(baseDir = defaultBaseDir()) {
|
|
@@ -38,7 +38,7 @@ export function renderCodexConfig(baseUrl) {
|
|
|
38
38
|
return `# Generated by \`bitmagic event\`. Rewritten on every launch — edits here are lost.
|
|
39
39
|
# This is a Codex home owned by Bitmagic for the duration of the event; your own
|
|
40
40
|
# ~/.codex/config.toml is untouched and still applies when you run codex directly.
|
|
41
|
-
model = "
|
|
41
|
+
model = "${CODEX_MODEL}"
|
|
42
42
|
model_provider = "bitmagic"
|
|
43
43
|
|
|
44
44
|
[model_providers.bitmagic]
|
|
@@ -66,12 +66,25 @@ export function ensureCodexHome(baseUrl, baseDir = defaultBaseDir()) {
|
|
|
66
66
|
}
|
|
67
67
|
return home;
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Removed by `bitmagic event clear`, so nothing of ours outlives the event.
|
|
71
|
+
*
|
|
72
|
+
* A failure here is reported as a CliError rather than thrown raw: on Windows a Codex still holding
|
|
73
|
+
* the directory open makes `rmSync` throw EBUSY/EPERM, and `clear` is the command someone runs when
|
|
74
|
+
* things have already gone wrong. It must not add a stack trace to their day.
|
|
75
|
+
*/
|
|
70
76
|
export function removeCodexHome(baseDir = defaultBaseDir()) {
|
|
71
77
|
const home = codexHomePath(baseDir);
|
|
72
78
|
if (!fs.existsSync(home))
|
|
73
79
|
return false;
|
|
74
|
-
|
|
80
|
+
try {
|
|
81
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new CliError(`Could not remove the event Codex configuration at ${home}: ` +
|
|
85
|
+
`${error instanceof Error ? error.message : String(error)}\n` +
|
|
86
|
+
'Close any running Codex and try again, or delete that directory yourself.', 1, 'event_codex_home_remove_failed');
|
|
87
|
+
}
|
|
75
88
|
return true;
|
|
76
89
|
}
|
|
77
90
|
//# sourceMappingURL=codex-home.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-home.js","sourceRoot":"","sources":["../../src/event/codex-home.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-home.js","sourceRoot":"","sources":["../../src/event/codex-home.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,QAAQ,GAAG,KAAK,CAAC;AAEvB,MAAM,UAAU,aAAa,CAAC,UAAkB,cAAc,EAAE;IAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO;;;WAGE,WAAW;;;;;cAKR,aAAa,CAAC,OAAO,CAAC;aACvB,aAAa;;;CAGzB,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,UAAkB,cAAc,EAAE;IACjF,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAChB,gDAAgD,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACjH,CAAC,EACD,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB,cAAc,EAAE;IAChE,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC;QACH,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAChB,qDAAqD,IAAI,IAAI;YAC3D,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;YAC7D,2EAA2E,EAC7E,CAAC,EACD,gCAAgC,CACjC,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/event/launch.d.ts
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* `baseEnv()` in types.ts and the `-c key=value` overrides in codex.ts. That code is the lab
|
|
17
17
|
* harness and is never built into dist/, so this is a copied pattern rather than an import.
|
|
18
18
|
*/
|
|
19
|
+
/** Model aliases the event proxy serves. Anything else is a 400 — it knows only its own names. */
|
|
20
|
+
export declare const OPUS_ALIAS = "claude-5.5-opus";
|
|
21
|
+
/** Codex's model: GPT-6 Sol on Bedrock, the same sponsor account that serves Opus. */
|
|
22
|
+
export declare const CODEX_MODEL = "bedrock-gpt-6-sol";
|
|
19
23
|
/** The env var Codex is told to read the key from, via `env_key`. */
|
|
20
24
|
export declare const CODEX_KEY_ENV = "BITMAGIC_EVENT_KEY";
|
|
21
25
|
export type EventAgent = 'claude' | 'codex';
|
|
@@ -24,6 +28,8 @@ export interface LaunchSpec {
|
|
|
24
28
|
argv: string[];
|
|
25
29
|
env: Record<string, string | undefined>;
|
|
26
30
|
}
|
|
31
|
+
/** The shells `bitmagic event env` can print for. */
|
|
32
|
+
export type EnvShell = 'posix' | 'powershell' | 'cmd';
|
|
27
33
|
/**
|
|
28
34
|
* The two clients want DIFFERENT forms of the same URL, and swapping them produces a 404 that
|
|
29
35
|
* reads like the proxy is down:
|
|
@@ -45,7 +51,7 @@ export declare function openAiBaseUrl(baseUrl: string): string;
|
|
|
45
51
|
* only the Opus default leaves those background calls 400ing. There is no Sonnet on the proxy,
|
|
46
52
|
* which is why Sonnet is pinned to Opus rather than to a Sonnet alias.
|
|
47
53
|
*/
|
|
48
|
-
export declare function claudeEnv(key: string, baseUrl: string, parentEnv?: Record<string, string | undefined
|
|
54
|
+
export declare function claudeEnv(key: string, baseUrl: string, parentEnv?: Record<string, string | undefined>, platform?: string): Record<string, string | undefined>;
|
|
49
55
|
/**
|
|
50
56
|
* Codex is configured through an isolated CODEX_HOME rather than `-c` overrides — see
|
|
51
57
|
* event/codex-home.ts for why overrides cannot work against a real installation.
|
|
@@ -55,6 +61,15 @@ export declare function codexEnv(key: string, codexHome: string, parentEnv?: Rec
|
|
|
55
61
|
* Everything needed to spawn one agent. Pure — the caller does the spawning, and for Codex the
|
|
56
62
|
* caller has already materialised `codexHome` (ensureCodexHome).
|
|
57
63
|
*/
|
|
58
|
-
export declare function launchSpec(agent: EventAgent, key: string, baseUrl: string, codexHome: string, passthrough?: string[], parentEnv?: Record<string, string | undefined
|
|
59
|
-
/**
|
|
60
|
-
export declare function
|
|
64
|
+
export declare function launchSpec(agent: EventAgent, key: string, baseUrl: string, codexHome: string, passthrough?: string[], parentEnv?: Record<string, string | undefined>, platform?: string): LaunchSpec;
|
|
65
|
+
/** Which shell `bitmagic event env` should print for when nobody said. */
|
|
66
|
+
export declare function defaultEnvShell(platform?: string): EnvShell;
|
|
67
|
+
/**
|
|
68
|
+
* The environment `bitmagic event env` prints, for anyone wiring it up by hand.
|
|
69
|
+
*
|
|
70
|
+
* Per-shell because this is the documented fallback for whoever the launcher failed, and a Windows
|
|
71
|
+
* participant is the likeliest person to reach it. POSIX `export` lines are a syntax error in both
|
|
72
|
+
* `cmd.exe` and PowerShell, so printing only those would send exactly the person who needs help
|
|
73
|
+
* somewhere that cannot work.
|
|
74
|
+
*/
|
|
75
|
+
export declare function exportLines(key: string, baseUrl: string, shell?: EnvShell): string[];
|
package/dist/event/launch.js
CHANGED
|
@@ -17,10 +17,31 @@
|
|
|
17
17
|
* harness and is never built into dist/, so this is a copied pattern rather than an import.
|
|
18
18
|
*/
|
|
19
19
|
/** Model aliases the event proxy serves. Anything else is a 400 — it knows only its own names. */
|
|
20
|
-
const OPUS_ALIAS = 'claude-5-opus';
|
|
20
|
+
export const OPUS_ALIAS = 'claude-5.5-opus';
|
|
21
21
|
const HAIKU_ALIAS = 'claude-4.5-haiku';
|
|
22
|
+
/** Codex's model: GPT-6 Sol on Bedrock, the same sponsor account that serves Opus. */
|
|
23
|
+
export const CODEX_MODEL = 'bedrock-gpt-6-sol';
|
|
22
24
|
/** The env var Codex is told to read the key from, via `env_key`. */
|
|
23
25
|
export const CODEX_KEY_ENV = 'BITMAGIC_EVENT_KEY';
|
|
26
|
+
/**
|
|
27
|
+
* Variables that select a model provider, and so OUTRANK the event key.
|
|
28
|
+
*
|
|
29
|
+
* Claude Code's documented credential precedence puts cloud-provider selection at rank 1 and
|
|
30
|
+
* `ANTHROPIC_AUTH_TOKEN` — what this launcher sets — at rank 2. A participant who already uses
|
|
31
|
+
* Claude Code against their employer's Bedrock has `CLAUDE_CODE_USE_BEDROCK=1` exported, and it
|
|
32
|
+
* would win: their session would run on their own AWS account, the event key would spend nothing,
|
|
33
|
+
* and no error would appear anywhere. The sponsor's credits go unused and the participant's
|
|
34
|
+
* employer gets the bill.
|
|
35
|
+
*
|
|
36
|
+
* At an AWS-sponsored event the people carrying this variable are not a rare case — they are the
|
|
37
|
+
* likeliest attendees.
|
|
38
|
+
*
|
|
39
|
+
* The lower-ranked credentials need no handling: `ANTHROPIC_API_KEY` (3), `apiKeyHelper` (4),
|
|
40
|
+
* `CLAUDE_CODE_OAUTH_TOKEN` (5), profiles (6) and a `/login` subscription (7) all lose to the
|
|
41
|
+
* bearer token on their own. ANTHROPIC_API_KEY is removed anyway because setting it alongside
|
|
42
|
+
* ANTHROPIC_AUTH_TOKEN is explicitly forbidden.
|
|
43
|
+
*/
|
|
44
|
+
const CLAUDE_PROVIDER_SELECTORS = ['CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY'];
|
|
24
45
|
/** Session-scoped variables a spawning Claude Code exports, which must not reach a fresh agent. */
|
|
25
46
|
const CLAUDE_SESSION_MARKERS = [
|
|
26
47
|
'CLAUDECODE',
|
|
@@ -33,6 +54,26 @@ const CLAUDE_SESSION_MARKERS = [
|
|
|
33
54
|
'CLAUDE_CODE_EXECPATH',
|
|
34
55
|
'CLAUDE_PID',
|
|
35
56
|
];
|
|
57
|
+
/**
|
|
58
|
+
* Removes a variable from the child environment.
|
|
59
|
+
*
|
|
60
|
+
* Windows environment names are CASE-INSENSITIVE: `Anthropic_Api_Key` set through the System
|
|
61
|
+
* Properties dialog is the same variable Claude Code reads as `ANTHROPIC_API_KEY`, but
|
|
62
|
+
* `delete env.ANTHROPIC_API_KEY` does not remove it — so the one condition this code exists to
|
|
63
|
+
* prevent survives the launch. On POSIX the opposite is true and a case-insensitive sweep would
|
|
64
|
+
* delete unrelated variables, so the platform decides.
|
|
65
|
+
*/
|
|
66
|
+
function deleteEnvVar(env, name, platform) {
|
|
67
|
+
if (platform !== 'win32') {
|
|
68
|
+
delete env[name];
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const lower = name.toLowerCase();
|
|
72
|
+
for (const key of Object.keys(env)) {
|
|
73
|
+
if (key.toLowerCase() === lower)
|
|
74
|
+
delete env[key];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
36
77
|
/**
|
|
37
78
|
* The two clients want DIFFERENT forms of the same URL, and swapping them produces a 404 that
|
|
38
79
|
* reads like the proxy is down:
|
|
@@ -58,26 +99,31 @@ export function openAiBaseUrl(baseUrl) {
|
|
|
58
99
|
* only the Opus default leaves those background calls 400ing. There is no Sonnet on the proxy,
|
|
59
100
|
* which is why Sonnet is pinned to Opus rather than to a Sonnet alias.
|
|
60
101
|
*/
|
|
61
|
-
export function claudeEnv(key, baseUrl, parentEnv = process.env) {
|
|
102
|
+
export function claudeEnv(key, baseUrl, parentEnv = process.env, platform = process.platform) {
|
|
62
103
|
const env = { ...parentEnv };
|
|
63
104
|
// Setting ANTHROPIC_API_KEY alongside ANTHROPIC_AUTH_TOKEN is explicitly forbidden, and a
|
|
64
105
|
// participant who already uses Claude Code on their own key will have one exported. Removing
|
|
65
106
|
// it is the main thing this launcher can do that a copied export block cannot.
|
|
66
|
-
|
|
107
|
+
deleteEnvVar(env, 'ANTHROPIC_API_KEY', platform);
|
|
67
108
|
// ANTHROPIC_MODEL, if the participant has pinned one for their own use, wins over the
|
|
68
109
|
// DEFAULT_* vars below and names a model the proxy does not serve — a 400 on every call.
|
|
69
|
-
|
|
110
|
+
deleteEnvVar(env, 'ANTHROPIC_MODEL', platform);
|
|
70
111
|
// Session markers from a Claude Code that spawned us — participants really do ask their agent
|
|
71
112
|
// to run the setup for them. cli/lab/drivers/types.ts drops the first two so a nested agent
|
|
72
113
|
// does not think it is inside another session; the rest are handles (sockets, tokens, pids)
|
|
73
114
|
// that name a process this one is not. CLAUDE_CONFIG_DIR is deliberately left alone: that one
|
|
74
115
|
// is a standing preference rather than session state.
|
|
75
116
|
//
|
|
76
|
-
// Note this is NOT what causes Claude Code's `unrecognized_model: claude-5-opus[1m]` line —
|
|
117
|
+
// Note this is NOT what causes Claude Code's `unrecognized_model: claude-5.5-opus[1m]` line —
|
|
77
118
|
// that appears with a clean environment and no launcher at all, because Claude Code's own
|
|
78
119
|
// model registry does not know the proxy's aliases. It is cosmetic; the call succeeds.
|
|
120
|
+
// A provider selector outranks the event key outright — see CLAUDE_PROVIDER_SELECTORS. Removing
|
|
121
|
+
// these is the difference between the sponsor paying for the session and the participant's own
|
|
122
|
+
// employer paying for it without either of them being told.
|
|
123
|
+
for (const selector of CLAUDE_PROVIDER_SELECTORS)
|
|
124
|
+
deleteEnvVar(env, selector, platform);
|
|
79
125
|
for (const marker of CLAUDE_SESSION_MARKERS)
|
|
80
|
-
|
|
126
|
+
deleteEnvVar(env, marker, platform);
|
|
81
127
|
env.ANTHROPIC_BASE_URL = anthropicBaseUrl(baseUrl);
|
|
82
128
|
env.ANTHROPIC_AUTH_TOKEN = key;
|
|
83
129
|
env.ANTHROPIC_DEFAULT_OPUS_MODEL = OPUS_ALIAS;
|
|
@@ -100,23 +146,43 @@ export function codexEnv(key, codexHome, parentEnv = process.env) {
|
|
|
100
146
|
* Everything needed to spawn one agent. Pure — the caller does the spawning, and for Codex the
|
|
101
147
|
* caller has already materialised `codexHome` (ensureCodexHome).
|
|
102
148
|
*/
|
|
103
|
-
export function launchSpec(agent, key, baseUrl, codexHome, passthrough = [], parentEnv = process.env) {
|
|
149
|
+
export function launchSpec(agent, key, baseUrl, codexHome, passthrough = [], parentEnv = process.env, platform = process.platform) {
|
|
104
150
|
if (agent === 'claude') {
|
|
105
|
-
return { bin: 'claude', argv: [...passthrough], env: claudeEnv(key, baseUrl, parentEnv) };
|
|
151
|
+
return { bin: 'claude', argv: [...passthrough], env: claudeEnv(key, baseUrl, parentEnv, platform) };
|
|
106
152
|
}
|
|
107
153
|
// No argv configuration at all: the generated config.toml in CODEX_HOME carries the provider.
|
|
108
154
|
return { bin: 'codex', argv: [...passthrough], env: codexEnv(key, codexHome, parentEnv) };
|
|
109
155
|
}
|
|
110
|
-
/**
|
|
111
|
-
export function
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
156
|
+
/** Which shell `bitmagic event env` should print for when nobody said. */
|
|
157
|
+
export function defaultEnvShell(platform = process.platform) {
|
|
158
|
+
return platform === 'win32' ? 'powershell' : 'posix';
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The environment `bitmagic event env` prints, for anyone wiring it up by hand.
|
|
162
|
+
*
|
|
163
|
+
* Per-shell because this is the documented fallback for whoever the launcher failed, and a Windows
|
|
164
|
+
* participant is the likeliest person to reach it. POSIX `export` lines are a syntax error in both
|
|
165
|
+
* `cmd.exe` and PowerShell, so printing only those would send exactly the person who needs help
|
|
166
|
+
* somewhere that cannot work.
|
|
167
|
+
*/
|
|
168
|
+
export function exportLines(key, baseUrl, shell = defaultEnvShell()) {
|
|
169
|
+
const vars = [
|
|
170
|
+
['ANTHROPIC_BASE_URL', anthropicBaseUrl(baseUrl)],
|
|
171
|
+
['ANTHROPIC_AUTH_TOKEN', key],
|
|
172
|
+
['ANTHROPIC_DEFAULT_OPUS_MODEL', OPUS_ALIAS],
|
|
173
|
+
['ANTHROPIC_DEFAULT_SONNET_MODEL', OPUS_ALIAS],
|
|
174
|
+
['ANTHROPIC_DEFAULT_HAIKU_MODEL', HAIKU_ALIAS],
|
|
175
|
+
['CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS', '1'],
|
|
176
|
+
[CODEX_KEY_ENV, key],
|
|
120
177
|
];
|
|
178
|
+
switch (shell) {
|
|
179
|
+
case 'powershell':
|
|
180
|
+
return vars.map(([name, value]) => `$env:${name} = "${value}"`);
|
|
181
|
+
case 'cmd':
|
|
182
|
+
// No quotes: cmd.exe would make them part of the value.
|
|
183
|
+
return vars.map(([name, value]) => `set ${name}=${value}`);
|
|
184
|
+
default:
|
|
185
|
+
return vars.map(([name, value]) => `export ${name}=${value}`);
|
|
186
|
+
}
|
|
121
187
|
}
|
|
122
188
|
//# sourceMappingURL=launch.js.map
|
package/dist/event/launch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/event/launch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,kGAAkG;AAClG,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/event/launch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EventAgent } from './launch.js';
|
|
1
2
|
export interface PreflightResult {
|
|
2
3
|
/** What the proxy actually served, from `x-litellm-model-name`. */
|
|
3
4
|
servedModel: string;
|
|
@@ -6,4 +7,4 @@ export interface PreflightResult {
|
|
|
6
7
|
/** Cumulative spend on this key in USD, from `x-litellm-key-spend`. */
|
|
7
8
|
keySpend: number | undefined;
|
|
8
9
|
}
|
|
9
|
-
export declare function preflight(key: string, baseUrl: string): Promise<PreflightResult>;
|
|
10
|
+
export declare function preflight(key: string, baseUrl: string, agent?: EventAgent): Promise<PreflightResult>;
|
package/dist/event/preflight.js
CHANGED
|
@@ -12,8 +12,32 @@
|
|
|
12
12
|
* into a sentence the participant can act on.
|
|
13
13
|
*/
|
|
14
14
|
import { CliError } from '../errors.js';
|
|
15
|
-
import { anthropicBaseUrl } from './launch.js';
|
|
15
|
+
import { CODEX_MODEL, OPUS_ALIAS, anthropicBaseUrl, openAiBaseUrl } from './launch.js';
|
|
16
16
|
const PREFLIGHT_TIMEOUT_MS = 15_000;
|
|
17
|
+
/**
|
|
18
|
+
* Each agent is probed on the model and wire API it will actually use, so a proxy that serves
|
|
19
|
+
* Opus but not GPT (or the reverse) is caught before that agent starts, not after.
|
|
20
|
+
*
|
|
21
|
+
* Codex goes through the Responses API because that is what `wire_api = "responses"` makes it
|
|
22
|
+
* call; 16 is the smallest `max_output_tokens` the Responses API accepts.
|
|
23
|
+
*/
|
|
24
|
+
const PROBES = {
|
|
25
|
+
claude: {
|
|
26
|
+
label: 'Opus 5.5',
|
|
27
|
+
url: (baseUrl) => `${anthropicBaseUrl(baseUrl)}/v1/messages`,
|
|
28
|
+
headers: { 'anthropic-version': '2023-06-01' },
|
|
29
|
+
// One token: enough to prove the whole path works, cheap enough to run on every launch.
|
|
30
|
+
body: { model: OPUS_ALIAS, max_tokens: 1, messages: [{ role: 'user', content: 'hi' }] },
|
|
31
|
+
served: ['opus-5-5', 'opus-5.5'],
|
|
32
|
+
},
|
|
33
|
+
codex: {
|
|
34
|
+
label: 'GPT-6 Sol',
|
|
35
|
+
url: (baseUrl) => `${openAiBaseUrl(baseUrl)}/responses`,
|
|
36
|
+
headers: {},
|
|
37
|
+
body: { model: CODEX_MODEL, max_output_tokens: 16, input: 'hi' },
|
|
38
|
+
served: ['gpt-6-sol'],
|
|
39
|
+
},
|
|
40
|
+
};
|
|
17
41
|
function numberHeader(headers, name) {
|
|
18
42
|
const raw = headers.get(name);
|
|
19
43
|
if (raw === null)
|
|
@@ -40,19 +64,18 @@ function refusal(status, body) {
|
|
|
40
64
|
}
|
|
41
65
|
return new CliError(`The event proxy returned HTTP ${status}.\n${body.slice(0, 300)}`, 1, 'event_proxy_error');
|
|
42
66
|
}
|
|
43
|
-
export async function preflight(key, baseUrl) {
|
|
44
|
-
const
|
|
67
|
+
export async function preflight(key, baseUrl, agent = 'claude') {
|
|
68
|
+
const probe = PROBES[agent];
|
|
45
69
|
let response;
|
|
46
70
|
try {
|
|
47
|
-
response = await fetch(url, {
|
|
71
|
+
response = await fetch(probe.url(baseUrl), {
|
|
48
72
|
method: 'POST',
|
|
49
73
|
headers: {
|
|
50
74
|
Authorization: `Bearer ${key}`,
|
|
51
|
-
'anthropic-version': '2023-06-01',
|
|
52
75
|
'content-type': 'application/json',
|
|
76
|
+
...probe.headers,
|
|
53
77
|
},
|
|
54
|
-
|
|
55
|
-
body: JSON.stringify({ model: 'claude-5-opus', max_tokens: 1, messages: [{ role: 'user', content: 'hi' }] }),
|
|
78
|
+
body: JSON.stringify(probe.body),
|
|
56
79
|
signal: AbortSignal.timeout(PREFLIGHT_TIMEOUT_MS),
|
|
57
80
|
});
|
|
58
81
|
}
|
|
@@ -65,11 +88,11 @@ export async function preflight(key, baseUrl) {
|
|
|
65
88
|
throw refusal(response.status, await response.text().catch(() => ''));
|
|
66
89
|
}
|
|
67
90
|
const servedModel = response.headers.get('x-litellm-model-name') ?? '';
|
|
68
|
-
if (!servedModel.includes(
|
|
69
|
-
// A 200 that did not come from
|
|
91
|
+
if (!probe.served.some((name) => servedModel.includes(name))) {
|
|
92
|
+
// A 200 that did not come from the intended model means a fallback served it. Refusing here rather than
|
|
70
93
|
// warning is deliberate: the participant would otherwise spend their budget on a weaker
|
|
71
94
|
// model without ever being told, and the spend accounting would be wrong too.
|
|
72
|
-
throw new CliError(`The event proxy answered with "${servedModel || 'an unknown model'}" instead of
|
|
95
|
+
throw new CliError(`The event proxy answered with "${servedModel || 'an unknown model'}" instead of ${probe.label}.\n` +
|
|
73
96
|
'That usually means the proxy is degraded. Tell an organiser before continuing.', 1, 'event_model_downgrade');
|
|
74
97
|
}
|
|
75
98
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/event/preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/event/preflight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Exists = (candidate: string) => boolean;
|
|
2
|
+
/**
|
|
3
|
+
* The absolute path of `name` on PATH, or `null` when it is not there.
|
|
4
|
+
*
|
|
5
|
+
* On anything but Windows the name is returned unchanged: `spawn` does the PATH search itself, and
|
|
6
|
+
* resolving it here would only add a way to disagree with the thing that actually launches it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveAgentBinary(name: string, env?: Record<string, string | undefined>, platform?: string, exists?: Exists): string | null;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding the participant's `claude` / `codex` executable before spawning it.
|
|
3
|
+
*
|
|
4
|
+
* On POSIX this is not a problem worth solving: the name goes to `spawn`, which searches PATH and
|
|
5
|
+
* executes whatever it finds. On Windows it is the whole problem. `CreateProcess` — which is where
|
|
6
|
+
* a non-shell spawn ends up — does not consult PATHEXT and cannot execute a batch file at all, so
|
|
7
|
+
* `spawn('claude')` fails for every installation that is not literally a file named `claude`:
|
|
8
|
+
*
|
|
9
|
+
* - `npm install -g @anthropic-ai/claude-code` writes `claude.cmd`. That is a batch shim, and
|
|
10
|
+
* since the CVE-2024-27980 fix (Node 18.20.2 / 20.12.2) spawning one without `shell: true`
|
|
11
|
+
* throws EINVAL rather than running it.
|
|
12
|
+
* - The agents' own native installers write `claude.exe`, which runs fine — but only once
|
|
13
|
+
* something has resolved the name to the file, extension included.
|
|
14
|
+
*
|
|
15
|
+
* So this module answers "which file", and `project/spawn-bin.ts` answers "how to run it". Keeping
|
|
16
|
+
* them apart is what lets a real `.exe` spawn directly, with no `cmd.exe` wrapped around an
|
|
17
|
+
* interactive terminal UI, while a `.cmd` shim still gets the shell it cannot run without.
|
|
18
|
+
*
|
|
19
|
+
* Pure, with PATH, PATHEXT and the existence probe injected, so the Windows behaviour is a test
|
|
20
|
+
* table rather than a machine we do not have — the same approach `binInvocation` and `openerFor`
|
|
21
|
+
* already take.
|
|
22
|
+
*/
|
|
23
|
+
import * as fs from 'fs';
|
|
24
|
+
import * as path from 'path';
|
|
25
|
+
/** What Windows uses when PATHEXT is unset. Only the executable kinds an agent could ship as. */
|
|
26
|
+
const DEFAULT_PATHEXT = '.COM;.EXE;.BAT;.CMD';
|
|
27
|
+
const realExists = (candidate) => {
|
|
28
|
+
try {
|
|
29
|
+
return fs.statSync(candidate).isFile();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The absolute path of `name` on PATH, or `null` when it is not there.
|
|
37
|
+
*
|
|
38
|
+
* On anything but Windows the name is returned unchanged: `spawn` does the PATH search itself, and
|
|
39
|
+
* resolving it here would only add a way to disagree with the thing that actually launches it.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveAgentBinary(name, env = process.env, platform = process.platform, exists = realExists) {
|
|
42
|
+
if (platform !== 'win32')
|
|
43
|
+
return name;
|
|
44
|
+
const pathValue = env.PATH ?? env.Path ?? '';
|
|
45
|
+
if (pathValue === '')
|
|
46
|
+
return null;
|
|
47
|
+
// An empty PATHEXT entry stands for the name exactly as given, which is how a extensionless
|
|
48
|
+
// executable (or one the participant typed with its extension) is still found.
|
|
49
|
+
const extensions = ['', ...(env.PATHEXT ?? DEFAULT_PATHEXT).split(';').filter((ext) => ext !== '')];
|
|
50
|
+
for (const dir of pathValue.split(';')) {
|
|
51
|
+
if (dir === '')
|
|
52
|
+
continue;
|
|
53
|
+
for (const ext of extensions) {
|
|
54
|
+
// `path.win32`, not `path.join`: the latter uses the separator of the machine running the
|
|
55
|
+
// code, so building a Windows path on a developer's Mac would produce `C:\dir/claude.exe`.
|
|
56
|
+
// The tests are the only place that happens, which is exactly where it would go unnoticed.
|
|
57
|
+
//
|
|
58
|
+
// Windows paths are case-insensitive, so the casing PATHEXT uses (`.EXE`) does not have to
|
|
59
|
+
// match the file's (`claude.exe`) — but the extension must be ON the candidate, because
|
|
60
|
+
// `statSync('…/claude')` does not find `claude.exe`.
|
|
61
|
+
const candidate = path.win32.join(dir, `${name}${ext}`);
|
|
62
|
+
if (exists(candidate))
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=resolve-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-agent.js","sourceRoot":"","sources":["../../src/event/resolve-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,iGAAiG;AACjG,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAI9C,MAAM,UAAU,GAAW,CAAC,SAAS,EAAE,EAAE;IACvC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,MAA0C,OAAO,CAAC,GAAG,EACrD,WAAmB,OAAO,CAAC,QAAQ,EACnC,SAAiB,UAAU;IAE3B,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7C,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAElC,4FAA4F;IAC5F,+EAA+E;IAC/E,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;IAEpG,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,GAAG,KAAK,EAAE;YAAE,SAAS;QACzB,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,0FAA0F;YAC1F,2FAA2F;YAC3F,2FAA2F;YAC3F,EAAE;YACF,2FAA2F;YAC3F,wFAAwF;YACxF,qDAAqD;YACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC;YACxD,IAAI,MAAM,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/event/store.js
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
* applies when it creates the file. A corrupt file is treated as absent, not as an error: the fix
|
|
11
11
|
* is always `bitmagic event setup` again, and a parse failure must not wedge the command that
|
|
12
12
|
* would repair it.
|
|
13
|
+
*
|
|
14
|
+
* Those modes are POSIX-only. Windows `chmod` toggles nothing but the read-only bit, so the file
|
|
15
|
+
* there is protected by the user profile's ACL and not by anything this module does — which is why
|
|
16
|
+
* `bitmagic event setup` does not claim otherwise on that platform.
|
|
13
17
|
*/
|
|
14
18
|
import * as fs from 'fs';
|
|
15
19
|
import * as os from 'os';
|
package/dist/event/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/event/store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/event/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,34 +1,15 @@
|
|
|
1
|
+
import { isSafeCandidateId, newCandidateId, type AcceptedReference as SharedAcceptedReference, type CandidateRecord } from '@bitmagic/asset-core/reference-record';
|
|
1
2
|
export declare const REFERENCE_DIR: string;
|
|
2
3
|
export declare function referenceDirPath(root: string): string;
|
|
3
4
|
export declare function acceptedReferencePath(root: string): string;
|
|
4
5
|
export declare function candidateImagePath(root: string, id: string): string;
|
|
5
|
-
/**
|
|
6
|
-
export
|
|
7
|
-
id: string;
|
|
8
|
-
/** The Asset Forger URL the generation returned. Short-lived; the accept re-hosts it. */
|
|
9
|
-
url: string;
|
|
10
|
-
/** The prompt actually sent, truncated — enough to recognise a candidate in a list. */
|
|
11
|
-
prompt: string;
|
|
12
|
-
/** The candidate this one was iterated from (`--from`), if any. */
|
|
13
|
-
from?: string;
|
|
14
|
-
/** An explicit `--reference-image-url` this candidate was steered by, if any. */
|
|
15
|
-
referenceImageUrl?: string;
|
|
16
|
-
createdAt: string;
|
|
17
|
-
}
|
|
18
|
-
/** The accepted reference — what every generator and forge inherits. */
|
|
19
|
-
export interface AcceptedReference {
|
|
20
|
-
/** The URL generators are given: the re-hosted public URL, or the source URL when re-hosting failed. */
|
|
21
|
-
url: string;
|
|
22
|
-
/** False when re-hosting failed and `url` is the (expiring) source URL — worth re-accepting. */
|
|
23
|
-
hosted: boolean;
|
|
24
|
-
/** What was accepted, before any re-hosting. */
|
|
25
|
-
sourceUrl: string;
|
|
26
|
-
/** Absent when a bare URL was accepted rather than a generated candidate. */
|
|
27
|
-
candidateId?: string;
|
|
6
|
+
/** The CLI keeps a local copy of the accepted bytes; the shared record has no such field. */
|
|
7
|
+
export type AcceptedReference = SharedAcceptedReference & {
|
|
28
8
|
/** The local copy, when bytes were available to keep. */
|
|
29
9
|
imagePath?: string;
|
|
30
|
-
|
|
31
|
-
}
|
|
10
|
+
};
|
|
11
|
+
export type { CandidateRecord };
|
|
12
|
+
export { isSafeCandidateId, newCandidateId };
|
|
32
13
|
export declare function readAcceptedReference(root: string): AcceptedReference | null;
|
|
33
14
|
export declare function writeAcceptedReference(root: string, accepted: AcceptedReference): void;
|
|
34
15
|
/** Remove the accepted reference. Candidates stay — clearing a decision is not deleting the work. */
|
|
@@ -37,10 +18,6 @@ export declare function readCandidate(root: string, id: string): CandidateRecord
|
|
|
37
18
|
export declare function writeCandidate(root: string, record: CandidateRecord): void;
|
|
38
19
|
/** Every readable candidate, newest first (ids sort chronologically by construction). */
|
|
39
20
|
export declare function listCandidates(root: string): CandidateRecord[];
|
|
40
|
-
/** `ref-<yyyymmdd-hhmmss>-<4 rand>` — short enough to type, sortable by creation time. */
|
|
41
|
-
export declare function newCandidateId(now?: Date): string;
|
|
42
|
-
/** Candidate ids become file names, so anything path-shaped is refused, never sanitised. */
|
|
43
|
-
export declare function isSafeCandidateId(id: string): boolean;
|
|
44
21
|
/** The two flags every reference-aware command declares (see REFERENCE_IMAGE_FLAG / NO_REFERENCE_FLAG). */
|
|
45
22
|
export interface ReferenceFlagArgs {
|
|
46
23
|
'reference-image-url'?: string;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import * as fs from 'fs';
|
|
22
22
|
import * as path from 'path';
|
|
23
|
+
import { isSafeCandidateId, newCandidateId, parseCandidateRecord, } from '@bitmagic/asset-core/reference-record';
|
|
23
24
|
export const REFERENCE_DIR = path.join('.bitmagic', 'reference');
|
|
24
25
|
const ACCEPTED_FILE = path.join('.bitmagic', 'reference.json');
|
|
25
26
|
export function referenceDirPath(root) {
|
|
@@ -34,6 +35,7 @@ export function candidateImagePath(root, id) {
|
|
|
34
35
|
function candidateRecordPath(root, id) {
|
|
35
36
|
return path.join(referenceDirPath(root), `${id}.json`);
|
|
36
37
|
}
|
|
38
|
+
export { isSafeCandidateId, newCandidateId };
|
|
37
39
|
function readJsonFile(file) {
|
|
38
40
|
let raw;
|
|
39
41
|
try {
|
|
@@ -87,19 +89,7 @@ export function readCandidate(root, id) {
|
|
|
87
89
|
if (!isSafeCandidateId(id))
|
|
88
90
|
return null;
|
|
89
91
|
const parsed = readJsonFile(candidateRecordPath(root, id));
|
|
90
|
-
|
|
91
|
-
return null;
|
|
92
|
-
const { url, prompt, from, referenceImageUrl, createdAt } = parsed;
|
|
93
|
-
if (!isString(url) || url.length === 0 || !isString(prompt) || !isString(createdAt))
|
|
94
|
-
return null;
|
|
95
|
-
return {
|
|
96
|
-
id,
|
|
97
|
-
url,
|
|
98
|
-
prompt,
|
|
99
|
-
createdAt,
|
|
100
|
-
...(isString(from) ? { from } : {}),
|
|
101
|
-
...(isString(referenceImageUrl) ? { referenceImageUrl } : {}),
|
|
102
|
-
};
|
|
92
|
+
return parsed ? parseCandidateRecord(parsed, id) : null;
|
|
103
93
|
}
|
|
104
94
|
export function writeCandidate(root, record) {
|
|
105
95
|
fs.mkdirSync(referenceDirPath(root), { recursive: true });
|
|
@@ -120,18 +110,6 @@ export function listCandidates(root) {
|
|
|
120
110
|
.filter((record) => record !== null)
|
|
121
111
|
.sort((a, b) => b.id.localeCompare(a.id));
|
|
122
112
|
}
|
|
123
|
-
/** `ref-<yyyymmdd-hhmmss>-<4 rand>` — short enough to type, sortable by creation time. */
|
|
124
|
-
export function newCandidateId(now = new Date()) {
|
|
125
|
-
const pad = (n) => String(n).padStart(2, '0');
|
|
126
|
-
const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` +
|
|
127
|
-
`-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
128
|
-
const rand = Math.random().toString(36).slice(2, 6).padEnd(4, '0');
|
|
129
|
-
return `ref-${stamp}-${rand}`;
|
|
130
|
-
}
|
|
131
|
-
/** Candidate ids become file names, so anything path-shaped is refused, never sanitised. */
|
|
132
|
-
export function isSafeCandidateId(id) {
|
|
133
|
-
return /^[a-z0-9][a-z0-9-]{0,63}$/.test(id);
|
|
134
|
-
}
|
|
135
113
|
/**
|
|
136
114
|
* The reference a generating command should send, in precedence order: an explicit
|
|
137
115
|
* `--reference-image-url` wins outright (it IS a reference choice), `--no-reference` disables,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/project/reference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/project/reference.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitmagic/cli",
|
|
3
|
-
"version": "0.1.68-dev.
|
|
3
|
+
"version": "0.1.68-dev.5",
|
|
4
4
|
"description": "Build Bitmagic games from your own agent tool",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "Bitmagic Oy",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"playwright-core": "^1.59.1",
|
|
26
26
|
"tar": "^7.4.3",
|
|
27
27
|
"ws": "^8.21.3",
|
|
28
|
-
"@bitmagic/animation-forger": "0.1.23-dev.
|
|
29
|
-
"@bitmagic/world-forger": "0.1.28-dev.
|
|
30
|
-
"@bitmagic/asset-core": "0.2.23-dev.
|
|
28
|
+
"@bitmagic/animation-forger": "0.1.23-dev.5",
|
|
29
|
+
"@bitmagic/world-forger": "0.1.28-dev.5",
|
|
30
|
+
"@bitmagic/asset-core": "0.2.23-dev.5"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@eslint/js": "^9.38.0",
|