@whoz-oss/coday-web 0.0.0-workstream-forge.144 → 0.0.0-workstream-forge.145

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 (4) hide show
  1. package/README.md +204 -115
  2. package/index.js +85 -38
  3. package/launcher.js +78 -0
  4. package/package.json +6 -4
package/README.md CHANGED
@@ -1,157 +1,246 @@
1
1
  # Coday Web Package
2
2
 
3
- This package provides the web interface launcher for Coday, bundling both the client (Angular app) and server components into a single executable package.
3
+ `@whoz-oss/coday-web` is the launcher of the Coday web interface: it serves the Angular client, the Factory cockpit and
4
+ the Express server, and runs AgentOS and the Factory next to them.
4
5
 
5
- ## Architecture
6
+ ## First run
6
7
 
7
- The web package acts as a thin orchestration layer:
8
-
9
- ```
10
- ┌─────────────────────────────────────────┐
11
- │ coday-web (index.js) │
12
- │ ┌───────────────────────────────────┐ │
13
- │ │ 1. Resolve client package path │ │
14
- │ │ 2. Set CODAY_CLIENT_PATH env var │ │
15
- │ │ 3. Import and run server │ │
16
- │ └───────────────────────────────────┘ │
17
- └─────────────────────────────────────────┘
18
- │
19
- ┌───────────┴───────────┐
20
- ▼ ▼
21
- ┌──────────────┐ ┌──────────────┐
22
- │ coday-server │ │ coday-client │
23
- │ (Express) │───────▶│ (Angular) │
24
- └──────────────┘ └──────────────┘
8
+ ```bash
9
+ npx @whoz-oss/coday-web
25
10
  ```
26
11
 
27
- ## Usage Modes
12
+ In a terminal (Nx mode, see below) the browser opens by itself, always on **`/welcome`**
13
+ (`http://localhost:3000/welcome`), as soon as the Express server listens and whatever the install: that page only talks
14
+ to Coday's own server, so it does not wait for AgentOS. On a **first run** it is the wizard. Otherwise (setup done, or an
15
+ install without a wizard: `--auth`, an external AgentOS, an existing install without a wizard identity) it is a plain
16
+ loading page (download, Java, AgentOS, Factory: nothing that reads as a setup) that follows the startup and leads into
17
+ the app by itself as soon as AgentOS is up. With an external `AGENTOS_URL` / `FACTORY_URL` the page has nothing to
18
+ download or start for that service and only waits for it to answer. Pass `--no-open` or set `CODAY_NO_OPEN=1` to keep
19
+ the browser closed (it is also never opened with `--auth`, a non-loopback host or `CI`). Without a terminal
20
+ (`--managed`, desktop apps) nothing is opened: open the URL printed as `Server is running on http://localhost:PORT`
21
+ yourself. The wizard is a four-step flow:
22
+
23
+ 1. **Your email.** It becomes your user ID and the AgentOS administrator. AgentOS and Factory JARs start downloading in
24
+ the background as soon as the page is open.
25
+ 2. **Providers.** Anthropic, OpenAI and/or Requesty, each with an API key. With several, drag the cards (or use the
26
+ arrows) to rank them: rank 1 is preferred. At least one is required.
27
+ 3. **Files folder.** Pick the folder your agent reads and writes (default `~/Coday`, created when missing).
28
+ 4. **Checklist.** Download %, Java, AgentOS, providers, models, your personal namespace, the Coday agent, then
29
+ **Start with Coday**.
30
+
31
+ **Java 25 or newer is required** (AgentOS and Factory run on the JVM). When it is missing the wizard says so and shows the
32
+ install command for your system, then continues by itself.
33
+
34
+ Once done, `<configDir>/web-setup.json` holds `{ identity, setupDone }` (never an API key: the keys go to AgentOS only).
35
+ To run the wizard again on a real install, stop Coday and delete `web-setup.json` **and** `<configDir>/agentos/data`
36
+ (AgentOS fixes its administrator at its first boot). For the local stack of the monorepo, use `web:local -- --fresh`
37
+ instead (see below).
38
+
39
+ The command is always the same, `npx @whoz-oss/coday-web`, and it always opens `/welcome`: the wizard while the setup is
40
+ not done, the loading page and then the app afterwards. The page appears once the launcher has generated the Nx
41
+ workspace, run `provision` and started the `server` task, which takes a few seconds (the Nx startup is most of it); it
42
+ does not wait for the downloads, Java or the JVMs.
43
+
44
+ ### AgentOS that already has data
45
+
46
+ The wizard's email is made the AgentOS administrator only when AgentOS boots on an **empty** database. Pointed at a
47
+ database that already holds users, that email is a plain user: it still gets its personal namespace (AgentOS creates it on
48
+ its first request), but only an administrator can create the platform providers and set the files folder, so the apply stops
49
+ on AgentOS's refusal with a message saying so. Use the administrator's email, or an empty `<configDir>/agentos/data`.
50
+
51
+ ### Model prices
52
+
53
+ The four models of each provider are created with their price (USD per million tokens: input, output, cache read, and
54
+ cache write for Anthropic), so AgentOS can estimate costs. Re-running the setup adds the prices to models created
55
+ before. They come from the providers' price lists and live in `apps/server/src/lib/setup/model-catalogue.ts`; Claude
56
+ Haiku 5.5 is priced at its base tier (prompts up to 100k tokens).
57
+
58
+ ## How it runs
28
59
 
