@agentsoc/beacon 0.0.7 → 0.0.9
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/README.md +4 -0
- package/dist/cli.js +103 -242
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -4
- package/dist/service-install.d.ts.map +1 -1
- package/dist/service-install.js +63 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -102,6 +102,10 @@ On macOS the plist is written under `/Library/LaunchDaemons/`, and on Linux the
|
|
|
102
102
|
|
|
103
103
|
**`sudo beacon` says “command not found”:** sudo resets `PATH`, so it often cannot see npm/nvm global bins. Use `sudo "$(command -v beacon)" install` (as above), or `sudo env "PATH=$PATH" beacon install`, or the full path from `which beacon`.
|
|
104
104
|
|
|
105
|
+
**`Beacon is not configured` under sudo:** the install command reads **`config.json` from the user who invoked sudo** (`SUDO_USER`, e.g. `/home/ubuntu/.config/...`), not from `/root`, so it matches `beacon config` run as your normal account.
|
|
106
|
+
|
|
107
|
+
**systemd shows `inactive`:** the unit must use the **full path to `node`** (or `bun`). A bare `node` in `ExecStart` fails under systemd when Node is installed via nvm/fnm, because the service does not load your shell `PATH`. Re-run **`sudo "$(command -v beacon)" install`** after upgrading the CLI so the unit is rewritten; then `systemctl status syslog-beacon` or `journalctl -u syslog-beacon -n 20` if it still fails.
|
|
108
|
+
|
|
105
109
|
### Status and stats
|
|
106
110
|
|
|
107
111
|
Show whether the systemd/launchd service is present, resolve **organization name and API key label** via the platform API (`GET /api/v1/siem/beacon/validate/key` using your ingest key), and print forwarding counters from the local stats file:
|
package/dist/cli.js
CHANGED
|
@@ -1,243 +1,104 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.option("-k, --key <key>", "AgentSOC API Key")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
console.log("\n AgentSOC Beacon — Status\n");
|
|
106
|
-
console.log(" Account");
|
|
107
|
-
if (context.ok) {
|
|
108
|
-
line("Organization", context.organizationName ??
|
|
109
|
-
"(name unavailable — check platform API / database)");
|
|
110
|
-
line("API key", context.apiKeyName);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
line("Connection", context.message);
|
|
114
|
-
}
|
|
115
|
-
console.log("\n Service");
|
|
116
|
-
line(`Daemon (${svc.manager})`, svc.installed ? svc.stateLabel : "not installed");
|
|
117
|
-
if (svc.active === true)
|
|
118
|
-
line("Running", "yes");
|
|
119
|
-
else if (svc.active === false)
|
|
120
|
-
line("Running", "no");
|
|
121
|
-
else
|
|
122
|
-
line("Running", "n/a");
|
|
123
|
-
if (svc.detail)
|
|
124
|
-
line("Note", svc.detail);
|
|
125
|
-
console.log("\n Forwarding (this machine)");
|
|
126
|
-
line("Log entries forwarded", String(stats.logsForwarded));
|
|
127
|
-
line("Successful batches", String(stats.batchesSucceeded));
|
|
128
|
-
line("Failed batches", String(stats.batchesFailed));
|
|
129
|
-
if (stats.updatedAt && stats.updatedAt !== new Date(0).toISOString()) {
|
|
130
|
-
line("Last stats update", stats.updatedAt);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
line("Last stats update", "(none yet)");
|
|
134
|
-
}
|
|
135
|
-
if (stats.lastError) {
|
|
136
|
-
line("Last error", stats.lastError);
|
|
137
|
-
}
|
|
138
|
-
console.log();
|
|
139
|
-
});
|
|
140
|
-
program
|
|
141
|
-
.command("update")
|
|
142
|
-
.description("Check for a newer Beacon CLI and optionally install it")
|
|
143
|
-
.option("--json", "Print machine-readable JSON on stdout")
|
|
144
|
-
.option("-y, --yes", "Run npm install -g @agentsoc/beacon@latest (non-interactive upgrade)")
|
|
145
|
-
.action(async (opts) => {
|
|
146
|
-
const current = BEACON_VERSION;
|
|
147
|
-
const fetched = await fetchBeaconUpdateFromNpm();
|
|
148
|
-
if (opts.json) {
|
|
149
|
-
const latest = fetched.ok ? fetched.info.latestVersion : null;
|
|
150
|
-
const outdated = latest != null &&
|
|
151
|
-
latest.length > 0 &&
|
|
152
|
-
semverLessThan(current, latest);
|
|
153
|
-
console.log(JSON.stringify({
|
|
154
|
-
currentVersion: current,
|
|
155
|
-
registry: "https://registry.npmjs.org/@agentsoc%2fbeacon",
|
|
156
|
-
remote: fetched.ok ? fetched.info : null,
|
|
157
|
-
error: fetched.ok ? undefined : fetched.message,
|
|
158
|
-
updateAvailable: fetched.ok ? outdated : null,
|
|
159
|
-
}, null, 2));
|
|
160
|
-
if (!fetched.ok)
|
|
161
|
-
process.exit(1);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (!fetched.ok) {
|
|
165
|
-
console.error(`[beacon] Could not reach npm registry: ${fetched.message}`);
|
|
166
|
-
console.error("[beacon] You can still run: npm install -g @agentsoc/beacon@latest");
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
const { info } = fetched;
|
|
170
|
-
const latest = info.latestVersion;
|
|
171
|
-
console.log("\n AgentSOC Beacon — Update check\n");
|
|
172
|
-
console.log(` This install ${current}`);
|
|
173
|
-
if (latest) {
|
|
174
|
-
console.log(` Latest on registry ${latest}`);
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
console.log(" Latest on registry (unavailable — unexpected npm response)");
|
|
178
|
-
}
|
|
179
|
-
const canCompare = Boolean(latest && latest.length > 0);
|
|
180
|
-
const outdated = canCompare && semverLessThan(current, latest);
|
|
181
|
-
if (canCompare && !outdated) {
|
|
182
|
-
console.log("\n You are on the latest published version.\n");
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (canCompare && outdated) {
|
|
186
|
-
console.log("\n A newer version is available.\n");
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
console.log("\n Compare versions manually, or reinstall with:\n");
|
|
190
|
-
}
|
|
191
|
-
console.log(` ${info.install.npm}`);
|
|
192
|
-
console.log(` ${info.install.bun}`);
|
|
193
|
-
console.log(` ${info.install.pnpm}`);
|
|
194
|
-
if (info.docsUrl) {
|
|
195
|
-
console.log(`\n Docs: ${info.docsUrl}`);
|
|
196
|
-
}
|
|
197
|
-
if (opts.yes) {
|
|
198
|
-
if (!outdated && canCompare) {
|
|
199
|
-
console.log("\n[beacon] Already up to date — skipping install.\n");
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
console.log("\n[beacon] Running npm install -g @agentsoc/beacon@latest …\n");
|
|
203
|
-
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
204
|
-
try {
|
|
205
|
-
execFileSync(npm, ["install", "-g", "@agentsoc/beacon@latest"], { stdio: "inherit", env: process.env });
|
|
206
|
-
console.log("\n[beacon] Update finished. Run `beacon --version` to verify.\n");
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
process.exit(1);
|
|
210
|
-
}
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
console.log("\n To upgrade now, run the same command with --yes\n");
|
|
214
|
-
});
|
|
215
|
-
program
|
|
216
|
-
.command("run")
|
|
217
|
-
.description("Run the forwarder daemon (foreground)")
|
|
218
|
-
.option("--batch-size <n>", "Batch size", "25")
|
|
219
|
-
.option("--flush-ms <n>", "Flush interval in ms", "2000")
|
|
220
|
-
.action(async (options) => {
|
|
221
|
-
const config = await loadConfig();
|
|
222
|
-
const apiKey = resolveBeaconApiKey(config);
|
|
223
|
-
const ingestUrl = resolveIngestUrl(config);
|
|
224
|
-
if (!apiKey) {
|
|
225
|
-
console.error(`[beacon] ${BEACON_CONFIG_REQUIRED_MESSAGE}`);
|
|
226
|
-
process.exit(1);
|
|
227
|
-
}
|
|
228
|
-
console.log("[beacon] Starting in foreground...");
|
|
229
|
-
const beacon = await runBeacon({
|
|
230
|
-
apiKey,
|
|
231
|
-
ingestUrl,
|
|
232
|
-
batchSize: parseInt(options.batchSize, 10),
|
|
233
|
-
flushMs: parseInt(options.flushMs, 10),
|
|
234
|
-
});
|
|
235
|
-
const stop = async () => {
|
|
236
|
-
console.log("\n[beacon] Stopping...");
|
|
237
|
-
await beacon.stop();
|
|
238
|
-
process.exit(0);
|
|
239
|
-
};
|
|
240
|
-
process.on("SIGINT", stop);
|
|
241
|
-
process.on("SIGTERM", stop);
|
|
242
|
-
});
|
|
243
|
-
program.parse(process.argv);
|
|
2
|
+
import{createRequire as $1}from"node:module";var t0=Object.create;var{getPrototypeOf:o0,defineProperty:Y0,getOwnPropertyNames:r0}=Object;var a0=Object.prototype.hasOwnProperty;var e0=($,z,B)=>{B=$!=null?t0(o0($)):{};let Q=z||!$||!$.__esModule?Y0(B,"default",{value:$,enumerable:!0}):B;for(let Y of r0($))if(!a0.call(Q,Y))Y0(Q,Y,{get:()=>$[Y],enumerable:!0});return Q};var j=($,z)=>()=>(z||$((z={exports:{}}).exports,z),z.exports);var S=$1(import.meta.url);var P=j((z1)=>{class v extends Error{constructor($,z,B){super(B);Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=z,this.exitCode=$,this.nestedError=void 0}}class Z0 extends v{constructor($){super(1,"commander.invalidArgument",$);Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}}z1.CommanderError=v;z1.InvalidArgumentError=Z0});var k=j((q1)=>{var{InvalidArgumentError:Y1}=P();class q0{constructor($,z){switch(this.description=z||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,$[0]){case"<":this.required=!0,this._name=$.slice(1,-1);break;case"[":this.required=!1,this._name=$.slice(1,-1);break;default:this.required=!0,this._name=$;break}if(this._name.length>3&&this._name.slice(-3)==="...")this.variadic=!0,this._name=this._name.slice(0,-3)}name(){return this._name}_concatValue($,z){if(z===this.defaultValue||!Array.isArray(z))return[$];return z.concat($)}default($,z){return this.defaultValue=$,this.defaultValueDescription=z,this}argParser($){return this.parseArg=$,this}choices($){return this.argChoices=$.slice(),this.parseArg=(z,B)=>{if(!this.argChoices.includes(z))throw new Y1(`Allowed choices are ${this.argChoices.join(", ")}.`);if(this.variadic)return this._concatValue(z,B);return z},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}}function Z1($){let z=$.name()+($.variadic===!0?"...":"");return $.required?"<"+z+">":"["+z+"]"}q1.Argument=q0;q1.humanReadableArgName=Z1});var h=j((W1)=>{var{humanReadableArgName:G1}=k();class J0{constructor(){this.helpWidth=void 0,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}visibleCommands($){let z=$.commands.filter((B)=>!B._hidden);if($._hasImplicitHelpCommand()){let[,B,Q]=$._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/),Y=$.createCommand(B).helpOption(!1);if(Y.description($._helpCommandDescription),Q)Y.arguments(Q);z.push(Y)}if(this.sortSubcommands)z.sort((B,Q)=>{return B.name().localeCompare(Q.name())});return z}compareOptions($,z){let B=(Q)=>{return Q.short?Q.short.replace(/^-/,""):Q.long.replace(/^--/,"")};return B($).localeCompare(B(z))}visibleOptions($){let z=$.options.filter((Y)=>!Y.hidden),B=$._hasHelpOption&&$._helpShortFlag&&!$._findOption($._helpShortFlag),Q=$._hasHelpOption&&!$._findOption($._helpLongFlag);if(B||Q){let Y;if(!B)Y=$.createOption($._helpLongFlag,$._helpDescription);else if(!Q)Y=$.createOption($._helpShortFlag,$._helpDescription);else Y=$.createOption($._helpFlags,$._helpDescription);z.push(Y)}if(this.sortOptions)z.sort(this.compareOptions);return z}visibleGlobalOptions($){if(!this.showGlobalOptions)return[];let z=[];for(let B=$.parent;B;B=B.parent){let Q=B.options.filter((Y)=>!Y.hidden);z.push(...Q)}if(this.sortOptions)z.sort(this.compareOptions);return z}visibleArguments($){if($._argsDescription)$.registeredArguments.forEach((z)=>{z.description=z.description||$._argsDescription[z.name()]||""});if($.registeredArguments.find((z)=>z.description))return $.registeredArguments;return[]}subcommandTerm($){let z=$.registeredArguments.map((B)=>G1(B)).join(" ");return $._name+($._aliases[0]?"|"+$._aliases[0]:"")+($.options.length?" [options]":"")+(z?" "+z:"")}optionTerm($){return $.flags}argumentTerm($){return $.name()}longestSubcommandTermLength($,z){return z.visibleCommands($).reduce((B,Q)=>{return Math.max(B,z.subcommandTerm(Q).length)},0)}longestOptionTermLength($,z){return z.visibleOptions($).reduce((B,Q)=>{return Math.max(B,z.optionTerm(Q).length)},0)}longestGlobalOptionTermLength($,z){return z.visibleGlobalOptions($).reduce((B,Q)=>{return Math.max(B,z.optionTerm(Q).length)},0)}longestArgumentTermLength($,z){return z.visibleArguments($).reduce((B,Q)=>{return Math.max(B,z.argumentTerm(Q).length)},0)}commandUsage($){let z=$._name;if($._aliases[0])z=z+"|"+$._aliases[0];let B="";for(let Q=$.parent;Q;Q=Q.parent)B=Q.name()+" "+B;return B+z+" "+$.usage()}commandDescription($){return $.description()}subcommandDescription($){return $.summary()||$.description()}optionDescription($){let z=[];if($.argChoices)z.push(`choices: ${$.argChoices.map((B)=>JSON.stringify(B)).join(", ")}`);if($.defaultValue!==void 0){if($.required||$.optional||$.isBoolean()&&typeof $.defaultValue==="boolean")z.push(`default: ${$.defaultValueDescription||JSON.stringify($.defaultValue)}`)}if($.presetArg!==void 0&&$.optional)z.push(`preset: ${JSON.stringify($.presetArg)}`);if($.envVar!==void 0)z.push(`env: ${$.envVar}`);if(z.length>0)return`${$.description} (${z.join(", ")})`;return $.description}argumentDescription($){let z=[];if($.argChoices)z.push(`choices: ${$.argChoices.map((B)=>JSON.stringify(B)).join(", ")}`);if($.defaultValue!==void 0)z.push(`default: ${$.defaultValueDescription||JSON.stringify($.defaultValue)}`);if(z.length>0){let B=`(${z.join(", ")})`;if($.description)return`${$.description} ${B}`;return B}return $.description}formatHelp($,z){let B=z.padWidth($,z),Q=z.helpWidth||80,Y=2,Z=2;function J(K,H){if(H){let x=`${K.padEnd(B+2)}${H}`;return z.wrap(x,Q-2,B+2)}return K}function q(K){return K.join(`
|
|
3
|
+
`).replace(/^/gm," ".repeat(2))}let X=[`Usage: ${z.commandUsage($)}`,""],G=z.commandDescription($);if(G.length>0)X=X.concat([z.wrap(G,Q,0),""]);let W=z.visibleArguments($).map((K)=>{return J(z.argumentTerm(K),z.argumentDescription(K))});if(W.length>0)X=X.concat(["Arguments:",q(W),""]);let U=z.visibleOptions($).map((K)=>{return J(z.optionTerm(K),z.optionDescription(K))});if(U.length>0)X=X.concat(["Options:",q(U),""]);if(this.showGlobalOptions){let K=z.visibleGlobalOptions($).map((H)=>{return J(z.optionTerm(H),z.optionDescription(H))});if(K.length>0)X=X.concat(["Global Options:",q(K),""])}let T=z.visibleCommands($).map((K)=>{return J(z.subcommandTerm(K),z.subcommandDescription(K))});if(T.length>0)X=X.concat(["Commands:",q(T),""]);return X.join(`
|
|
4
|
+
`)}padWidth($,z){return Math.max(z.longestOptionTermLength($,z),z.longestGlobalOptionTermLength($,z),z.longestSubcommandTermLength($,z),z.longestArgumentTermLength($,z))}wrap($,z,B,Q=40){let Z=new RegExp(`[\\n][${" \\f\\t\\v - \uFEFF"}]+`);if($.match(Z))return $;let J=z-B;if(J<Q)return $;let q=$.slice(0,B),X=$.slice(B).replace(`\r
|
|
5
|
+
`,`
|
|
6
|
+
`),G=" ".repeat(B),U=`\\s${""}`,T=new RegExp(`
|
|
7
|
+
|.{1,${J-1}}([${U}]|$)|[^${U}]+?([${U}]|$)`,"g"),K=X.match(T)||[];return q+K.map((H,x)=>{if(H===`
|
|
8
|
+
`)return"";return(x>0?G:"")+H.trimEnd()}).join(`
|
|
9
|
+
`)}}W1.Help=J0});var u=j((L1)=>{var{InvalidArgumentError:K1}=P();class X0{constructor($,z){this.flags=$,this.description=z||"",this.required=$.includes("<"),this.optional=$.includes("["),this.variadic=/\w\.\.\.[>\]]$/.test($),this.mandatory=!1;let B=W0($);if(this.short=B.shortFlag,this.long=B.longFlag,this.negate=!1,this.long)this.negate=this.long.startsWith("--no-");this.defaultValue=void 0,this.defaultValueDescription=void 0,this.presetArg=void 0,this.envVar=void 0,this.parseArg=void 0,this.hidden=!1,this.argChoices=void 0,this.conflictsWith=[],this.implied=void 0}default($,z){return this.defaultValue=$,this.defaultValueDescription=z,this}preset($){return this.presetArg=$,this}conflicts($){return this.conflictsWith=this.conflictsWith.concat($),this}implies($){let z=$;if(typeof $==="string")z={[$]:!0};return this.implied=Object.assign(this.implied||{},z),this}env($){return this.envVar=$,this}argParser($){return this.parseArg=$,this}makeOptionMandatory($=!0){return this.mandatory=!!$,this}hideHelp($=!0){return this.hidden=!!$,this}_concatValue($,z){if(z===this.defaultValue||!Array.isArray(z))return[$];return z.concat($)}choices($){return this.argChoices=$.slice(),this.parseArg=(z,B)=>{if(!this.argChoices.includes(z))throw new K1(`Allowed choices are ${this.argChoices.join(", ")}.`);if(this.variadic)return this._concatValue(z,B);return z},this}name(){if(this.long)return this.long.replace(/^--/,"");return this.short.replace(/^-/,"")}attributeName(){return U1(this.name().replace(/^no-/,""))}is($){return this.short===$||this.long===$}isBoolean(){return!this.required&&!this.optional&&!this.negate}}class G0{constructor($){this.positiveOptions=new Map,this.negativeOptions=new Map,this.dualOptions=new Set,$.forEach((z)=>{if(z.negate)this.negativeOptions.set(z.attributeName(),z);else this.positiveOptions.set(z.attributeName(),z)}),this.negativeOptions.forEach((z,B)=>{if(this.positiveOptions.has(B))this.dualOptions.add(B)})}valueFromOption($,z){let B=z.attributeName();if(!this.dualOptions.has(B))return!0;let Q=this.negativeOptions.get(B).presetArg,Y=Q!==void 0?Q:!1;return z.negate===(Y===$)}}function U1($){return $.split("-").reduce((z,B)=>{return z+B[0].toUpperCase()+B.slice(1)})}function W0($){let z,B,Q=$.split(/[ |,]+/);if(Q.length>1&&!/^[[<]/.test(Q[1]))z=Q.shift();if(B=Q.shift(),!z&&/^-[^-]$/.test(B))z=B,B=void 0;return{shortFlag:z,longFlag:B}}L1.Option=X0;L1.splitOptionFlags=W0;L1.DualOptions=G0});var M0=j((I1)=>{function T1($,z){if(Math.abs($.length-z.length)>3)return Math.max($.length,z.length);let B=[];for(let Q=0;Q<=$.length;Q++)B[Q]=[Q];for(let Q=0;Q<=z.length;Q++)B[0][Q]=Q;for(let Q=1;Q<=z.length;Q++)for(let Y=1;Y<=$.length;Y++){let Z=1;if($[Y-1]===z[Q-1])Z=0;else Z=1;if(B[Y][Q]=Math.min(B[Y-1][Q]+1,B[Y][Q-1]+1,B[Y-1][Q-1]+Z),Y>1&&Q>1&&$[Y-1]===z[Q-2]&&$[Y-2]===z[Q-1])B[Y][Q]=Math.min(B[Y][Q],B[Y-2][Q-2]+1)}return B[$.length][z.length]}function j1($,z){if(!z||z.length===0)return"";z=Array.from(new Set(z));let B=$.startsWith("--");if(B)$=$.slice(2),z=z.map((J)=>J.slice(2));let Q=[],Y=3,Z=0.4;if(z.forEach((J)=>{if(J.length<=1)return;let q=T1($,J),X=Math.max($.length,J.length);if((X-q)/X>Z){if(q<Y)Y=q,Q=[J];else if(q===Y)Q.push(J)}}),Q.sort((J,q)=>J.localeCompare(q)),B)Q=Q.map((J)=>`--${J}`);if(Q.length>1)return`
|
|
10
|
+
(Did you mean one of ${Q.join(", ")}?)`;if(Q.length===1)return`
|
|
11
|
+
(Did you mean ${Q[0]}?)`;return""}I1.suggestSimilar=j1});var H0=j((F1)=>{var N1=S("events").EventEmitter,g=S("child_process"),R=S("path"),c=S("fs"),M=S("process"),{Argument:S1,humanReadableArgName:P1}=k(),{CommanderError:l}=P(),{Help:E1}=h(),{Option:K0,splitOptionFlags:w1,DualOptions:D1}=u(),{suggestSimilar:U0}=M0();class m extends N1{constructor($){super();this.commands=[],this.options=[],this.parent=null,this._allowUnknownOption=!1,this._allowExcessArguments=!0,this.registeredArguments=[],this._args=this.registeredArguments,this.args=[],this.rawArgs=[],this.processedArgs=[],this._scriptPath=null,this._name=$||"",this._optionValues={},this._optionValueSources={},this._storeOptionsAsProperties=!1,this._actionHandler=null,this._executableHandler=!1,this._executableFile=null,this._executableDir=null,this._defaultCommandName=null,this._exitCallback=null,this._aliases=[],this._combineFlagAndOptionalValue=!0,this._description="",this._summary="",this._argsDescription=void 0,this._enablePositionalOptions=!1,this._passThroughOptions=!1,this._lifeCycleHooks={},this._showHelpAfterError=!1,this._showSuggestionAfterError=!0,this._outputConfiguration={writeOut:(z)=>M.stdout.write(z),writeErr:(z)=>M.stderr.write(z),getOutHelpWidth:()=>M.stdout.isTTY?M.stdout.columns:void 0,getErrHelpWidth:()=>M.stderr.isTTY?M.stderr.columns:void 0,outputError:(z,B)=>B(z)},this._hidden=!1,this._hasHelpOption=!0,this._helpFlags="-h, --help",this._helpDescription="display help for command",this._helpShortFlag="-h",this._helpLongFlag="--help",this._addImplicitHelpCommand=void 0,this._helpCommandName="help",this._helpCommandnameAndArgs="help [command]",this._helpCommandDescription="display help for command",this._helpConfiguration={}}copyInheritedSettings($){return this._outputConfiguration=$._outputConfiguration,this._hasHelpOption=$._hasHelpOption,this._helpFlags=$._helpFlags,this._helpDescription=$._helpDescription,this._helpShortFlag=$._helpShortFlag,this._helpLongFlag=$._helpLongFlag,this._helpCommandName=$._helpCommandName,this._helpCommandnameAndArgs=$._helpCommandnameAndArgs,this._helpCommandDescription=$._helpCommandDescription,this._helpConfiguration=$._helpConfiguration,this._exitCallback=$._exitCallback,this._storeOptionsAsProperties=$._storeOptionsAsProperties,this._combineFlagAndOptionalValue=$._combineFlagAndOptionalValue,this._allowExcessArguments=$._allowExcessArguments,this._enablePositionalOptions=$._enablePositionalOptions,this._showHelpAfterError=$._showHelpAfterError,this._showSuggestionAfterError=$._showSuggestionAfterError,this}_getCommandAndAncestors(){let $=[];for(let z=this;z;z=z.parent)$.push(z);return $}command($,z,B){let Q=z,Y=B;if(typeof Q==="object"&&Q!==null)Y=Q,Q=null;Y=Y||{};let[,Z,J]=$.match(/([^ ]+) *(.*)/),q=this.createCommand(Z);if(Q)q.description(Q),q._executableHandler=!0;if(Y.isDefault)this._defaultCommandName=q._name;if(q._hidden=!!(Y.noHelp||Y.hidden),q._executableFile=Y.executableFile||null,J)q.arguments(J);if(this.commands.push(q),q.parent=this,q.copyInheritedSettings(this),Q)return this;return q}createCommand($){return new m($)}createHelp(){return Object.assign(new E1,this.configureHelp())}configureHelp($){if($===void 0)return this._helpConfiguration;return this._helpConfiguration=$,this}configureOutput($){if($===void 0)return this._outputConfiguration;return Object.assign(this._outputConfiguration,$),this}showHelpAfterError($=!0){if(typeof $!=="string")$=!!$;return this._showHelpAfterError=$,this}showSuggestionAfterError($=!0){return this._showSuggestionAfterError=!!$,this}addCommand($,z){if(!$._name)throw Error(`Command passed to .addCommand() must have a name
|
|
12
|
+
- specify the name in Command constructor or using .name()`);if(z=z||{},z.isDefault)this._defaultCommandName=$._name;if(z.noHelp||z.hidden)$._hidden=!0;return this.commands.push($),$.parent=this,this}createArgument($,z){return new S1($,z)}argument($,z,B,Q){let Y=this.createArgument($,z);if(typeof B==="function")Y.default(Q).argParser(B);else Y.default(B);return this.addArgument(Y),this}arguments($){return $.trim().split(/ +/).forEach((z)=>{this.argument(z)}),this}addArgument($){let z=this.registeredArguments.slice(-1)[0];if(z&&z.variadic)throw Error(`only the last argument can be variadic '${z.name()}'`);if($.required&&$.defaultValue!==void 0&&$.parseArg===void 0)throw Error(`a default value for a required argument is never used: '${$.name()}'`);return this.registeredArguments.push($),this}addHelpCommand($,z){if($===!1)this._addImplicitHelpCommand=!1;else{if(this._addImplicitHelpCommand=!0,typeof $==="string")this._helpCommandName=$.split(" ")[0],this._helpCommandnameAndArgs=$;this._helpCommandDescription=z||this._helpCommandDescription}return this}_hasImplicitHelpCommand(){if(this._addImplicitHelpCommand===void 0)return this.commands.length&&!this._actionHandler&&!this._findCommand("help");return this._addImplicitHelpCommand}hook($,z){let B=["preSubcommand","preAction","postAction"];if(!B.includes($))throw Error(`Unexpected value for event passed to hook : '${$}'.
|
|
13
|
+
Expecting one of '${B.join("', '")}'`);if(this._lifeCycleHooks[$])this._lifeCycleHooks[$].push(z);else this._lifeCycleHooks[$]=[z];return this}exitOverride($){if($)this._exitCallback=$;else this._exitCallback=(z)=>{if(z.code!=="commander.executeSubCommandAsync")throw z};return this}_exit($,z,B){if(this._exitCallback)this._exitCallback(new l($,z,B));M.exit($)}action($){let z=(B)=>{let Q=this.registeredArguments.length,Y=B.slice(0,Q);if(this._storeOptionsAsProperties)Y[Q]=this;else Y[Q]=this.opts();return Y.push(this),$.apply(this,Y)};return this._actionHandler=z,this}createOption($,z){return new K0($,z)}_callParseArg($,z,B,Q){try{return $.parseArg(z,B)}catch(Y){if(Y.code==="commander.invalidArgument"){let Z=`${Q} ${Y.message}`;this.error(Z,{exitCode:Y.exitCode,code:Y.code})}throw Y}}addOption($){let z=$.name(),B=$.attributeName();if($.negate){let Y=$.long.replace(/^--no-/,"--");if(!this._findOption(Y))this.setOptionValueWithSource(B,$.defaultValue===void 0?!0:$.defaultValue,"default")}else if($.defaultValue!==void 0)this.setOptionValueWithSource(B,$.defaultValue,"default");this.options.push($);let Q=(Y,Z,J)=>{if(Y==null&&$.presetArg!==void 0)Y=$.presetArg;let q=this.getOptionValue(B);if(Y!==null&&$.parseArg)Y=this._callParseArg($,Y,q,Z);else if(Y!==null&&$.variadic)Y=$._concatValue(Y,q);if(Y==null)if($.negate)Y=!1;else if($.isBoolean()||$.optional)Y=!0;else Y="";this.setOptionValueWithSource(B,Y,J)};if(this.on("option:"+z,(Y)=>{let Z=`error: option '${$.flags}' argument '${Y}' is invalid.`;Q(Y,Z,"cli")}),$.envVar)this.on("optionEnv:"+z,(Y)=>{let Z=`error: option '${$.flags}' value '${Y}' from env '${$.envVar}' is invalid.`;Q(Y,Z,"env")});return this}_optionEx($,z,B,Q,Y){if(typeof z==="object"&&z instanceof K0)throw Error("To add an Option object use addOption() instead of option() or requiredOption()");let Z=this.createOption(z,B);if(Z.makeOptionMandatory(!!$.mandatory),typeof Q==="function")Z.default(Y).argParser(Q);else if(Q instanceof RegExp){let J=Q;Q=(q,X)=>{let G=J.exec(q);return G?G[0]:X},Z.default(Y).argParser(Q)}else Z.default(Q);return this.addOption(Z)}option($,z,B,Q){return this._optionEx({},$,z,B,Q)}requiredOption($,z,B,Q){return this._optionEx({mandatory:!0},$,z,B,Q)}combineFlagAndOptionalValue($=!0){return this._combineFlagAndOptionalValue=!!$,this}allowUnknownOption($=!0){return this._allowUnknownOption=!!$,this}allowExcessArguments($=!0){return this._allowExcessArguments=!!$,this}enablePositionalOptions($=!0){return this._enablePositionalOptions=!!$,this}passThroughOptions($=!0){if(this._passThroughOptions=!!$,!!this.parent&&$&&!this.parent._enablePositionalOptions)throw Error("passThroughOptions can not be used without turning on enablePositionalOptions for parent command(s)");return this}storeOptionsAsProperties($=!0){if(this.options.length)throw Error("call .storeOptionsAsProperties() before adding options");return this._storeOptionsAsProperties=!!$,this}getOptionValue($){if(this._storeOptionsAsProperties)return this[$];return this._optionValues[$]}setOptionValue($,z){return this.setOptionValueWithSource($,z,void 0)}setOptionValueWithSource($,z,B){if(this._storeOptionsAsProperties)this[$]=z;else this._optionValues[$]=z;return this._optionValueSources[$]=B,this}getOptionValueSource($){return this._optionValueSources[$]}getOptionValueSourceWithGlobals($){let z;return this._getCommandAndAncestors().forEach((B)=>{if(B.getOptionValueSource($)!==void 0)z=B.getOptionValueSource($)}),z}_prepareUserArgs($,z){if($!==void 0&&!Array.isArray($))throw Error("first parameter to parse must be array or undefined");if(z=z||{},$===void 0){if($=M.argv,M.versions&&M.versions.electron)z.from="electron"}this.rawArgs=$.slice();let B;switch(z.from){case void 0:case"node":this._scriptPath=$[1],B=$.slice(2);break;case"electron":if(M.defaultApp)this._scriptPath=$[1],B=$.slice(2);else B=$.slice(1);break;case"user":B=$.slice(0);break;default:throw Error(`unexpected parse option { from: '${z.from}' }`)}if(!this._name&&this._scriptPath)this.nameFromFilename(this._scriptPath);return this._name=this._name||"program",B}parse($,z){let B=this._prepareUserArgs($,z);return this._parseCommand([],B),this}async parseAsync($,z){let B=this._prepareUserArgs($,z);return await this._parseCommand([],B),this}_executeSubCommand($,z){z=z.slice();let B=!1,Q=[".js",".ts",".tsx",".mjs",".cjs"];function Y(G,W){let U=R.resolve(G,W);if(c.existsSync(U))return U;if(Q.includes(R.extname(W)))return;let T=Q.find((K)=>c.existsSync(`${U}${K}`));if(T)return`${U}${T}`;return}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let Z=$._executableFile||`${this._name}-${$._name}`,J=this._executableDir||"";if(this._scriptPath){let G;try{G=c.realpathSync(this._scriptPath)}catch(W){G=this._scriptPath}J=R.resolve(R.dirname(G),J)}if(J){let G=Y(J,Z);if(!G&&!$._executableFile&&this._scriptPath){let W=R.basename(this._scriptPath,R.extname(this._scriptPath));if(W!==this._name)G=Y(J,`${W}-${$._name}`)}Z=G||Z}B=Q.includes(R.extname(Z));let q;if(M.platform!=="win32")if(B)z.unshift(Z),z=R0(M.execArgv).concat(z),q=g.spawn(M.argv[0],z,{stdio:"inherit"});else q=g.spawn(Z,z,{stdio:"inherit"});else z.unshift(Z),z=R0(M.execArgv).concat(z),q=g.spawn(M.execPath,z,{stdio:"inherit"});if(!q.killed)["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach((W)=>{M.on(W,()=>{if(q.killed===!1&&q.exitCode===null)q.kill(W)})});let X=this._exitCallback;if(!X)q.on("close",M.exit.bind(M));else q.on("close",()=>{X(new l(M.exitCode||0,"commander.executeSubCommandAsync","(close)"))});q.on("error",(G)=>{if(G.code==="ENOENT"){let W=J?`searched for local subcommand relative to directory '${J}'`:"no directory for search for local subcommand, use .executableDir() to supply a custom directory",U=`'${Z}' does not exist
|
|
14
|
+
- if '${$._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
15
|
+
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
16
|
+
- ${W}`;throw Error(U)}else if(G.code==="EACCES")throw Error(`'${Z}' not executable`);if(!X)M.exit(1);else{let W=new l(1,"commander.executeSubCommandAsync","(error)");W.nestedError=G,X(W)}}),this.runningCommand=q}_dispatchSubcommand($,z,B){let Q=this._findCommand($);if(!Q)this.help({error:!0});let Y;return Y=this._chainOrCallSubCommandHook(Y,Q,"preSubcommand"),Y=this._chainOrCall(Y,()=>{if(Q._executableHandler)this._executeSubCommand(Q,z.concat(B));else return Q._parseCommand(z,B)}),Y}_dispatchHelpCommand($){if(!$)this.help();let z=this._findCommand($);if(z&&!z._executableHandler)z.help();return this._dispatchSubcommand($,[],[this._helpLongFlag||this._helpShortFlag])}_checkNumberOfArguments(){if(this.registeredArguments.forEach(($,z)=>{if($.required&&this.args[z]==null)this.missingArgument($.name())}),this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)return;if(this.args.length>this.registeredArguments.length)this._excessArguments(this.args)}_processArguments(){let $=(B,Q,Y)=>{let Z=Q;if(Q!==null&&B.parseArg){let J=`error: command-argument value '${Q}' is invalid for argument '${B.name()}'.`;Z=this._callParseArg(B,Q,Y,J)}return Z};this._checkNumberOfArguments();let z=[];this.registeredArguments.forEach((B,Q)=>{let Y=B.defaultValue;if(B.variadic){if(Q<this.args.length){if(Y=this.args.slice(Q),B.parseArg)Y=Y.reduce((Z,J)=>{return $(B,J,Z)},B.defaultValue)}else if(Y===void 0)Y=[]}else if(Q<this.args.length){if(Y=this.args[Q],B.parseArg)Y=$(B,Y,B.defaultValue)}z[Q]=Y}),this.processedArgs=z}_chainOrCall($,z){if($&&$.then&&typeof $.then==="function")return $.then(()=>z());return z()}_chainOrCallHooks($,z){let B=$,Q=[];if(this._getCommandAndAncestors().reverse().filter((Y)=>Y._lifeCycleHooks[z]!==void 0).forEach((Y)=>{Y._lifeCycleHooks[z].forEach((Z)=>{Q.push({hookedCommand:Y,callback:Z})})}),z==="postAction")Q.reverse();return Q.forEach((Y)=>{B=this._chainOrCall(B,()=>{return Y.callback(Y.hookedCommand,this)})}),B}_chainOrCallSubCommandHook($,z,B){let Q=$;if(this._lifeCycleHooks[B]!==void 0)this._lifeCycleHooks[B].forEach((Y)=>{Q=this._chainOrCall(Q,()=>{return Y(this,z)})});return Q}_parseCommand($,z){let B=this.parseOptions(z);if(this._parseOptionsEnv(),this._parseOptionsImplied(),$=$.concat(B.operands),z=B.unknown,this.args=$.concat(z),$&&this._findCommand($[0]))return this._dispatchSubcommand($[0],$.slice(1),z);if(this._hasImplicitHelpCommand()&&$[0]===this._helpCommandName)return this._dispatchHelpCommand($[1]);if(this._defaultCommandName)return L0(this,z),this._dispatchSubcommand(this._defaultCommandName,$,z);if(this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName)this.help({error:!0});L0(this,B.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let Q=()=>{if(B.unknown.length>0)this.unknownOption(B.unknown[0])},Y=`command:${this.name()}`;if(this._actionHandler){Q(),this._processArguments();let Z;if(Z=this._chainOrCallHooks(Z,"preAction"),Z=this._chainOrCall(Z,()=>this._actionHandler(this.processedArgs)),this.parent)Z=this._chainOrCall(Z,()=>{this.parent.emit(Y,$,z)});return Z=this._chainOrCallHooks(Z,"postAction"),Z}if(this.parent&&this.parent.listenerCount(Y))Q(),this._processArguments(),this.parent.emit(Y,$,z);else if($.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",$,z);if(this.listenerCount("command:*"))this.emit("command:*",$,z);else if(this.commands.length)this.unknownCommand();else Q(),this._processArguments()}else if(this.commands.length)Q(),this.help({error:!0});else Q(),this._processArguments()}_findCommand($){if(!$)return;return this.commands.find((z)=>z._name===$||z._aliases.includes($))}_findOption($){return this.options.find((z)=>z.is($))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(($)=>{$.options.forEach((z)=>{if(z.mandatory&&$.getOptionValue(z.attributeName())===void 0)$.missingMandatoryOptionValue(z)})})}_checkForConflictingLocalOptions(){let $=this.options.filter((B)=>{let Q=B.attributeName();if(this.getOptionValue(Q)===void 0)return!1;return this.getOptionValueSource(Q)!=="default"});$.filter((B)=>B.conflictsWith.length>0).forEach((B)=>{let Q=$.find((Y)=>B.conflictsWith.includes(Y.attributeName()));if(Q)this._conflictingOption(B,Q)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(($)=>{$._checkForConflictingLocalOptions()})}parseOptions($){let z=[],B=[],Q=z,Y=$.slice();function Z(q){return q.length>1&&q[0]==="-"}let J=null;while(Y.length){let q=Y.shift();if(q==="--"){if(Q===B)Q.push(q);Q.push(...Y);break}if(J&&!Z(q)){this.emit(`option:${J.name()}`,q);continue}if(J=null,Z(q)){let X=this._findOption(q);if(X){if(X.required){let G=Y.shift();if(G===void 0)this.optionMissingArgument(X);this.emit(`option:${X.name()}`,G)}else if(X.optional){let G=null;if(Y.length>0&&!Z(Y[0]))G=Y.shift();this.emit(`option:${X.name()}`,G)}else this.emit(`option:${X.name()}`);J=X.variadic?X:null;continue}}if(q.length>2&&q[0]==="-"&&q[1]!=="-"){let X=this._findOption(`-${q[1]}`);if(X){if(X.required||X.optional&&this._combineFlagAndOptionalValue)this.emit(`option:${X.name()}`,q.slice(2));else this.emit(`option:${X.name()}`),Y.unshift(`-${q.slice(2)}`);continue}}if(/^--[^=]+=/.test(q)){let X=q.indexOf("="),G=this._findOption(q.slice(0,X));if(G&&(G.required||G.optional)){this.emit(`option:${G.name()}`,q.slice(X+1));continue}}if(Z(q))Q=B;if((this._enablePositionalOptions||this._passThroughOptions)&&z.length===0&&B.length===0){if(this._findCommand(q)){if(z.push(q),Y.length>0)B.push(...Y);break}else if(q===this._helpCommandName&&this._hasImplicitHelpCommand()){if(z.push(q),Y.length>0)z.push(...Y);break}else if(this._defaultCommandName){if(B.push(q),Y.length>0)B.push(...Y);break}}if(this._passThroughOptions){if(Q.push(q),Y.length>0)Q.push(...Y);break}Q.push(q)}return{operands:z,unknown:B}}opts(){if(this._storeOptionsAsProperties){let $={},z=this.options.length;for(let B=0;B<z;B++){let Q=this.options[B].attributeName();$[Q]=Q===this._versionOptionName?this._version:this[Q]}return $}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce(($,z)=>Object.assign($,z.opts()),{})}error($,z){if(this._outputConfiguration.outputError(`${$}
|
|
17
|
+
`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError==="string")this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
18
|
+
`);else if(this._showHelpAfterError)this._outputConfiguration.writeErr(`
|
|
19
|
+
`),this.outputHelp({error:!0});let B=z||{},Q=B.exitCode||1,Y=B.code||"commander.error";this._exit(Q,Y,$)}_parseOptionsEnv(){this.options.forEach(($)=>{if($.envVar&&$.envVar in M.env){let z=$.attributeName();if(this.getOptionValue(z)===void 0||["default","config","env"].includes(this.getOptionValueSource(z)))if($.required||$.optional)this.emit(`optionEnv:${$.name()}`,M.env[$.envVar]);else this.emit(`optionEnv:${$.name()}`)}})}_parseOptionsImplied(){let $=new D1(this.options),z=(B)=>{return this.getOptionValue(B)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(B))};this.options.filter((B)=>B.implied!==void 0&&z(B.attributeName())&&$.valueFromOption(this.getOptionValue(B.attributeName()),B)).forEach((B)=>{Object.keys(B.implied).filter((Q)=>!z(Q)).forEach((Q)=>{this.setOptionValueWithSource(Q,B.implied[Q],"implied")})})}missingArgument($){let z=`error: missing required argument '${$}'`;this.error(z,{code:"commander.missingArgument"})}optionMissingArgument($){let z=`error: option '${$.flags}' argument missing`;this.error(z,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue($){let z=`error: required option '${$.flags}' not specified`;this.error(z,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption($,z){let B=(Z)=>{let J=Z.attributeName(),q=this.getOptionValue(J),X=this.options.find((W)=>W.negate&&J===W.attributeName()),G=this.options.find((W)=>!W.negate&&J===W.attributeName());if(X&&(X.presetArg===void 0&&q===!1||X.presetArg!==void 0&&q===X.presetArg))return X;return G||Z},Q=(Z)=>{let J=B(Z),q=J.attributeName();if(this.getOptionValueSource(q)==="env")return`environment variable '${J.envVar}'`;return`option '${J.flags}'`},Y=`error: ${Q($)} cannot be used with ${Q(z)}`;this.error(Y,{code:"commander.conflictingOption"})}unknownOption($){if(this._allowUnknownOption)return;let z="";if($.startsWith("--")&&this._showSuggestionAfterError){let Q=[],Y=this;do{let Z=Y.createHelp().visibleOptions(Y).filter((J)=>J.long).map((J)=>J.long);Q=Q.concat(Z),Y=Y.parent}while(Y&&!Y._enablePositionalOptions);z=U0($,Q)}let B=`error: unknown option '${$}'${z}`;this.error(B,{code:"commander.unknownOption"})}_excessArguments($){if(this._allowExcessArguments)return;let z=this.registeredArguments.length,B=z===1?"":"s",Y=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${z} argument${B} but got ${$.length}.`;this.error(Y,{code:"commander.excessArguments"})}unknownCommand(){let $=this.args[0],z="";if(this._showSuggestionAfterError){let Q=[];this.createHelp().visibleCommands(this).forEach((Y)=>{if(Q.push(Y.name()),Y.alias())Q.push(Y.alias())}),z=U0($,Q)}let B=`error: unknown command '${$}'${z}`;this.error(B,{code:"commander.unknownCommand"})}version($,z,B){if($===void 0)return this._version;this._version=$,z=z||"-V, --version",B=B||"output the version number";let Q=this.createOption(z,B);return this._versionOptionName=Q.attributeName(),this.options.push(Q),this.on("option:"+Q.name(),()=>{this._outputConfiguration.writeOut(`${$}
|
|
20
|
+
`),this._exit(0,"commander.version",$)}),this}description($,z){if($===void 0&&z===void 0)return this._description;if(this._description=$,z)this._argsDescription=z;return this}summary($){if($===void 0)return this._summary;return this._summary=$,this}alias($){if($===void 0)return this._aliases[0];let z=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler)z=this.commands[this.commands.length-1];if($===z._name)throw Error("Command alias can't be the same as its name");return z._aliases.push($),this}aliases($){if($===void 0)return this._aliases;return $.forEach((z)=>this.alias(z)),this}usage($){if($===void 0){if(this._usage)return this._usage;let z=this.registeredArguments.map((B)=>{return P1(B)});return[].concat(this.options.length||this._hasHelpOption?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?z:[]).join(" ")}return this._usage=$,this}name($){if($===void 0)return this._name;return this._name=$,this}nameFromFilename($){return this._name=R.basename($,R.extname($)),this}executableDir($){if($===void 0)return this._executableDir;return this._executableDir=$,this}helpInformation($){let z=this.createHelp();if(z.helpWidth===void 0)z.helpWidth=$&&$.error?this._outputConfiguration.getErrHelpWidth():this._outputConfiguration.getOutHelpWidth();return z.formatHelp(this,z)}_getHelpContext($){$=$||{};let z={error:!!$.error},B;if(z.error)B=(Q)=>this._outputConfiguration.writeErr(Q);else B=(Q)=>this._outputConfiguration.writeOut(Q);return z.write=$.write||B,z.command=this,z}outputHelp($){let z;if(typeof $==="function")z=$,$=void 0;let B=this._getHelpContext($);this._getCommandAndAncestors().reverse().forEach((Y)=>Y.emit("beforeAllHelp",B)),this.emit("beforeHelp",B);let Q=this.helpInformation(B);if(z){if(Q=z(Q),typeof Q!=="string"&&!Buffer.isBuffer(Q))throw Error("outputHelp callback must return a string or a Buffer")}if(B.write(Q),this._helpLongFlag)this.emit(this._helpLongFlag);this.emit("afterHelp",B),this._getCommandAndAncestors().forEach((Y)=>Y.emit("afterAllHelp",B))}helpOption($,z){if(typeof $==="boolean")return this._hasHelpOption=$,this;this._helpFlags=$||this._helpFlags,this._helpDescription=z||this._helpDescription;let B=w1(this._helpFlags);return this._helpShortFlag=B.shortFlag,this._helpLongFlag=B.longFlag,this}help($){this.outputHelp($);let z=M.exitCode||0;if(z===0&&$&&typeof $!=="function"&&$.error)z=1;this._exit(z,"commander.help","(outputHelp)")}addHelpText($,z){let B=["beforeAll","before","after","afterAll"];if(!B.includes($))throw Error(`Unexpected value for position to addHelpText.
|
|
21
|
+
Expecting one of '${B.join("', '")}'`);let Q=`${$}Help`;return this.on(Q,(Y)=>{let Z;if(typeof z==="function")Z=z({error:Y.error,command:Y.command});else Z=z;if(Z)Y.write(`${Z}
|
|
22
|
+
`)}),this}}function L0($,z){if($._hasHelpOption&&z.find((Q)=>Q===$._helpLongFlag||Q===$._helpShortFlag))$.outputHelp(),$._exit(0,"commander.helpDisplayed","(outputHelp)")}function R0($){return $.map((z)=>{if(!z.startsWith("--inspect"))return z;let B,Q="127.0.0.1",Y="9229",Z;if((Z=z.match(/^(--inspect(-brk)?)$/))!==null)B=Z[1];else if((Z=z.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null)if(B=Z[1],/^\d+$/.test(Z[3]))Y=Z[3];else Q=Z[3];else if((Z=z.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null)B=Z[1],Q=Z[3],Y=Z[4];if(B&&Y!=="0")return`${B}=${Q}:${parseInt(Y)+1}`;return z})}F1.Command=m});var I0=j((L,j0)=>{var{Argument:y1}=k(),{Command:_0}=H0(),{CommanderError:A1,InvalidArgumentError:T0}=P(),{Help:b1}=h(),{Option:C1}=u();L=j0.exports=new _0;L.program=L;L.Command=_0;L.Option=C1;L.Argument=y1;L.Help=b1;L.CommanderError=A1;L.InvalidArgumentError=T0;L.InvalidOptionArgumentError=T0});import{execFileSync as U$}from"node:child_process";var V0=e0(I0(),1),{program:N$,createCommand:S$,createArgument:P$,createOption:E$,CommanderError:w$,InvalidArgumentError:D$,InvalidOptionArgumentError:F$,Command:N0,Argument:k$,Option:y$,Help:A$}=V0.default;import O1 from"node:os";import I from"node:path";import d from"node:fs/promises";var f1="https://ingest.agentsoc.com/api/v1/webhooks/syslog",x1="http://localhost:8110/api/v1/webhooks/syslog",v1="https://api.agentsoc.com",h1="http://localhost:8100",u1="/api/v1/siem/beacon/validate/key";function p($){let z=process.env.AGENTSOC_API_KEY?.trim();if(z)return z;return $.apiKey?.trim()||void 0}var E="Beacon is not configured. Run: beacon config --key <your-api-key> [--env production|development]. Or set AGENTSOC_API_KEY in your environment.";function y($){let z=$.toLowerCase().trim();if(z==="production"||z==="prod")return"production";if(z==="development"||z==="dev")return"development";throw Error(`Invalid environment "${$}". Use production or development (prod / dev).`)}function s($){if($==="production"||$==="development")return $;if(typeof $==="string")try{return y($)}catch{return}return}function g1($){return $==="development"?x1:f1}function c1($){return $==="development"?h1:v1}function l1(){let $=process.env.AGENTSOC_ENV?.trim();if(!$)return;try{return y($)}catch{console.warn(`[beacon] Ignoring invalid AGENTSOC_ENV="${$}" (use production or development).`);return}}function P0($){return l1()??s($.environment)??"production"}function E0($){let z=process.env.AGENTSOC_INGEST_URL?.trim();if(z)return z;return g1(P0($))}function m1($){let z=process.env.AGENTSOC_PLATFORM_URL?.trim()||process.env.AGENTSOC_PLATFORM_API_BASE_URL?.trim();if(z)return z.replace(/\/$/,"");return c1(P0($))}function w0($){return`${m1($)}${u1}`}function i($){if(process.platform==="win32")return I.join(process.env.APPDATA||I.join($,"AppData","Roaming"),"agentsoc-beacon");if(process.platform==="darwin")return I.join($,"Library","Application Support","agentsoc-beacon");let z=process.env.XDG_CONFIG_HOME||I.join($,".config");return I.join(z,"agentsoc-beacon")}function w(){return i(O1.homedir())}function S0(){return I.join(w(),"config.json")}async function _(){return n(w())}async function n($){try{let z=I.join($,"config.json"),B=await d.readFile(z,"utf8");return JSON.parse(B)}catch{return{}}}async function A($){let z=w();try{await d.mkdir(z,{recursive:!0}),await d.writeFile(S0(),JSON.stringify($,null,2),"utf8")}catch(B){console.error(`[syslog-beacon] Failed to save config to ${S0()}:`,B)}}async function D0($,z){let B=new AbortController,Q=setTimeout(()=>B.abort(),12000);try{let Y=await fetch($,{method:"GET",headers:{"X-API-Key":z},signal:B.signal}),Z=await Y.text(),J;try{J=Z?JSON.parse(Z):null}catch{return{ok:!1,message:"Invalid response from platform API"}}if(!Y.ok){let X=J;return{ok:!1,message:X&&typeof X.error==="string"?X.error:`HTTP ${Y.status}`}}let q=J;if(!q?.success||!q.apiKey?.name)return{ok:!1,message:"Unexpected response from platform API"};return{ok:!0,organizationName:q.organization?.name??null,organizationSlug:q.organization?.slug??null,apiKeyName:q.apiKey.name}}catch(Y){if(Y instanceof Error&&Y.name==="AbortError")return{ok:!1,message:"Request timed out"};return{ok:!1,message:Y instanceof Error?Y.message:String(Y)}}finally{clearTimeout(Q)}}var d1=`https://registry.npmjs.org/${encodeURIComponent("@agentsoc/beacon")}`;function p1($,z){return{success:!0,package:"@agentsoc/beacon",latestVersion:$,registryResolved:z,install:{npm:"npm install -g @agentsoc/beacon@latest",bun:"bun add -g @agentsoc/beacon@latest",pnpm:"pnpm add -g @agentsoc/beacon@latest"},docsUrl:"https://agentsoc.com/products/agentsoc-beacon",installScriptUrl:"https://agentsoc.com/connectors/beacon.sh"}}async function F0(){let $=new AbortController,z=setTimeout(()=>$.abort(),12000);try{let B=await fetch(d1,{headers:{Accept:"application/json"},signal:$.signal}),Q=await B.text(),Y;try{Y=Q?JSON.parse(Q):null}catch{return{ok:!1,message:"Invalid JSON from registry.npmjs.org"}}if(!B.ok)return{ok:!1,message:`registry.npmjs.org returned HTTP ${B.status}`};let J=Y["dist-tags"]?.latest?.trim()??null;return{ok:!0,info:p1(J,!0)}}catch(B){if(B instanceof Error&&B.name==="AbortError")return{ok:!1,message:"Request timed out"};return{ok:!1,message:B instanceof Error?B.message:String(B)}}finally{clearTimeout(z)}}import{existsSync as s1,readFileSync as i1}from"node:fs";import{dirname as k0,join as n1}from"node:path";import{fileURLToPath as t1}from"node:url";function A0(){let $=k0(t1(import.meta.url));for(let z=0;z<8;z++){let B=n1($,"package.json");if(s1(B))try{let Y=JSON.parse(i1(B,"utf8"));if(Y.name==="@agentsoc/beacon"&&typeof Y.version==="string")return Y.version}catch{}let Q=k0($);if(Q===$)break;$=Q}return"0.0.0"}function y0($){let z=$.indexOf("-");return z===-1?$:$.slice(0,z)}function t($,z){let B=y0($).split(".").map((Z)=>parseInt(Z,10)||0),Q=y0(z).split(".").map((Z)=>parseInt(Z,10)||0),Y=Math.max(B.length,Q.length);for(let Z=0;Z<Y;Z++){let J=B[Z]??0,q=Q[Z]??0;if(J<q)return!0;if(J>q)return!1}return!1}import o from"node:os";import o1 from"node:crypto";async function b0(){let $=await _(),z=$.agentId;if(!z)z=o1.randomUUID(),$.agentId=z,await A($);let B=o.hostname(),Q=o.platform(),Y="127.0.0.1",Z="00:00:00:00:00:00",J=o.networkInterfaces();for(let q of Object.keys(J)){let X=J[q];if(!X)continue;for(let G of X)if(!G.internal&&G.family==="IPv4"){Y=G.address,Z=G.mac;break}if(Y!=="127.0.0.1")break}return{agentId:z,hostname:B,ip:Y,osPlatform:Q,mac:Z}}import b from"node:fs/promises";import C0 from"node:path";var D=1,r=()=>({version:D,updatedAt:new Date(0).toISOString(),logsForwarded:0,batchesSucceeded:0,batchesFailed:0});function C(){return C0.join(w(),"stats.json")}async function O(){try{let $=await b.readFile(C(),"utf8"),z=JSON.parse($);if(z.version!==D)return r();return{...r(),...z,version:D}}catch{return r()}}async function O0($){let z=C(),B=C0.dirname(z);await b.mkdir(B,{recursive:!0});let Q=`${z}.${process.pid}.tmp`;await b.writeFile(Q,JSON.stringify($,null,2),"utf8"),await b.rename(Q,z)}async function f0($){try{let z=await O();await O0({version:D,updatedAt:new Date().toISOString(),logsForwarded:z.logsForwarded+$,batchesSucceeded:z.batchesSucceeded+1,batchesFailed:z.batchesFailed,lastError:void 0})}catch{}}async function a($){try{let z=await O(),B=$.replace(/\s+/g," ").slice(0,500);await O0({version:D,updatedAt:new Date().toISOString(),logsForwarded:z.logsForwarded,batchesSucceeded:z.batchesSucceeded,batchesFailed:z.batchesFailed+1,lastError:B||"Unknown error"})}catch{}}function r1($){let z=5,B=1,Q=$.match(/^<(\d+)>/);if(Q){let Z=parseInt(Q[1],10);B=Math.floor(Z/8),z=Z&7}else{let Z=$.toLowerCase();if(Z.includes("critical")||Z.includes("fatal")||Z.includes("panic"))z=2;else if(Z.includes("high")||Z.includes("error")||Z.includes("failed"))z=3;else if(Z.includes("medium")||Z.includes("warn"))z=4;else if(Z.includes("info"))z=6;else if(Z.includes("low")||Z.includes("notice"))z=5}let Y="info";if(z<=2)Y="critical";else if(z===3)Y="high";else if(z===4)Y="medium";else if(z===5)Y="low";return{severityStr:Y,facility:B}}function a1($){let z=$.match(/^\S+\s+(?:\S+\s+)?(\w+)(?:\[\d+\])?:\s*(.*)$/);if(z)return{app:z[1],message:z[2]};return{message:$}}class e{opts;buffer=[];timer=null;batchSize;flushMs;constructor($){this.opts=$;this.batchSize=$.batchSize||25,this.flushMs=$.flushMs||2000}pushLog($){let{severityStr:z,facility:B}=r1($),{app:Q,message:Y}=a1($),Z={full_log:Y,timestamp:new Date().toISOString(),hostname:this.opts.host.hostname,facility:B,severity:z,id:`${this.opts.host.agentId}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,agent:{id:this.opts.host.agentId,name:this.opts.host.hostname,ip:this.opts.host.ip,mac:this.opts.host.mac}};if(Q)Z.app=Q,Z.process={name:Q};if(this.buffer.push(Z),this.buffer.length>=this.batchSize)this.flush();else if(!this.timer)this.timer=setTimeout(()=>this.flush(),this.flushMs)}async flush(){if(this.timer)clearTimeout(this.timer),this.timer=null;if(this.buffer.length===0)return;let $=this.buffer;this.buffer=[],console.log(`[syslog-beacon] Pushing ${$.length} logs to API...`);try{let z=await fetch(this.opts.ingestUrl,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.opts.apiKey}`},body:JSON.stringify($)});if(!z.ok){let B=await z.text(),Q=`HTTP ${z.status} ${B}`;console.error(`[syslog-beacon] Failed to push logs: HTTP ${z.status} ${B}`),await a(Q)}else console.log(`[syslog-beacon] Successfully pushed ${$.length} logs`),await f0($.length)}catch(z){console.error("[syslog-beacon] Ingest error:",z),await a(z instanceof Error?z.message:String(z))}}async stop(){if(this.buffer.length>0)await this.flush()}}import{spawn as $0,spawnSync as e1}from"node:child_process";import $$ from"node:dgram";import x0 from"node:fs";var z$=["/var/log/syslog","/var/log/auth.log","/var/log/messages"];function B$(){return z$.filter(($)=>{try{return x0.existsSync($)&&x0.statSync($).isFile()}catch{return!1}})}function Q$(){let $=e1("journalctl",["--version"],{stdio:"ignore"});return!$.error&&$.status===0}var Y$=/not seeing messages from other users/i;class z0{onLog;tailProc;udpServer;journalRestrictedHintShown=!1;constructor($){this.onLog=$}startUdpListener(){this.udpServer=$$.createSocket("udp4"),this.udpServer.on("message",($)=>{this.onLog($.toString("utf8").trim())}),this.udpServer.on("error",($)=>{console.error(`[syslog-udp] error:
|
|
23
|
+
${$.stack}`),this.udpServer?.close()}),this.udpServer.bind(5140,()=>{console.log("[syslog-udp] listening on UDP 5140")})}start(){if(process.platform==="linux"){let $=!1;if(Q$())$=!0,console.log("[syslog-tail] Streaming systemd journal (journalctl -f)"),this.tailProc=$0("journalctl",["-f","--no-pager","-o","short-iso"]);else{let z=B$();if(z.length>0)console.log(`[syslog-tail] Following: ${z.join(", ")}`),this.tailProc=$0("tail",["-F",...z]);else{console.log("[syslog-tail] No journalctl or log files under /var/log; listening on UDP 5140"),this.startUdpListener();return}}this.tailProc.stdout?.on("data",(z)=>{let B=z.toString().split(`
|
|
24
|
+
`);for(let Q of B)if(Q.trim())this.onLog(Q)}),this.tailProc.stderr?.on("data",(z)=>{let B=z.toString();if(console.error(`[syslog-tail] ${B}`),$&&!this.journalRestrictedHintShown&&Y$.test(B))this.journalRestrictedHintShown=!0,console.error("[syslog-tail] Only your user journal is visible. For system-wide logs, add this user to group systemd-journal or adm, or run beacon as root (no extra packages).")})}else if(process.platform==="darwin")this.tailProc=$0("log",["stream","--predicate",'process == "sshd" or process == "sudo" or process == "login" or process == "logger"',"--style","syslog"]),console.log("[syslog-tail] macOS log stream started"),this.tailProc.stdout?.on("data",($)=>{let z=$.toString().split(`
|
|
25
|
+
`);for(let B of z)if(B.trim())this.onLog(B)}),this.tailProc.stderr?.on("data",($)=>{console.error(`[syslog-tail] ${$.toString()}`)});else this.startUdpListener()}stop(){if(this.tailProc)this.tailProc.kill();if(this.udpServer)this.udpServer.close()}}async function v0($){let z=await b0(),B=new e({...$,host:z}),Q=new z0((Y)=>{B.pushLog(Y)});return Q.start(),{stop:async()=>{Q.stop(),await B.stop()}}}import{constants as Z$}from"node:fs";import Q0 from"node:fs/promises";import q$ from"node:os";import F from"node:path";import{execFileSync as V,execSync as B0}from"node:child_process";var J$=`That location is only writable as root. From the same shell where \`beacon\` works, run:
|
|
26
|
+
|
|
27
|
+
sudo "$(command -v beacon)" install
|
|
28
|
+
|
|
29
|
+
You will be prompted for your administrator password.
|
|
30
|
+
|
|
31
|
+
Why not \`sudo beacon install\`? sudo uses a minimal PATH. When beacon was installed with npm/nvm/fnm as your user, root often cannot find the \`beacon\` command (you will see "command not found"). The line above resolves the full path before sudo runs.
|
|
32
|
+
|
|
33
|
+
Other options:
|
|
34
|
+
sudo env "PATH=$PATH" beacon install
|
|
35
|
+
sudo /path/from/which/beacon install`;function m0($){return Error(`Cannot install the system service: permission denied for ${F.dirname($)}.
|
|
36
|
+
|
|
37
|
+
${J$}`)}async function h0($){let z=F.dirname($);try{await Q0.access(z,Z$.W_OK)}catch(B){let Q=B&&typeof B==="object"&&"code"in B?B.code:void 0;if(Q==="EACCES"||Q==="EPERM")throw m0($);throw B}}async function u0($,z){try{await Q0.writeFile($,z,"utf8")}catch(B){let Q=B&&typeof B==="object"&&"code"in B?B.code:void 0;if(Q==="EACCES"||Q==="EPERM")throw m0($);throw B}}function g0(){if(process.execPath.endsWith("bun")||process.execPath.endsWith("bun.exe"))return process.execPath;let z=F.basename(process.execPath);if(/^node(\.exe)?$/i.test(z))return process.execPath;try{let B=V("/usr/bin/which",["node"],{encoding:"utf8",env:process.env}).trim();if(B)return B}catch{}return"node"}function c0($){if(/["\\\s]/.test($))return`"${$.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`;return $}function X$($,z){try{V("launchctl",["bootout","system",$],{stdio:"ignore"});return}catch{}try{V("launchctl",["bootout",`system/${z}`],{stdio:"ignore"})}catch{}}function G$($){if(process.platform==="win32")return;try{let B=V("getent",["passwd",$],{encoding:"utf8"}).trim().split(":");if(B.length>=6&&B[5])return B[5]}catch{}if(process.platform==="darwin")return`/Users/${$}`;return F.join("/home",$)}async function W$(){if((typeof process.getuid==="function"?process.getuid():-1)===0){let z=process.env.SUDO_USER?.trim();if(z){let B=G$(z);if(B)return n(i(B))}}return _()}function l0(){let $=process.env.SUDO_USER?.trim();if($)return $;if((typeof process.getuid==="function"?process.getuid():-1)!==0)try{return q$.userInfo().username}catch{}throw Error("Cannot determine which user account should run the beacon daemon. Config is stored under that user's home directory. Run install from your normal account with sudo, e.g. `sudo beacon install`, not from a root-only shell.")}function M$($){return $.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function K$($){try{V("launchctl",["bootstrap","system",$],{encoding:"utf8",stdio:["ignore","inherit","pipe"]})}catch(z){let Q=z.stderr?.toString("utf8").trim()??"",Y=Q?`
|
|
38
|
+
${Q}`:"";throw Error(`launchctl bootstrap failed for ${$}.${Y}
|
|
39
|
+
|
|
40
|
+
Try:
|
|
41
|
+
sudo launchctl bootout system ${$}
|
|
42
|
+
sudo "$(command -v beacon)" install`)}}async function d0(){if(!(await W$()).apiKey?.trim())throw Error(E);let z=g0(),B=F.resolve(process.argv[1]),Q=`${c0(z)} ${c0(B)} run`;if(process.platform==="linux"){let Z=`[Unit]
|
|
43
|
+
Description=AgentSOC Syslog Beacon
|
|
44
|
+
After=network.target
|
|
45
|
+
|
|
46
|
+
[Service]
|
|
47
|
+
Type=simple
|
|
48
|
+
User=${l0()}
|
|
49
|
+
ExecStart=${Q}
|
|
50
|
+
Restart=always
|
|
51
|
+
RestartSec=10
|
|
52
|
+
Environment=NODE_ENV=production
|
|
53
|
+
|
|
54
|
+
[Install]
|
|
55
|
+
WantedBy=multi-user.target
|
|
56
|
+
`,J="/etc/systemd/system/syslog-beacon.service";await h0("/etc/systemd/system/syslog-beacon.service"),await u0("/etc/systemd/system/syslog-beacon.service",Z),B0("systemctl daemon-reload"),B0("systemctl enable syslog-beacon"),B0("systemctl start syslog-beacon");try{V("systemctl",["is-active","syslog-beacon"],{encoding:"utf8",stdio:["ignore","pipe","pipe"]})}catch{console.warn("[syslog-beacon] Service is not active yet. If this persists: journalctl -u syslog-beacon -n 30 --no-pager")}console.log("[syslog-beacon] Installed systemd service")}else if(process.platform==="darwin"){let Z=M$(l0()),J=g0(),q=`<?xml version="1.0" encoding="UTF-8"?>
|
|
57
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
58
|
+
<plist version="1.0">
|
|
59
|
+
<dict>
|
|
60
|
+
<key>Label</key>
|
|
61
|
+
<string>com.agentsoc.syslog-beacon</string>
|
|
62
|
+
<key>UserName</key>
|
|
63
|
+
<string>${Z}</string>
|
|
64
|
+
<key>ProgramArguments</key>
|
|
65
|
+
<array>
|
|
66
|
+
<string>${J}</string>
|
|
67
|
+
<string>${B}</string>
|
|
68
|
+
<string>run</string>
|
|
69
|
+
</array>
|
|
70
|
+
<key>RunAtLoad</key>
|
|
71
|
+
<true/>
|
|
72
|
+
<key>KeepAlive</key>
|
|
73
|
+
<true/>
|
|
74
|
+
</dict>
|
|
75
|
+
</plist>
|
|
76
|
+
`,X="/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist";await h0("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist"),X$("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist","com.agentsoc.syslog-beacon"),await u0("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist",q),V("chown",["root:wheel","/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist"],{stdio:"inherit"}),await Q0.chmod("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist",420),K$("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist"),console.log("[syslog-beacon] Installed launchd service")}else if(process.platform==="win32")console.log("[syslog-beacon] Windows service installation must be done via NSSM or WinSW. Skipping automatic install.");else throw Error(`Platform ${process.platform} is not supported for automatic service installation.`)}import f from"node:fs";import{execFileSync as p0}from"node:child_process";function s0($,z=200){let B=$.replace(/\s+/g," ").trim();return B.length<=z?B:`${B.slice(0,z)}…`}function i0(){if(process.platform==="linux"){if(!f.existsSync("/etc/systemd/system/syslog-beacon.service"))return{manager:"systemd",installed:!1,active:null,stateLabel:"not installed",detail:"No unit at /etc/systemd/system/syslog-beacon.service"};try{let B=p0("systemctl",["is-active","syslog-beacon"],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim();return{manager:"systemd",installed:!0,active:B==="active",stateLabel:B||"unknown"}}catch(B){let Q=B.status,Y=B.stderr?.toString?.()??"";if(Q===3)return{manager:"systemd",installed:!0,active:!1,stateLabel:"inactive"};return{manager:"systemd",installed:!0,active:!1,stateLabel:"unknown",detail:s0(Y||String(B))}}}if(process.platform==="darwin"){if(!f.existsSync("/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist"))return{manager:"launchd",installed:!1,active:null,stateLabel:"not installed",detail:"No plist at /Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist"};try{let Y=p0("launchctl",["print","system/com.agentsoc.syslog-beacon"],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).match(/^\s*state\s*=\s*(\S+)/m)?.[1]??"unknown";return{manager:"launchd",installed:!0,active:Y==="running",stateLabel:Y}}catch(B){let Q=B.stderr?.toString?.()??"";return{manager:"launchd",installed:!0,active:null,stateLabel:"unknown",detail:s0(Q||String(B))}}}return{manager:"none",installed:!1,active:null,stateLabel:"unsupported",detail:"Automatic service detection is only available on Linux (systemd) and macOS (launchd)."}}var n0=A0(),N=new N0;N.name("beacon").description("AgentSOC Syslog Beacon - Lightweight background log forwarder").version(n0,"-v, --version");N.command("config").description("Configure the AgentSOC connection").option("-e, --env <env>","Environment: production (default) or development").option("-k, --key <key>","AgentSOC API Key").action(async($)=>{if(!$.key)console.log(`
|
|
77
|
+
[beacon] Missing required option.
|
|
78
|
+
`),console.log(`Usage: beacon config --key <key> [--env production|development]
|
|
79
|
+
`),console.log("Examples:"),console.log(" beacon config --key sk_1234567890abcdef"),console.log(` beacon config --key sk_1234567890abcdef --env development
|
|
80
|
+
`),console.log("Options:"),console.log(" -k, --key <key> AgentSOC API Key (required)"),console.log(` -e, --env <env> production (default) or development; sets ingest + platform API defaults
|
|
81
|
+
`),process.exit(1);let z=await _(),B;try{B=$.env!==void 0?y($.env):s(z.environment)??"production"}catch(Q){console.error("[beacon]",Q instanceof Error?Q.message:String(Q)),process.exit(1)}await A({apiKey:$.key,environment:B,agentId:z.agentId}),console.log("[beacon] Config saved."),console.log(`[beacon] Environment: ${B}`)});N.command("install").description("Install the background service daemon").action(async()=>{try{await d0()}catch($){let z=$ instanceof Error?$.message:String($);console.error(`[beacon] Install failed:
|
|
82
|
+
|
|
83
|
+
${z}
|
|
84
|
+
`),process.exit(1)}});N.command("status").description("Show service state and forwarding statistics").option("--json","Print machine-readable JSON on stdout").action(async($)=>{let z=i0(),B=await O(),Q=C(),Y=await _(),Z=p(Y),J=w0(Y),q=Z?await D0(J,Z):{ok:!1,message:E};if($.json){console.log(JSON.stringify({service:z,stats:B,statsPath:Q,validateKeyUrl:J,context:q.ok?{organizationName:q.organizationName,organizationSlug:q.organizationSlug,apiKeyName:q.apiKeyName}:{error:q.message}},null,2));return}let X=26,G=(W,U)=>{console.log(` ${W.padEnd(X)}${U}`)};if(console.log(`
|
|
85
|
+
AgentSOC Beacon — Status
|
|
86
|
+
`),console.log(" Account"),q.ok)G("Organization",q.organizationName??"(name unavailable — check platform API / database)"),G("API key",q.apiKeyName);else G("Connection",q.message);if(console.log(`
|
|
87
|
+
Service`),G(`Daemon (${z.manager})`,z.installed?z.stateLabel:"not installed"),z.active===!0)G("Running","yes");else if(z.active===!1)G("Running","no");else G("Running","n/a");if(z.detail)G("Note",z.detail);if(console.log(`
|
|
88
|
+
Forwarding (this machine)`),G("Log entries forwarded",String(B.logsForwarded)),G("Successful batches",String(B.batchesSucceeded)),G("Failed batches",String(B.batchesFailed)),B.updatedAt&&B.updatedAt!==new Date(0).toISOString())G("Last stats update",B.updatedAt);else G("Last stats update","(none yet)");if(B.lastError)G("Last error",B.lastError);console.log()});N.command("update").description("Check for a newer Beacon CLI and optionally install it").option("--json","Print machine-readable JSON on stdout").option("-y, --yes","Run npm install -g @agentsoc/beacon@latest (non-interactive upgrade)").action(async($)=>{let z=n0,B=await F0();if($.json){let q=B.ok?B.info.latestVersion:null,X=q!=null&&q.length>0&&t(z,q);if(console.log(JSON.stringify({currentVersion:z,registry:"https://registry.npmjs.org/@agentsoc%2fbeacon",remote:B.ok?B.info:null,error:B.ok?void 0:B.message,updateAvailable:B.ok?X:null},null,2)),!B.ok)process.exit(1);return}if(!B.ok)console.error(`[beacon] Could not reach npm registry: ${B.message}`),console.error("[beacon] You can still run: npm install -g @agentsoc/beacon@latest"),process.exit(1);let{info:Q}=B,Y=Q.latestVersion;if(console.log(`
|
|
89
|
+
AgentSOC Beacon — Update check
|
|
90
|
+
`),console.log(` This install ${z}`),Y)console.log(` Latest on registry ${Y}`);else console.log(" Latest on registry (unavailable — unexpected npm response)");let Z=Boolean(Y&&Y.length>0),J=Z&&t(z,Y);if(Z&&!J){console.log(`
|
|
91
|
+
You are on the latest published version.
|
|
92
|
+
`);return}if(Z&&J)console.log(`
|
|
93
|
+
A newer version is available.
|
|
94
|
+
`);else console.log(`
|
|
95
|
+
Compare versions manually, or reinstall with:
|
|
96
|
+
`);if(console.log(` ${Q.install.npm}`),console.log(` ${Q.install.bun}`),console.log(` ${Q.install.pnpm}`),Q.docsUrl)console.log(`
|
|
97
|
+
Docs: ${Q.docsUrl}`);if($.yes){if(!J&&Z){console.log(`
|
|
98
|
+
[beacon] Already up to date — skipping install.
|
|
99
|
+
`);return}console.log(`
|
|
100
|
+
[beacon] Running npm install -g @agentsoc/beacon@latest …
|
|
101
|
+
`);let q=process.platform==="win32"?"npm.cmd":"npm";try{U$(q,["install","-g","@agentsoc/beacon@latest"],{stdio:"inherit",env:process.env}),console.log("\n[beacon] Update finished. Run `beacon --version` to verify.\n")}catch{process.exit(1)}return}console.log(`
|
|
102
|
+
To upgrade now, run the same command with --yes
|
|
103
|
+
`)});N.command("run").description("Run the forwarder daemon (foreground)").option("--batch-size <n>","Batch size","25").option("--flush-ms <n>","Flush interval in ms","2000").action(async($)=>{let z=await _(),B=p(z),Q=E0(z);if(!B)console.error(`[beacon] ${E}`),process.exit(1);console.log("[beacon] Starting in foreground...");let Y=await v0({apiKey:B,ingestUrl:Q,batchSize:parseInt($.batchSize,10),flushMs:parseInt($.flushMs,10)}),Z=async()=>{console.log(`
|
|
104
|
+
[beacon] Stopping...`),await Y.stop(),process.exit(0)};process.on("SIGINT",Z),process.on("SIGTERM",Z)});N.parse(process.argv);
|
package/dist/config.d.ts
CHANGED
|
@@ -38,8 +38,14 @@ export declare function resolvePlatformApiBase(config: BeaconConfig): string;
|
|
|
38
38
|
export declare function resolveSiemBeaconValidateKeyUrl(config: BeaconConfig): string;
|
|
39
39
|
/** @deprecated Use {@link resolveSiemBeaconValidateKeyUrl} */
|
|
40
40
|
export declare function resolveBeaconContextUrl(config: BeaconConfig): string;
|
|
41
|
+
/**
|
|
42
|
+
* Config directory for a given home directory (same layout as {@link getConfigDir} for that user).
|
|
43
|
+
* Used when `sudo beacon install` must read the invoking user's `config.json` (root's home is /root).
|
|
44
|
+
*/
|
|
45
|
+
export declare function getConfigDirForHome(home: string): string;
|
|
41
46
|
export declare function getConfigDir(): string;
|
|
42
47
|
export declare function getConfigFile(): string;
|
|
43
48
|
export declare function loadConfig(): Promise<BeaconConfig>;
|
|
49
|
+
export declare function loadConfigFromConfigDir(configDir: string): Promise<BeaconConfig>;
|
|
44
50
|
export declare function saveConfig(config: BeaconConfig): Promise<void>;
|
|
45
51
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,uDACoB,CAAC;AAEvD,eAAO,MAAM,sBAAsB,iDACa,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,qCACN,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7D,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK5E;AAED,iEAAiE;AACjE,eAAO,MAAM,8BAA8B,mJACuG,CAAC;AAEnJ,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAOvE;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAU/B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAItE;AAmBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAM5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAI7D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAMnE;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,MAAM,CAER;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,uDACoB,CAAC;AAEvD,eAAO,MAAM,sBAAsB,iDACa,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,qCACN,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7D,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK5E;AAED,iEAAiE;AACjE,eAAO,MAAM,8BAA8B,mJACuG,CAAC;AAEnJ,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAOvE;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAU/B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAItE;AAmBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAM5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAI7D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAMnE;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,MAAM,CAER;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEpE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYxD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,CAExD;AAED,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,CAQvB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAepE"}
|
package/dist/config.js
CHANGED
|
@@ -95,8 +95,11 @@ export function resolveSiemBeaconValidateKeyUrl(config) {
|
|
|
95
95
|
export function resolveBeaconContextUrl(config) {
|
|
96
96
|
return resolveSiemBeaconValidateKeyUrl(config);
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Config directory for a given home directory (same layout as {@link getConfigDir} for that user).
|
|
100
|
+
* Used when `sudo beacon install` must read the invoking user's `config.json` (root's home is /root).
|
|
101
|
+
*/
|
|
102
|
+
export function getConfigDirForHome(home) {
|
|
100
103
|
if (process.platform === "win32") {
|
|
101
104
|
return path.join(process.env.APPDATA || path.join(home, "AppData", "Roaming"), "agentsoc-beacon");
|
|
102
105
|
}
|
|
@@ -106,16 +109,22 @@ export function getConfigDir() {
|
|
|
106
109
|
const xdg = process.env.XDG_CONFIG_HOME || path.join(home, ".config");
|
|
107
110
|
return path.join(xdg, "agentsoc-beacon");
|
|
108
111
|
}
|
|
112
|
+
export function getConfigDir() {
|
|
113
|
+
return getConfigDirForHome(os.homedir());
|
|
114
|
+
}
|
|
109
115
|
export function getConfigFile() {
|
|
110
116
|
return path.join(getConfigDir(), "config.json");
|
|
111
117
|
}
|
|
112
118
|
export async function loadConfig() {
|
|
119
|
+
return loadConfigFromConfigDir(getConfigDir());
|
|
120
|
+
}
|
|
121
|
+
export async function loadConfigFromConfigDir(configDir) {
|
|
113
122
|
try {
|
|
114
|
-
const file =
|
|
123
|
+
const file = path.join(configDir, "config.json");
|
|
115
124
|
const data = await fs.readFile(file, "utf8");
|
|
116
125
|
return JSON.parse(data);
|
|
117
126
|
}
|
|
118
|
-
catch
|
|
127
|
+
catch {
|
|
119
128
|
return {};
|
|
120
129
|
}
|
|
121
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"AAqMA,wBAAsB,cAAc,kBAqFnC"}
|
package/dist/service-install.js
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { execFileSync, execSync } from 'node:child_process';
|
|
6
|
-
import { BEACON_CONFIG_REQUIRED_MESSAGE, loadConfig } from './config.js';
|
|
6
|
+
import { BEACON_CONFIG_REQUIRED_MESSAGE, getConfigDirForHome, loadConfig, loadConfigFromConfigDir, } from './config.js';
|
|
7
7
|
const PERMISSION_DENIED_HINT = `That location is only writable as root. From the same shell where \`beacon\` works, run:
|
|
8
8
|
|
|
9
9
|
sudo "$(command -v beacon)" install
|
|
@@ -47,8 +47,11 @@ async function writeServiceFile(destPath, contents) {
|
|
|
47
47
|
throw e;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Absolute path to node/bun. systemd and launchd do not use login-shell PATH, so a bare
|
|
52
|
+
* `node` breaks when Node comes from nvm/fnm (service stays inactive).
|
|
53
|
+
*/
|
|
54
|
+
function resolveDaemonJsRunner() {
|
|
52
55
|
const isBun = process.execPath.endsWith('bun') || process.execPath.endsWith('bun.exe');
|
|
53
56
|
if (isBun) {
|
|
54
57
|
return process.execPath;
|
|
@@ -60,6 +63,7 @@ function resolveLaunchdRunner() {
|
|
|
60
63
|
try {
|
|
61
64
|
const nodePath = execFileSync('/usr/bin/which', ['node'], {
|
|
62
65
|
encoding: 'utf8',
|
|
66
|
+
env: process.env,
|
|
63
67
|
}).trim();
|
|
64
68
|
if (nodePath) {
|
|
65
69
|
return nodePath;
|
|
@@ -70,6 +74,13 @@ function resolveLaunchdRunner() {
|
|
|
70
74
|
}
|
|
71
75
|
return 'node';
|
|
72
76
|
}
|
|
77
|
+
/** One argument for systemd ExecStart (quote if spaces or quotes). */
|
|
78
|
+
function systemdExecArg(arg) {
|
|
79
|
+
if (/["\\\s]/.test(arg)) {
|
|
80
|
+
return `"${arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
81
|
+
}
|
|
82
|
+
return arg;
|
|
83
|
+
}
|
|
73
84
|
function launchctlBootoutSystem(plistPath, label) {
|
|
74
85
|
try {
|
|
75
86
|
execFileSync('launchctl', ['bootout', 'system', plistPath], {
|
|
@@ -89,6 +100,41 @@ function launchctlBootoutSystem(plistPath, label) {
|
|
|
89
100
|
// not loaded yet
|
|
90
101
|
}
|
|
91
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Home directory for passwd entry (for `sudo beacon install`: read invoking user's config, not /root).
|
|
105
|
+
*/
|
|
106
|
+
function lookupUnixHomeDir(username) {
|
|
107
|
+
if (process.platform === 'win32')
|
|
108
|
+
return undefined;
|
|
109
|
+
try {
|
|
110
|
+
const line = execFileSync('getent', ['passwd', username], {
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
}).trim();
|
|
113
|
+
const parts = line.split(':');
|
|
114
|
+
if (parts.length >= 6 && parts[5])
|
|
115
|
+
return parts[5];
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
/* getent missing (e.g. some macOS) or unknown user */
|
|
119
|
+
}
|
|
120
|
+
if (process.platform === 'darwin') {
|
|
121
|
+
return `/Users/${username}`;
|
|
122
|
+
}
|
|
123
|
+
return path.join('/home', username);
|
|
124
|
+
}
|
|
125
|
+
async function loadConfigForServiceInstall() {
|
|
126
|
+
const uid = typeof process.getuid === 'function' ? process.getuid() : -1;
|
|
127
|
+
if (uid === 0) {
|
|
128
|
+
const sudoUser = process.env.SUDO_USER?.trim();
|
|
129
|
+
if (sudoUser) {
|
|
130
|
+
const home = lookupUnixHomeDir(sudoUser);
|
|
131
|
+
if (home) {
|
|
132
|
+
return loadConfigFromConfigDir(getConfigDirForHome(home));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return loadConfig();
|
|
137
|
+
}
|
|
92
138
|
/**
|
|
93
139
|
* Config and stats paths use os.homedir(). A LaunchDaemon/systemd unit runs as root by
|
|
94
140
|
* default, which points at /var/root (macOS) or /root — not the user who ran `beacon config`.
|
|
@@ -133,15 +179,14 @@ function launchctlBootstrapSystem(plistPath) {
|
|
|
133
179
|
}
|
|
134
180
|
}
|
|
135
181
|
export async function installService() {
|
|
136
|
-
const config = await
|
|
182
|
+
const config = await loadConfigForServiceInstall();
|
|
137
183
|
// Service units do not inherit the install shell's env — key must be saved in config.
|
|
138
184
|
if (!config.apiKey?.trim()) {
|
|
139
185
|
throw new Error(BEACON_CONFIG_REQUIRED_MESSAGE);
|
|
140
186
|
}
|
|
141
|
-
const
|
|
142
|
-
const runner = isBun ? process.execPath : 'node';
|
|
187
|
+
const runner = resolveDaemonJsRunner();
|
|
143
188
|
const cliPath = path.resolve(process.argv[1]);
|
|
144
|
-
const
|
|
189
|
+
const execStartLine = `${systemdExecArg(runner)} ${systemdExecArg(cliPath)} run`;
|
|
145
190
|
if (process.platform === 'linux') {
|
|
146
191
|
const runAs = resolveDaemonRunAsUsername();
|
|
147
192
|
const serviceUnit = `[Unit]
|
|
@@ -151,7 +196,7 @@ After=network.target
|
|
|
151
196
|
[Service]
|
|
152
197
|
Type=simple
|
|
153
198
|
User=${runAs}
|
|
154
|
-
ExecStart=${
|
|
199
|
+
ExecStart=${execStartLine}
|
|
155
200
|
Restart=always
|
|
156
201
|
RestartSec=10
|
|
157
202
|
Environment=NODE_ENV=production
|
|
@@ -165,12 +210,21 @@ WantedBy=multi-user.target
|
|
|
165
210
|
execSync('systemctl daemon-reload');
|
|
166
211
|
execSync('systemctl enable syslog-beacon');
|
|
167
212
|
execSync('systemctl start syslog-beacon');
|
|
213
|
+
try {
|
|
214
|
+
execFileSync('systemctl', ['is-active', 'syslog-beacon'], {
|
|
215
|
+
encoding: 'utf8',
|
|
216
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
console.warn('[syslog-beacon] Service is not active yet. If this persists: journalctl -u syslog-beacon -n 30 --no-pager');
|
|
221
|
+
}
|
|
168
222
|
console.log('[syslog-beacon] Installed systemd service');
|
|
169
223
|
}
|
|
170
224
|
else if (process.platform === 'darwin') {
|
|
171
225
|
const label = 'com.agentsoc.syslog-beacon';
|
|
172
226
|
const runAs = escapePlistString(resolveDaemonRunAsUsername());
|
|
173
|
-
const launchdRunner =
|
|
227
|
+
const launchdRunner = resolveDaemonJsRunner();
|
|
174
228
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
175
229
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
176
230
|
<plist version="1.0">
|