@nanobpm/nano-workforce 0.172.0 → 0.172.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.172.1](https://github.com/nanobpm/nano-workforce/compare/v0.172.0...v0.172.1) (2026-09-01)
2
+
3
+ ### Bug Fixes
4
+
5
+ * **onboarding:** send full ProjectConfig on env write (install.sh Phase 2 HTTP 422) ([#693](https://github.com/nanobpm/nano-workforce/issues/693)) ([cea5a13](https://github.com/nanobpm/nano-workforce/commit/cea5a133fe2e53299432e8f61b81c8eadbf9f1ed)), closes [nanobpm/nano-workforce#692](https://github.com/nanobpm/nano-workforce/issues/692) [#692](https://github.com/nanobpm/nano-workforce/issues/692)
6
+
1
7
  ## [0.172.0](https://github.com/nanobpm/nano-workforce/compare/v0.171.11...v0.172.0) (2026-09-01)
2
8
 
3
9
  ### Features
package/install.sh CHANGED
@@ -1124,6 +1124,25 @@ build_config_body() { # $1 = redact? ("redact" to mask the token)
1124
1124
  "$_gh" "$(json_str "$CONSOLE_ORIGIN")" "$(json_str "$APPVIEW_BASE")" "$(json_str "${PR_REVIEW_PORT:-3000}")"
1125
1125
  }
1126
1126
 
1127
+ # Merge our env object into the project's FULL ProjectConfig and print the
1128
+ # merged object. `PUT /console/api/projects/<name>/config` is a whole-object
1129
+ # replace: it deserializes the body into the complete ProjectConfig (which
1130
+ # requires `name`, `main`, `platforms`, `lang`, …), so a partial {"env":{…}}
1131
+ # body fails with HTTP 422 "missing field name" (nanobpm/nano-workforce#692).
1132
+ # We therefore fetch the live config and set its `.env` instead of hand-building
1133
+ # a minimal body. Values are passed via the environment (not argv) so quoting is
1134
+ # never an issue; node is a hard preflight requirement so it is always present.
1135
+ # Prints the merged JSON on success; returns non-zero (empty stdout) if either
1136
+ # input is not parseable.
1137
+ merge_config_env() { # $1 = current ProjectConfig JSON, $2 = {"env":{…}} JSON
1138
+ NWF_CFG_JSON=$1 NWF_ENV_JSON=$2 node -e '
1139
+ const cfg = JSON.parse(process.env.NWF_CFG_JSON);
1140
+ const env = JSON.parse(process.env.NWF_ENV_JSON).env || {};
1141
+ cfg.env = env;
1142
+ process.stdout.write(JSON.stringify(cfg));
1143
+ ' 2>/dev/null
1144
+ }
1145
+
1127
1146
  # Step 9 — the console must be reachable before we mutate anything.
1128
1147
  app_preflight() {
1129
1148
  info "Preflighting the console at ${CONSOLE_ORIGIN}/console"
@@ -1245,18 +1264,39 @@ app_provision() {
1245
1264
  esac
1246
1265
  fi
1247
1266
 
1248
- # 11.5 — write ProjectConfig.env (token redacted in dry-run output).
1267
+ # 11.5 — write ProjectConfig.env (token redacted in dry-run output). The
1268
+ # config endpoint is a whole-object replace, so we GET the current config and
1269
+ # merge our env into it; a partial {"env":{…}} body 422s (#692).
1249
1270
  info "Configuring project '$PROJECT' (ProjectConfig.env)"
1250
- _cfg_body=$(build_config_body) || {
1271
+ _env_body=$(build_config_body) || {
1251
1272
  record_failure "app: invalid ProjectConfig.env value (control characters)"
1252
1273
  return 1
1253
1274
  }
1254
- _cfg_show=$(build_config_body redact) || {
1275
+ _env_show=$(build_config_body redact) || {
1255
1276
  record_failure "app: invalid ProjectConfig.env value (control characters)"
1256
1277
  return 1
1257
1278
  }
1258
- api PUT "/console/api/projects/${PROJECT}/config" "$_cfg_body" "$_cfg_show"
1259
- if [ "$DRY_RUN" -eq 0 ]; then
1279
+ if [ "$DRY_RUN" -eq 1 ]; then
1280
+ # No live config to fetch under --dry-run: show the env we would merge in.
1281
+ api PUT "/console/api/projects/${PROJECT}/config" "$_env_body" "$_env_show"
1282
+ else
1283
+ api GET "/console/api/projects/${PROJECT}/config"
1284
+ case "$API_STATUS" in
1285
+ 2*) : ;;
1286
+ *) err "GET project config -> $(api_outcome)"
1287
+ [ -n "$API_BODY" ] && note "$API_BODY"
1288
+ record_failure "app: GET config $(api_outcome)"
1289
+ return 1 ;;
1290
+ esac
1291
+ _cur_cfg=$API_BODY
1292
+ _cfg_body=$(merge_config_env "$_cur_cfg" "$_env_body") || {
1293
+ err "could not merge env into the current ProjectConfig (unparseable config?)."
1294
+ [ -n "$_cur_cfg" ] && note "$_cur_cfg"
1295
+ record_failure "app: merge ProjectConfig.env"
1296
+ return 1
1297
+ }
1298
+ _cfg_show=$(merge_config_env "$_cur_cfg" "$_env_show") || _cfg_show=$_cfg_body
1299
+ api PUT "/console/api/projects/${PROJECT}/config" "$_cfg_body" "$_cfg_show"
1260
1300
  case "$API_STATUS" in
1261
1301
  2*) ok "config written (NANO_WORKFORCE_BASE_URL=${APPVIEW_BASE})" ;;
1262
1302
  *) err "PUT project config -> $(api_outcome)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.172.0",
3
+ "version": "0.172.1",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",
@@ -302,6 +302,13 @@ const srv = http.createServer((req, res) => {
302
302
  if (m === 'POST' && url === '/console/api/extensions/install') return json(201, { id: 'nano-workforce' });
303
303
  if (m === 'POST' && url === '/console/api/projects') return mode === 'exists' ? json(409, { error: 'exists' }) : json(201, { name: 'Workforce' });
304
304
  if (m === 'PUT' && url === '/console/api/projects/Workforce/config') return json(200, { ok: true });
305
+ if (m === 'GET' && url === '/console/api/projects/Workforce/config') {
306
+ // The whole-object ProjectConfig install.sh fetches before merging `.env`
307
+ // and PUTting it back (nanobpm/nano-workforce#692). Must carry the required
308
+ // top-level fields (name, main, platforms, lang) so merge_config_env has a
309
+ // full object to set `.env` on.
310
+ return json(200, { name: 'Workforce', main: 'nano-workforce', platforms: ['console'], lang: 'ts', env: {} });
311
+ }
305
312
  if (m === 'POST' && url === '/console/api/projects/Workforce/run') { ran = true; return json(200, { state: 'running' }); }
306
313
  if (m === 'GET' && url === '/console/app-view/Workforce/app/api/version') {
307
314
  if (mode === 'timeout') return json(404, {});