29
- ### Production Mode (Published Package)
30
-
31
- Use the published npm package via npx:
60
+ ```
61
+ interactive terminal no TTY / --managed / CODAY_NO_NX=1
62
+ ──────────────────── ───────────────────────────────────
63
+ coday-web (index.js) coday-web (index.js)
64
+ └─ writes <configDir>/runtime/{nx,project}.json
65
+ └─ nx run coday:status └─ one process: Express + AgentOS + Factory
66
+ provision ─┬─ status (entry task) (what the desktop apps use; prints
67
+ │ ├─ server (pinned next `Server is running on http://localhost:PORT`)
68
+ │ │ to status,
69
+ │ │ opens the browser)
70
+ │ ├─ agentos (own pane)
71
+ │ └─ factory (own pane)
72
+ ```
32
73
 
33
- ```bash
34
- # Using the published package
35
- pnpm web
74
+ - **Nx mode** (default in a terminal). The launcher generates a tiny Nx workspace under `<configDir>/runtime/`
75
+ (no daemon, no cloud, no cache) and runs the bundled `nx`. `provision` is a quick task (profile, secrets, Java check,
76
+ ports → `runtime/state.json`); `status`, `server`, `agentos` and `factory` are continuous tasks, each with its own
77
+ pane. The launcher runs ONE target, `nx run coday:status`, and `status` depends on the three services, so Nx starts
78
+ them for it. `agentos` prints *Waiting for first-run setup → http://localhost:3000/welcome* until you gave your email;
79
+ `factory` waits for AgentOS to be healthy. As soon as Express listens, the `server` task opens the browser on
80
+ `/welcome` (see *First run*); it never does when `--auth`, a non-loopback `--host`, `CI`, `--no-open` or
81
+ `CODAY_NO_OPEN` say so. Nothing waits for AgentOS before opening: the page shows the progress itself. For an external
82
+ AgentOS (`AGENTOS_URL`) / Factory (`FACTORY_URL`) the setup API probes those URLs, which is what the proxy targets.
83
+ - **The `status` pane.** The Nx TUI has no status bar, so a small dedicated task reads `runtime/state.json` and probes
84
+ the health URLs every second. It prints one line per meaningful change only: `agentos download 42%` (one line per
85
+ 10%), `java ok` or the install hint, `agentos healthy :8224`, `factory healthy :8241`, `agentos external <origin>`
86
+ for an `AGENTOS_URL`/`FACTORY_URL`, and `Open -> http://localhost:3000/welcome` (the same line whatever the profile and
87
+ the setup state, same URL as the browser). In the
88
+ TUI, select a pane and pin it next to another one to keep the download and the URL on screen while you read the
89
+ logs of the others; press `?` for the key help of the Nx TUI. At startup `status` is pinned next to `server`: Nx
90
+ pins the initiating task and its first continuous dependency, but only for a single-target run (`nx run`), which is
91
+ why the launcher does not use `run-many`. That behaviour was derived from reading the Nx 23 sources (the native
92
+ TUI rendering of pinned panes could not be inspected): confirm it visually.
93
+ Because `status` depends on the services, none of them may exit while it runs (Nx would report an exited
94
+ dependency as crashed, and a failed one would skip `status`): a service that cannot start (no Java, download
95
+ failed, port taken) or that is external (`AGENTOS_URL`/`FACTORY_URL`) prints why and stays open until Ctrl+C.
96
+ - **Managed mode** (no TTY, `--managed`, or `CODAY_NO_NX=1`). Same code, one process, no Nx. The desktop apps spawn
97
+ `coday-web` without a terminal and keep working unchanged.
98
+
99
+ All the logic lives in the server package (`apps/server/src/lib/runtime`, `lib/setup`); the Nx workspace is only a
100
+ manifest calling `coday-server provision|agentos|factory|server|status`.
101
+
102
+ ### Ports
103
+
104
+ The packaged stack prefers its own ports: **AgentOS 8224, Factory 8241, AgentOS embedded Neo4j Bolt 7788** (each falls
105
+ back to the next free port, the choice is written to `runtime/state.json`). The dev ports **8124 (AgentOS), 8141
106
+ (Factory) and 7688 (Bolt) are reserved for dev mode** (`pnpm web:serve:dev`, `bootRun`), so a packaged instance and a
107
+ dev stack run side by side without colliding or picking up each other's services.
108
+
109
+ ### Logs
110
+
111
+ Each process writes to its own file, in addition to its pane / the console:
36
112
 
