@openagents-org/agent-launcher 0.2.164 → 0.2.165
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 +1 -1
- package/src/cli.js +4 -0
- package/src/daemon.js +7 -0
- package/src/index.js +4 -0
- package/src/win-console.js +85 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// Before ./index so the daemon and every `agn` subprocess inherit the same
|
|
4
|
+
// no-stray-console-window default on Windows. See win-console.js.
|
|
5
|
+
require('./win-console').installWindowsHideDefault();
|
|
6
|
+
|
|
3
7
|
const { AgentConnector, Daemon } = require('./index');
|
|
4
8
|
const { hasCredentialMetadata, formatAuthGuidance } = require('./auth-guidance');
|
|
5
9
|
|
package/src/daemon.js
CHANGED
|
@@ -265,6 +265,10 @@ class Daemon {
|
|
|
265
265
|
// Run from home so a created agent's default working dir is sensible
|
|
266
266
|
// (not the ~/.openagents config dir).
|
|
267
267
|
cwd: os.homedir(),
|
|
268
|
+
// The daemon has no console of its own (it is spawned DETACHED), so a
|
|
269
|
+
// child without this gets a fresh console window — the blank black box
|
|
270
|
+
// that used to appear every time _refreshRuntimes() ran.
|
|
271
|
+
windowsHide: true,
|
|
268
272
|
});
|
|
269
273
|
let stdout = '';
|
|
270
274
|
let stderr = '';
|
|
@@ -921,6 +925,9 @@ class Daemon {
|
|
|
921
925
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
922
926
|
env: getEnhancedEnv(opts.env),
|
|
923
927
|
cwd: opts.cwd,
|
|
928
|
+
// Windows: cmd.exe would otherwise open a console window per agent (the
|
|
929
|
+
// daemon has none to inherit) and leave it up for the agent's lifetime.
|
|
930
|
+
windowsHide: true,
|
|
924
931
|
};
|
|
925
932
|
|
|
926
933
|
if (IS_WINDOWS) {
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// Must run before anything captures a child_process reference: on Windows it
|
|
4
|
+
// keeps every spawn from popping a stray console window. See win-console.js.
|
|
5
|
+
require('./win-console').installWindowsHideDefault();
|
|
6
|
+
|
|
3
7
|
const { Config } = require('./config');
|
|
4
8
|
const { EnvManager } = require('./env');
|
|
5
9
|
const { Registry } = require('./registry');
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stop Windows from popping a console window for every child process we spawn.
|
|
5
|
+
*
|
|
6
|
+
* Neither process that runs this code owns a console: the daemon is spawned
|
|
7
|
+
* DETACHED (`agn up --foreground`), and the launcher's Electron main process is
|
|
8
|
+
* a GUI app. On Windows, when a console-less process launches a console
|
|
9
|
+
* executable *without* CREATE_NO_WINDOW, the OS allocates a brand-new console
|
|
10
|
+
* for the child — an empty black cmd/Windows-Terminal window that pops to the
|
|
11
|
+
* foreground and steals focus. With stdio piped nothing is ever drawn in it,
|
|
12
|
+
* so what the user sees is a blank window appearing out of nowhere.
|
|
13
|
+
*
|
|
14
|
+
* That is the "命令框 keeps popping up" report: `_refreshRuntimes()` shells out
|
|
15
|
+
* to `agn runtimes --json` every two minutes, and the probe it runs keeps the
|
|
16
|
+
* window on screen for as long as it takes to check every installed CLI.
|
|
17
|
+
*
|
|
18
|
+
* Node exposes CREATE_NO_WINDOW as the `windowsHide` spawn option and most call
|
|
19
|
+
* sites pass it — but there are ~60 of them across the adapters and a single
|
|
20
|
+
* miss brings the window back. So the default lives here, applied once at the
|
|
21
|
+
* process entry points (src/index.js, src/cli.js) before any module has
|
|
22
|
+
* captured a reference to child_process.
|
|
23
|
+
*
|
|
24
|
+
* Two things this deliberately does NOT do:
|
|
25
|
+
* - override an explicit `windowsHide: false` — the launcher opens a real
|
|
26
|
+
* terminal for CLI sign-in that way, and that window is the point; and
|
|
27
|
+
* - break interactive output: libuv only applies CREATE_NO_WINDOW when no
|
|
28
|
+
* stdio handle is inherited, so `agn` run from a terminal (stdio 'inherit')
|
|
29
|
+
* is unaffected by this and still prints where the user can see it.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const childProcess = require('child_process');
|
|
33
|
+
|
|
34
|
+
const PATCHED = Symbol.for('openagents.windowsHideDefault');
|
|
35
|
+
const WRAPPED = ['spawn', 'spawnSync', 'exec', 'execSync', 'execFile', 'execFileSync'];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Return a copy of `args` whose options object carries `windowsHide: true`.
|
|
39
|
+
*
|
|
40
|
+
* Every child_process signature ends with `[options][, callback]`, so the
|
|
41
|
+
* options object — if there is one — is the last non-function argument. The
|
|
42
|
+
* caller's object is copied rather than mutated: callers reuse option objects
|
|
43
|
+
* and must not see ours leak into their state.
|
|
44
|
+
*/
|
|
45
|
+
function withWindowsHide(args) {
|
|
46
|
+
const out = args.slice();
|
|
47
|
+
const cbIdx = typeof out[out.length - 1] === 'function' ? out.length - 1 : -1;
|
|
48
|
+
const optIdx = cbIdx === -1 ? out.length - 1 : cbIdx - 1;
|
|
49
|
+
const opts = optIdx >= 0 ? out[optIdx] : undefined;
|
|
50
|
+
|
|
51
|
+
if (opts && typeof opts === 'object' && !Array.isArray(opts)) {
|
|
52
|
+
if ('windowsHide' in opts) return args; // explicit wins, either way
|
|
53
|
+
out[optIdx] = { ...opts, windowsHide: true };
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
// No options argument at all — insert one ahead of any callback.
|
|
57
|
+
out.splice(cbIdx === -1 ? out.length : cbIdx, 0, { windowsHide: true });
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Default `windowsHide: true` for this process's child_process calls.
|
|
63
|
+
* No-op off Windows, and idempotent.
|
|
64
|
+
*/
|
|
65
|
+
function installWindowsHideDefault() {
|
|
66
|
+
if (process.platform !== 'win32') return;
|
|
67
|
+
if (childProcess[PATCHED]) return;
|
|
68
|
+
|
|
69
|
+
for (const name of WRAPPED) {
|
|
70
|
+
const original = childProcess[name];
|
|
71
|
+
if (typeof original !== 'function') continue;
|
|
72
|
+
const wrapper = function (...args) {
|
|
73
|
+
return original.apply(this, withWindowsHide(args));
|
|
74
|
+
};
|
|
75
|
+
// Keep util.promisify(exec) and friends working.
|
|
76
|
+
for (const sym of Object.getOwnPropertySymbols(original)) {
|
|
77
|
+
wrapper[sym] = original[sym];
|
|
78
|
+
}
|
|
79
|
+
Object.defineProperty(wrapper, 'name', { value: name });
|
|
80
|
+
childProcess[name] = wrapper;
|
|
81
|
+
}
|
|
82
|
+
childProcess[PATCHED] = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { installWindowsHideDefault, withWindowsHide };
|