@cordfuse/crosstalk 8.3.0 → 8.3.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/dispatch.ts +27 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordfuse/crosstalk",
3
- "version": "8.3.0",
3
+ "version": "8.3.1",
4
4
  "description": "Crosstalk — agent-agnostic swarm communication protocol over a shared directory (git or filesystem transport). Operator CLI + daemon in one binary.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/dispatch.ts CHANGED
@@ -52,7 +52,7 @@ import { startApi } from './api.js';
52
52
  import { logBuffer } from './log-buffer.js';
53
53
  import { FileUserStore } from './auth/users.js';
54
54
  import { FileTokenStore } from './auth/tokens.js';
55
- import { SetupState } from './auth/setup.js';
55
+ import { SetupState, bootstrapFromEnv } from './auth/setup.js';
56
56
  import type { Server as HttpServer } from 'http';
57
57
 
58
58
  const RUNTIME_VERSION: string = (() => {
@@ -478,15 +478,32 @@ async function main(): Promise<void> {
478
478
  const userStore = new FileUserStore(join(authDir, 'users.json'));
479
479
  const tokenStore = new FileTokenStore(join(authDir, 'tokens.json'));
480
480
  const setupState = new SetupState(join(authDir, 'setup-token'));
481
- // First-run: mint setup token + log the URL so the operator can
482
- // bootstrap from the browser. Subsequent boots: leave the
483
- // existing token if present (operator may have stalled mid-setup).
484
- if (await userStore.isEmpty() && !setupState.hasActiveToken) {
485
- const rec = setupState.mint();
486
- log('auth_first_run_setup_token', {
487
- url: `http://127.0.0.1:<port>/setup?token=${rec.token}`,
488
- note: 'Visit this URL in a browser to create the admin account. Replace <port> with the bound API port.',
489
- });
481
+ // First-run: try the non-interactive env-var bootstrap first (Docker /
482
+ // CI / headless deploys LLMUX_INIT_USERNAME/NAME/PASSPHRASE, see
483
+ // bootstrapFromEnv's docstring). Falls through to minting a browser
484
+ // setup token when no env vars are set, same as before. A PARTIAL env
485
+ // var set is almost certainly an operator typo, not something to fail
486
+ // silently on — logged loudly, but still falls through to the browser
487
+ // path rather than crashing the boot over one bad var, same
488
+ // skip-and-continue philosophy as the skip-bad-provider handling in
489
+ // models.ts.
490
+ if (await userStore.isEmpty()) {
491
+ let bootstrapped: Awaited<ReturnType<typeof bootstrapFromEnv>>;
492
+ try {
493
+ bootstrapped = await bootstrapFromEnv(userStore, tokenStore);
494
+ } catch (err) {
495
+ log('auth_bootstrap_from_env_failed', { error: (err as Error).message });
496
+ bootstrapped = undefined;
497
+ }
498
+ if (bootstrapped) {
499
+ log('auth_bootstrap_from_env', { username: bootstrapped.token.username });
500
+ } else if (!setupState.hasActiveToken) {
501
+ const rec = setupState.mint();
502
+ log('auth_first_run_setup_token', {
503
+ url: `http://127.0.0.1:<port>/setup?token=${rec.token}`,
504
+ note: 'Visit this URL in a browser to create the admin account. Replace <port> with the bound API port.',
505
+ });
506
+ }
490
507
  }
491
508
  apiServer = startApi(
492
509
  {