37
- # Or directly with npx
38
- npx @whoz-oss/coday-web --no_auth
113
+ ```
114
+ <configDir>/logs/server.log
115
+ <configDir>/logs/agentos.log
116
+ <configDir>/logs/factory.log
39
117
  ```
40
118
 
41
- In production mode:
42
- - The web launcher resolves the client package from node_modules
43
- - Server serves pre-built static files from the client package
44
- - Single process handles both server and client
119
+ `configDir` defaults to `~/.coday` (`--configDir <dir>` to change it).
45
120
 
46
- ### Development Mode (Local Sources)
121
+ ### Security in laptop mode
47
122
 
48
- For development with live reload and local sources:
123
+ Auth mode trusts identity headers, so every listener is bound to loopback: Express `127.0.0.1`, AgentOS
124
+ `--server.address=127.0.0.1`, Factory `FACTORY_BIND_HOST=127.0.0.1`. AgentOS and Factory run with
125
+ `*_SECURITY_MODE=auth`. Secrets (`FACTORY_FAKE_IDP_SECRET`, AgentOS and Factory encryption key/salt) are generated once into
126
+ `<configDir>/runtime/secrets.json` (mode `0600`). An install that already holds unencrypted data keeps `NONE` for that
127
+ service and logs a warning (encrypting existing data is a manual migration).
49
128
 
50
- ```bash
51
- # Start both client and server in development mode
52
- pnpm web:dev
53
- ```
54
-
55
- This command:
56
- - Starts the Angular dev server on port 4200 (with HMR)
57
- - Starts the Express server on port 4100 (with tsx watch)
58
- - Server proxies non-API requests to Angular dev server
59
- - Changes to client or server code trigger automatic reloads
129
+ The first-run setup API (`/api/setup/*`: folder browser, apply) only answers loopback callers and is disabled once the
130
+ setup is done. Deployments (`--auth`), an external AgentOS (`AGENTOS_URL`), an imposed `AGENTOS_EXTERNAL_USERID` and
131
+ existing installs without a wizard identity keep their previous behaviour: no wizard, no redirect.
60
132
 
61
- **How it works in dev mode:**
62
- 1. Client runs with Angular CLI dev server (localhost:4200)
63
- 2. Server runs with tsx watch (localhost:4100)
64
- 3. Server detects `BUILD_ENV=development` and proxies to Angular
65
- 4. API routes (e.g., `/api/*`) are handled by the server
66
- 5. All other routes are proxied to Angular for client-side routing
133
+ ## Environment variables and options
67
134
 
68
- ## Development Workflow
135
+ | Name | Effect |
136
+ |---|---|
137
+ | `--configDir <dir>` | Config directory (default `~/.coday`) |
138
+ | `--host <addr>` / `CODAY_HOST` | Interface Express listens on (default `127.0.0.1`; `0.0.0.0` with `--auth`) |
139
+ | `--managed` / `CODAY_NO_NX=1` | Force the single-process mode (no Nx) |
140
+ | `--no-open` / `CODAY_NO_OPEN=1` | Do not open the browser on start (only Nx mode opens it; never with `--auth`, a non-loopback host or `CI`) |
141
+ | `PORT` | Express port (strict when set; default 3000, 4100 in dev) |
142
+ | `AGENTOS_URL`, `FACTORY_URL` | Use an external AgentOS / Factory instead of managed ones |
143
+ | `AGENTOS_EXTERNAL_USERID` | Impose the identity forwarded to AgentOS (disables the wizard) |
144
+ | `CODAY_AGENTOS_VERSION`, `CODAY_FACTORY_VERSION` | JAR version to run (`dev` = JARs placed by hand in `<configDir>/{agentos,factory}`) |
145
+ | `CODAY_DEFAULT_FILES_DIR` | Folder proposed by the wizard instead of `~/Coday` |
146
+ | `CODAY_CLIENT_PATH`, `CODAY_FACTORY_COCKPIT_PATH` | Set by the launcher: where the static apps are |
147
+ | `BUILD_ENV=development` | Dev mode (proxy to the Angular dev servers) |
69
148
 
