onbuzz 5.4.4 → 5.4.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onbuzz",
3
- "version": "5.4.4",
3
+ "version": "5.4.7",
4
4
  "description": "Loxia OnBuzz - Your AI Fleet",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -204,4 +204,4 @@
204
204
  "glob",
205
205
  "rimraf"
206
206
  ]
207
- }
207
+ }
@@ -77,6 +77,18 @@ const SOFT_REQUIRED = [
77
77
  breaks: 'Electron in-app auto-update dialog + background download',
78
78
  fixHint: 'npm install --save-optional electron-updater@^6.8.3',
79
79
  },
80
+ {
81
+ name: '@nut-tree-fork/nut-js',
82
+ // Used by src/tools/desktop/osController.js (lazy dynamic import).
83
+ // ~30MB native module — MUST stay in optionalDependencies so a failed
84
+ // native build (Wayland, minimal containers) degrades to the
85
+ // NATIVE_UNAVAILABLE fallback instead of breaking the whole install.
86
+ // This entry exists because the dep was MISSING from package.json for
87
+ // months (field report: agents told users to `npm install` it by
88
+ // hand) — never let an audit-fix quietly reintroduce that gap.
89
+ breaks: 'DesktopTool (OS-level mouse/keyboard/screen control) — agents instruct users to install it manually',
90
+ fixHint: 'npm install --save-optional @nut-tree-fork/nut-js@^4.2.6',
91
+ },
80
92
  {
81
93
  name: 'jsdom',
82
94
  // Required by widget runtime/acceptance tests (84 tests across
@@ -106,8 +118,15 @@ const SOFT_REQUIRED = [
106
118
  },
107
119
  ];
108
120
 
121
+ // --simulate-missing=<name,name>: treat the named deps as missing even when
122
+ // they resolve. Dry-run tool — lets an operator (or a test) verify the banner
123
+ // and the emitted restore command without actually uninstalling anything.
124
+ const simArg = process.argv.find((a) => a.startsWith('--simulate-missing='));
125
+ const simulated = new Set(simArg ? simArg.split('=')[1].split(',').filter(Boolean) : []);
126
+
109
127
  const missing = [];
110
128
  for (const dep of SOFT_REQUIRED) {
129
+ if (simulated.has(dep.name)) { missing.push(dep); continue; }
111
130
  try {
112
131
  require.resolve(dep.name, { paths: [repoRoot] });
113
132
  } catch {
@@ -120,14 +139,29 @@ if (missing.length === 0) process.exit(0);
120
139
  // --emit-install: print a single composite `npm install ...` command to
121
140
  // stdout (separate from the stderr banner). release.bat captures stdout
122
141
  // for the [r]estore path. Newline-terminated, no extra logging on stdout.
142
+ //
143
+ // Deps are GROUPED by the save flag in their fixHint: restoring an
144
+ // optionalDependency (electron-updater, nut-js) with a flat `--save` would
145
+ // silently relocate it into hard `dependencies` — turning "native build may
146
+ // fail, that's fine" into "native build failure breaks the whole install".
147
+ // Groups are chained with ` && ` (cmd.exe and sh both honor it).
123
148
  if (process.argv.includes('--emit-install')) {
124
- const args = missing.map((m) => {
149
+ const groups = { '--save': [], '--save-optional': [], '--save-dev': [] };
150
+ for (const m of missing) {
125
151
  // Pull the version pin out of the fixHint ("npm install pkg@^x.y.z # …").
126
152
  // Falls back to no-pin if the hint doesn't follow the convention.
127
153
  const match = m.fixHint.match(/(@?[\w/.-]+@[\^~]?[\w.-]+)/);
128
- return match ? match[1] : m.name;
129
- }).join(' ');
130
- process.stdout.write(`npm install --save ${args}\n`);
154
+ const spec = match ? match[1] : m.name;
155
+ const flag = m.fixHint.includes('--save-optional') ? '--save-optional'
156
+ : m.fixHint.includes('--save-dev') ? '--save-dev'
157
+ : '--save';
158
+ groups[flag].push(spec);
159
+ }
160
+ const cmd = Object.entries(groups)
161
+ .filter(([, specs]) => specs.length > 0)
162
+ .map(([flag, specs]) => `npm install ${flag} ${specs.join(' ')}`)
163
+ .join(' && ');
164
+ process.stdout.write(`${cmd}\n`);
131
165
  // Banner still went to stderr above.
132
166
  process.exit(1);
133
167
  }