70
- ### Running Individual Services
149
+ ## Running the local code like an npx user: `web:local`
71
150
 
72
- You can also run services separately for debugging:
151
+ End users always run `npx @whoz-oss/coday-web`. In the monorepo the equivalent, one command whatever your setup state,
152
+ is:
73
153
 
74
154
  ```bash
75
- # Run only the client (Angular dev server)
76
- pnpm client
77
-
78
- # Run only the server (Express with tsx watch)
79
- pnpm server
155
+ pnpm nx run web:local # everyday: build local code, run it like an npx user, keeps your setup
156
+ pnpm nx run web:local -- --fresh # test the first-run wizard again (deletes the local config first)
157
+ pnpm nx run web:local -- --managed # single process, plain console (instead of the Nx TUI)
158
+ pnpm nx run web:local -- --no-open # do not open the browser (every restart would otherwise open a tab)
159
+ pnpm nx run web:local -- --port 3100 # pick the port
80
160
  ```
81
161
 
82
- ### Building for Production
83
-
84
- The web package depends on built client and server packages:
162
+ The first time you get the wizard; afterwards the loading page and then the app, on the instance you configured, so you can stop,
163
+ rebuild and restart as often as you like. The target builds the client, factory cockpit, server and web packages plus
164
+ the AgentOS and Factory boot JARs, then `scripts/web-local.ts` works in a **persistent root, `~/.coday-local`**:
85
165
 
86
- ```bash
87
- # Build all packages
88
- pnpm nx run-many --target=build --projects=client,server,web
89
-
90
- # Or build everything
91
- pnpm nx run-many --target=build --all
166
+ ```
167
+ ~/.coday-local/
168
+ packs/ pnpm pack tarballs (emptied on every run)
169
+ install/ the tarballs installed with npm (recreated on every run, what npx does minus the registry)
170
+ config/ the --configDir (KEPT: web-setup.json, agentos/data, factory data, secrets)
171
+ files/Coday folder proposed by the wizard instead of ~/Coday
92
172
  ```
93
173
 
94
- ### Testing Changes
95
-
96
- When making changes to the web launcher:
174
+ Every run re-packs and re-installs (the code may have changed), overwrites the `dev`-layout JARs in
175
+ `config/{agentos,factory}` (`agentos-service-dev.jar`, plugins in `plugins/`; the data directories are left alone) and
176
+ runs the installed `coday-web --configDir ~/.coday-local/config` with `CODAY_AGENTOS_VERSION=dev
177
+ CODAY_FACTORY_VERSION=dev`. It prints every path and whether this is a **first run** (no `setupDone` in
178
+ `web-setup.json`) or a **resume**. Your `~/.coday` and `~/Coday` are never touched (the script refuses a root that is, or
179
+ lies in, them, your home or the repository), and nothing is published.
97
180
 
98
- 1. Modify `apps/web/index.js`
99
- 2. Test with local server: `node apps/web/index.js --no_auth`
100
- 3. Verify client resolution works correctly
101
- 4. Check that server starts and serves the client
181
+ | Option / env | Effect |
182
+ |---|---|
183
+ | `--fresh` | Delete `config/` and `files/` (printed) before starting: a brand-new first run |
184
+ | `--managed`, `--port <n>` | Single-process mode, Express port |
185
+ | `--no-open` | Do not open the browser (also `CODAY_NO_OPEN=1`) |
186
+ | `--prepare-only` | Prepare everything, print the paths as JSON on the last line, no server |
187
+ | `--clean` | Delete the **whole** root when the server stops (setup and data included) |
188
+ | `CODAY_LOCAL_DIR=<dir>` | Use another root than `~/.coday-local` (`CODAY_FIRST_RUN_DIR` is a deprecated alias) |
102
189
 
103
- ## Environment Variables
190
+ `web:first-run` is kept as an alias of `web:local -- --fresh`.
104
191
 
105
- - `CODAY_CLIENT_PATH`: Set by the web launcher to tell server where client files are
106
- - `BUILD_ENV`: Set to `development` by server's serve target for dev mode
107
- - `PORT`: Override default server port (default: 3000 production, 4100 dev)
192
+ Automated version: `pnpm nx run client-e2e:first-run-e2e` drives the wizard with Playwright against a real AgentOS
193
+ (dummy keys, no LLM call) and checks the providers, models, personal namespace, Coday agent and shared folder through
194
+ the AgentOS REST API. It runs `web:local --fresh` on its own throwaway root (`FIRST_RUN_E2E_DIR` to choose it, it never
195
+ reads `CODAY_LOCAL_DIR`) and skips itself, with a reason, when Java 25 or the built JARs are missing.
108
196
 
109
- ## Package Dependencies
197
+ ## Development (monorepo)
110
198
 
111
- ```json
112
- {
113
- "@whoz-oss/coday-client": "workspace:*",
114
- "@whoz-oss/coday-server": "workspace:*"
115
- }
199
+ ```bash
200
+ pnpm web:serve:dev # nx run web:serve:dev: client, factory-cockpit, server, AgentOS and Factory, one pane each
201
+ pnpm web:dev # lighter: client + server only (no AgentOS/Factory; set AGENTOS_URL to use your own)
202
+ pnpm client # Angular dev server only (4200)
203
+ pnpm server # Express with tsx watch only (4100)
116
204
  ```
117
205
 
118
- These use workspace protocol in development and resolve to specific versions when published.
206
+ `web:serve:dev` is a set of continuous Nx tasks: `client:serve` (4200), `factory-cockpit:serve` (4300),
207
+ `web:dev-server` (Express, 4100), `web:dev-agentos` (`agentos-service:bootRun`, 8124) and `web:dev-factory`
208
+ (`factory-service:bootRun`, 8141). These are the dev-only ports; the packaged stack uses 8224 / 8241 (see *Ports*). The dev server uses the
209
+ external-service mode (`AGENTOS_URL`/`FACTORY_URL`), so the wizard is not shown: use `web:local -- --fresh` to test it.
119
210
 
120
- ## Troubleshooting
121
-
122
- ### "Could not resolve @whoz-oss/coday-client package"
123
-
124
- This means the client package isn't built or installed:
211
+ ### Building and testing
125
212
 
126
213
  ```bash
127
- # In development
128
- pnpm install
129
- pnpm nx run client:build
130
-
131
- # Or use the web:dev command which doesn't require builds
132
- pnpm web:dev
214
+ pnpm nx run-many -t build -p client,factory-cockpit,server,web
215
+ pnpm nx run-many -t lint test -p server,web,client,agentos-ui,scripts
133
216
  ```
134
217
 
135
- ### "Failed to start server"
218
+ ## Package dependencies
136
219
 
137
- Check that all dependencies are installed:
138
-
139
- ```bash
140
- pnpm install
220
+ ```json
221
+ {
222
+ "@whoz-oss/coday-client": "workspace:*",
223
+ "@whoz-oss/coday-factory-cockpit": "workspace:*",
224
+ "@whoz-oss/coday-server": "workspace:*",
225
+ "nx": "catalog:dev"
226
+ }
141
227
  ```
142
228
 
143
- ### Development mode not proxying correctly
229
+ `nx` is a runtime dependency here (it is the process manager of the interactive mode), which makes the package larger
230
+ than the former thin launcher. Versions of the `platform:npm` packages move in lockstep: never edit them by hand.
144
231
 
145
- Ensure both services are running:
146
- 1. Angular dev server should be on port 4200
147
- 2. Express server should be on port 4100
148
- 3. Access the app via http://localhost:4100
149
-
150
- ## Quick Reference
232
+ ## Troubleshooting
151
233
 
152
- | Command | Mode | Ports | Use Case |
153
- |---------|------|-------|----------|
154
- | `pnpm web` | Production | 3000 | Testing published package |
155
- | `pnpm web:dev` | Development | 4100→4200 | Active development |
156
- | `pnpm client` | Development | 4200 | Client-only work |
157
- | `pnpm server` | Development | 4100 | Server-only work |
234
+ - **"Could not resolve @whoz-oss/coday-client package"**: the client is not built or installed. `pnpm install` and
235
+ `pnpm nx run client:build`, or use `pnpm web:serve:dev`.
236
+ - **The Nx panes do not show / garbled output**: use `--managed` (or `CODAY_NO_NX=1`) for plain console output.
237
+ - **"Waiting for first-run setup" never ends**: open the URL printed in the pane (or the `Open ->` line of the `status`
238
+ pane) and answer the wizard.
239
+ - **The browser did not open**: headless Linux or no `xdg-open`, `--no-open`, `CI`, `--auth` or a non-loopback host; the
240
+ `server` pane logs one line (`Not opening the browser: <why>`) and the `status` pane shows the URL.
241
+ - **"AgentOS refused: ... is not an administrator"** at the end of the wizard: see *AgentOS that already has data*.
242
+ - **The loading page does not leave**: AgentOS is not up yet. Look at the `agentos` pane / log, Java 25 is the usual
243
+ cause. With an external `AGENTOS_URL`, check that URL answers on `/management/health`. (Opening `/` yourself
244
+ meanwhile shows a blank page for up to 90 s, the app waits for AgentOS.)
245
+ - **Java missing or too old**: install Java 25 (the wizard shows the command), the page continues by itself.
246
+ - **Port already in use**: `PORT=3100 npx @whoz-oss/coday-web`.
package/index.js CHANGED
@@ -2,30 +2,30 @@
2
2
  import { fileURLToPath, pathToFileURL } from 'url';
3
3
  import { dirname, resolve } from 'path';
4
4
  import { existsSync } from 'fs';
5
+ import { spawn, spawnSync } from 'child_process';
5
6
  import { createRequire } from 'module';
7
+ import { chooseMode, nxArgs, nxEnv, parseWorkspaceDir, resolveConfigDir, serverArgs } from './launcher.js';
6
8
 
7
9
  const __filename = fileURLToPath(import.meta.url);
8
10
  const __dirname = dirname(__filename);
9
11
 
10
12
  /**
11
13
  * Coday Web Launcher
12
- *
13
- * This script orchestrates the web interface by:
14
- * 1. Resolving the client package location at runtime
15
- * 2. Setting the client path for the server to use
16
- * 3. Delegating execution to the server package
14
+ *
15
+ * 1. Resolves the client, factory cockpit and server packages at runtime.
16
+ * 2. Interactive terminal: writes a generated Nx workspace under <configDir>/runtime/ and runs the
17
+ * bundled `nx` on it, so the server, AgentOS and the Factory each get their own pane and log file.
18
+ * 3. No TTY (desktop apps), --managed or CODAY_NO_NX=1: runs everything inside the server process,
19
+ * exactly like before (it still prints `Server is running on http://localhost:PORT`).
17
20
  */
18
21
 
19
22
  // Create require function for resolving packages
20
23
  const require = createRequire(import.meta.url);
21
24
 
22
25
  /**
23
- * Resolve the client package location
24
- *
25
- * Tries multiple resolution strategies:
26
+ * Resolve a static package location. Tries, in order:
26
27
  * 1. Standard node_modules resolution (production/npx)
27
- * 2. Workspace protocol resolution (development)
28
- * 3. Relative path fallback (monorepo development)
28
+ * 2. Relative path fallback (monorepo development)
29
29
  */
30
30
  function resolveStaticPackagePath(packageName, developmentPath, displayName) {
31
31
  const developmentBrowserPath = resolve(__dirname, developmentPath);
@@ -65,7 +65,27 @@ function resolveStaticPackagePath(packageName, developmentPath, displayName) {
65
65
  }
66
66
  }
67
67
 
68
- // Resolve and expose static application paths to the server.
68
+ function resolveServerMain() {
69
+ try {
70
+ const serverPackagePath = require.resolve('@whoz-oss/coday-server/package.json');
71
+ const packagedServerMainPath = resolve(dirname(serverPackagePath), 'server.js');
72
+ const developmentServerMainPath = resolve(__dirname, '../server/dist/server.js');
73
+ const serverMainPath = existsSync(packagedServerMainPath) ? packagedServerMainPath : developmentServerMainPath;
74
+ if (!existsSync(serverMainPath)) {
75
+ throw new Error(
76
+ `Server entry point is missing. Checked paths: ${packagedServerMainPath}, ${developmentServerMainPath}`
77
+ );
78
+ }
79
+ return serverMainPath;
80
+ } catch (error) {
81
+ console.error('Could not resolve @whoz-oss/coday-server package.');
82
+ console.error('Please ensure dependencies are installed: pnpm install');
83
+ console.error('Error:', error.message);
84
+ process.exit(1);
85
+ }
86
+ }
87
+
88
+ // Resolve and expose static application paths to the server (and, through env inheritance, to every Nx task).
69
89
  const clientPath = resolveStaticPackagePath('@whoz-oss/coday-client', '../client/dist/browser', 'Client');
70
90
  const factoryCockpitPath = resolveStaticPackagePath(
71
91
  '@whoz-oss/coday-factory-cockpit',
@@ -78,34 +98,61 @@ process.env.CODAY_FACTORY_COCKPIT_PATH = factoryCockpitPath;
78
98
  console.log(`Coday Web: Using client files from ${clientPath}`);
79
99
  console.log(`Coday Web: Using factory cockpit files from ${factoryCockpitPath}`);
80
100
 
81
- // Import and run the server
82
- // The server package exports its main module which starts the server
83
- try {
84
- // Try to resolve the server package
85
- const serverPackagePath = require.resolve('@whoz-oss/coday-server/package.json');
86
- const serverDir = dirname(serverPackagePath);
87
- const packagedServerMainPath = resolve(serverDir, 'server.js');
88
- const developmentServerMainPath = resolve(__dirname, '../server/dist/server.js');
89
- const serverMainPath = existsSync(packagedServerMainPath)
90
- ? packagedServerMainPath
91
- : developmentServerMainPath;
92
-
93
- if (!existsSync(serverMainPath)) {
94
- throw new Error(
95
- `Server entry point is missing. Checked paths: ${packagedServerMainPath}, ${developmentServerMainPath}`
96
- );
97
- }
98
-
99
- // Import the server module
101
+ const serverMainPath = resolveServerMain();
102
+ const rawArgs = process.argv.slice(2);
103
+ const { mode, reason } = chooseMode({ argv: rawArgs, env: process.env, isTTY: process.stdout.isTTY });
104
+
105
+ async function runManaged() {
106
+ // The server reads process.argv: hide the launcher-only flags from it.
107
+ process.argv = [process.argv[0], process.argv[1], ...serverArgs(rawArgs)];
100
108
  // Convert Windows absolute path to file:// URL for ESM import
101
- const serverModuleURL = pathToFileURL(serverMainPath).href;
102
- import(serverModuleURL).catch((error) => {
103
- console.error('Failed to start server:', error);
109
+ await import(pathToFileURL(serverMainPath).href);
110
+ }
111
+
112
+ function runNx() {
113
+ const configDir = resolveConfigDir(rawArgs);
114
+
115
+ let nxBin;
116
+ try {
117
+ nxBin = require.resolve('nx/bin/nx.js');
118
+ } catch (error) {
119
+ console.warn(`Nx is not available (${error.message}): falling back to the in-process mode.`);
120
+ return runManaged();
121
+ }
122
+
123
+ // 1. Generate the Nx workspace (the bundled server knows how: single implementation).
124
+ const generated = spawnSync(process.execPath, [serverMainPath, 'workspace', ...serverArgs(rawArgs)], {
125
+ encoding: 'utf8',
126
+ stdio: ['ignore', 'pipe', 'inherit'],
127
+ env: process.env,
128
+ });
129
+ const workspaceDir = parseWorkspaceDir(generated.stdout);
130
+ if (generated.status !== 0 || !workspaceDir || !existsSync(workspaceDir)) {
131
+ console.error('Could not generate the runtime workspace; falling back to the in-process mode.');
132
+ return runManaged();
133
+ }
134
+
135
+ console.log(`Coday Web: runtime workspace ${workspaceDir} (logs in ${resolve(configDir, 'logs')})`);
136
+
137
+ // 2. Run the continuous tasks. Nx draws one pane per process, in the terminal.
138
+ const nx = spawn(process.execPath, [nxBin, ...nxArgs()], {
139
+ cwd: workspaceDir,
140
+ env: nxEnv(process.env, configDir),
141
+ stdio: 'inherit',
142
+ });
143
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
144
+ process.on(signal, () => nx.kill(signal));
145
+ }
146
+ nx.on('error', (error) => {
147
+ console.error('Failed to start nx:', error.message);
104
148
  process.exit(1);
105
149
  });
106
- } catch (error) {
107
- console.error('Could not resolve @whoz-oss/coday-server package.');
108
- console.error('Please ensure dependencies are installed: pnpm install');
109
- console.error('Error:', error.message);
110
- process.exit(1);
150
+ nx.on('exit', (code) => process.exit(code ?? 0));
151
+ return undefined;
111
152
  }
153
+
154
+ console.log(`Coday Web: ${mode} mode (${reason})`);
155
+ (mode === 'nx' ? Promise.resolve().then(runNx) : runManaged()).catch((error) => {
156
+ console.error('Failed to start server:', error);
157
+ process.exit(1);
158
+ });
package/launcher.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Pure helpers of the coday-web launcher (no side effects at import time).
3
+ * Tested with `node --test` (see launcher.test.js, run by the `web:test` Nx target).
4
+ */
5
+ import { homedir } from 'os';
6
+ import { join, resolve } from 'path';
7
+
8
+ /**
9
+ * Decide how to run: `nx` (generated workspace, one pane per process) or `managed` (everything in the
10
+ * server process, which is what the desktop apps need).
11
+ *
12
+ * managed when: `--managed` flag, `CODAY_NO_NX=1`, or stdout is not a TTY (desktop apps spawn us
13
+ * without one, and the Nx TUI needs a terminal anyway).
14
+ */
15
+ export function chooseMode({ argv, env, isTTY }) {
16
+ if (argv.includes('--managed')) return { mode: 'managed', reason: '--managed flag' };
17
+ if (env.CODAY_NO_NX === '1' || env.CODAY_NO_NX === 'true') return { mode: 'managed', reason: 'CODAY_NO_NX is set' };
18
+ if (!isTTY) return { mode: 'managed', reason: 'no TTY (desktop app, CI, pipe)' };
19
+ return { mode: 'nx', reason: 'interactive terminal' };
20
+ }
21
+
22
+ /**
23
+ * `--configDir <dir>` / `--configDir=<dir>` / `--coday_config_dir ...`, default `~/.coday`. Always absolute: Nx and
24
+ * its tasks run from `<configDir>/runtime`, where a relative directory would point somewhere else.
25
+ */
26
+ export function resolveConfigDir(argv, home = homedir()) {
27
+ for (let i = 0; i < argv.length; i++) {
28
+ const arg = argv[i];
29
+ for (const flag of ['--configDir', '--coday_config_dir']) {
30
+ if (arg === flag && argv[i + 1]) return resolve(argv[i + 1]);
31
+ if (arg.startsWith(`${flag}=`)) return resolve(arg.slice(flag.length + 1));
32
+ }
33
+ }
34
+ return join(home, '.coday');
35
+ }
36
+
37
+ /** The arguments the server must see: the launcher's own (`--managed`) are removed. */
38
+ export function serverArgs(argv) {
39
+ return argv.filter((a) => a !== '--managed');
40
+ }
41
+
42
+ /** Marker the server's `workspace` command prints before the directory it generated. */
43
+ export const WORKSPACE_MARKER = 'CODAY_RUNTIME_WORKSPACE=';
44
+
45
+ /** The generated workspace directory, found among any other stdout lines; undefined when absent. */
46
+ export function parseWorkspaceDir(stdout) {
47
+ const line = String(stdout ?? '')
48
+ .split('\n')
49
+ .map((l) => l.trim())
50
+ .reverse()
51
+ .find((l) => l.startsWith(WORKSPACE_MARKER));
52
+ const dir = line?.slice(WORKSPACE_MARKER.length).trim();
53
+ return dir || undefined;
54
+ }
55
+
56
+ /**
57
+ * Arguments of `nx run`: ONE target, `coday:status`, whose continuous dependencies are the server, AgentOS and the
58
+ * Factory (each gets its own TUI pane). A single-target run makes the Nx TUI pin the initiating task (`status`) and
59
+ * its first continuous dependency (`server`) at startup; `run-many` pins nothing. The target names are those of
60
+ * NX_ENTRY_TASK / NX_SERVICES in apps/server/src/lib/runtime/workspace.ts (a server spec checks they match).
61
+ * `--parallel` only caps discrete tasks (`provision`): continuous tasks have their own threads.
62
+ */
63
+ export function nxArgs() {
64
+ return ['run', 'coday:status', '--parallel=5', '--outputStyle=tui'];
65
+ }
66
+
67
+ /** Environment of the Nx process: no daemon, no cloud, no cache. */
68
+ export function nxEnv(env, configDir) {
69
+ return {
70
+ ...env,
71
+ NX_DAEMON: 'false',
72
+ NX_NO_CLOUD: 'true',
73
+ NX_SKIP_NX_CACHE: 'true',
74
+ NX_TUI: 'true',
75
+ NX_WORKSPACE_DATA_DIRECTORY: join(configDir, 'runtime', '.nx'),
76
+ NX_CACHE_DIRECTORY: join(configDir, 'runtime', '.nx', 'cache'),
77
+ };
78
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whoz-oss/coday-web",
3
- "version": "0.0.0-workstream-forge.144",
3
+ "version": "0.0.0-workstream-forge.145",
4
4
  "repository": "https://github.com/whoz-oss/coday",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,12 +8,14 @@
8
8
  },
9
9
  "files": [
10
10
  "index.js",
11
+ "launcher.js",
11
12
  "README.md"
12
13
  ],
13
14
  "dependencies": {
14
- "@whoz-oss/coday-client": "0.0.0-workstream-forge.144",
15
- "@whoz-oss/coday-factory-cockpit": "0.0.0-workstream-forge.144",
16
- "@whoz-oss/coday-server": "0.0.0-workstream-forge.144"
15
+ "nx": "23.1.1",
16
+ "@whoz-oss/coday-client": "0.0.0-workstream-forge.145",
17
+ "@whoz-oss/coday-factory-cockpit": "0.0.0-workstream-forge.145",
18
+ "@whoz-oss/coday-server": "0.0.0-workstream-forge.145"
17
19
  },
18
20
  "publishConfig": {
19
21
  "access": "public"