@honeybee-ai/waggle-cli 1.0.0 → 1.0.2
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/dist/brood.d.ts +92 -0
- package/dist/brood.js +259 -0
- package/dist/brood.js.map +1 -0
- package/dist/cli.js +1025 -91
- package/dist/cli.js.map +4 -4
- package/dist/commands/auth.js +1 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/down.d.ts +1 -0
- package/dist/commands/down.js +76 -0
- package/dist/commands/down.js.map +1 -0
- package/dist/commands/integrations.js +10 -5
- package/dist/commands/integrations.js.map +1 -1
- package/dist/commands/marketplace.js +1 -1
- package/dist/commands/marketplace.js.map +1 -1
- package/dist/commands/swarm.js +1 -1
- package/dist/commands/swarm.js.map +1 -1
- package/dist/commands/telemetry.d.ts +1 -0
- package/dist/commands/telemetry.js +151 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/up.d.ts +1 -0
- package/dist/commands/up.js +376 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/hook.js +10 -9
- package/dist/hook.js.map +3 -3
- package/dist/hooks/session-start.js +7 -5
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/lib/global-config.js +1 -1
- package/dist/lib/global-config.js.map +1 -1
- package/dist/lib/ipc-broker.d.ts +23 -0
- package/dist/lib/ipc-broker.js +95 -0
- package/dist/lib/ipc-broker.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/package.json +9 -12
package/dist/cli.js
CHANGED
|
@@ -188,14 +188,14 @@ var init_hooks = __esm({
|
|
|
188
188
|
}
|
|
189
189
|
});
|
|
190
190
|
|
|
191
|
-
// node_modules/.pnpm/@agentcoordinationprotocol+sdk@
|
|
191
|
+
// node_modules/.pnpm/@agentcoordinationprotocol+sdk@0.1.0/node_modules/@agentcoordinationprotocol/sdk/dist/client.js
|
|
192
192
|
import { request as httpRequest } from "node:http";
|
|
193
193
|
import { request as httpsRequest } from "node:https";
|
|
194
194
|
function createAcpClient(config) {
|
|
195
195
|
const base = config.server.replace(/\/$/, "");
|
|
196
196
|
const ns = (config.namespace ?? "default") === "default" ? "" : `/${config.namespace}`;
|
|
197
197
|
function fetch(method, path, body) {
|
|
198
|
-
return new Promise((
|
|
198
|
+
return new Promise((resolve3, reject) => {
|
|
199
199
|
const url = new URL(`${base}/api${ns}${path}`);
|
|
200
200
|
const isHttps = url.protocol === "https:";
|
|
201
201
|
const reqFn = isHttps ? httpsRequest : httpRequest;
|
|
@@ -214,9 +214,9 @@ function createAcpClient(config) {
|
|
|
214
214
|
res.on("end", () => {
|
|
215
215
|
try {
|
|
216
216
|
const parsed = data ? JSON.parse(data) : {};
|
|
217
|
-
|
|
217
|
+
resolve3({ ok: res.statusCode >= 200 && res.statusCode < 300, status: res.statusCode, data: parsed });
|
|
218
218
|
} catch {
|
|
219
|
-
|
|
219
|
+
resolve3({ ok: false, status: res.statusCode, data: {} });
|
|
220
220
|
}
|
|
221
221
|
});
|
|
222
222
|
});
|
|
@@ -341,14 +341,14 @@ function createAcpClient(config) {
|
|
|
341
341
|
}
|
|
342
342
|
var TIMEOUT;
|
|
343
343
|
var init_client = __esm({
|
|
344
|
-
"node_modules/.pnpm/@agentcoordinationprotocol+sdk@
|
|
344
|
+
"node_modules/.pnpm/@agentcoordinationprotocol+sdk@0.1.0/node_modules/@agentcoordinationprotocol/sdk/dist/client.js"() {
|
|
345
345
|
TIMEOUT = 3e3;
|
|
346
346
|
}
|
|
347
347
|
});
|
|
348
348
|
|
|
349
|
-
// node_modules/.pnpm/@agentcoordinationprotocol+sdk@
|
|
349
|
+
// node_modules/.pnpm/@agentcoordinationprotocol+sdk@0.1.0/node_modules/@agentcoordinationprotocol/sdk/dist/index.js
|
|
350
350
|
var init_dist = __esm({
|
|
351
|
-
"node_modules/.pnpm/@agentcoordinationprotocol+sdk@
|
|
351
|
+
"node_modules/.pnpm/@agentcoordinationprotocol+sdk@0.1.0/node_modules/@agentcoordinationprotocol/sdk/dist/index.js"() {
|
|
352
352
|
init_client();
|
|
353
353
|
}
|
|
354
354
|
});
|
|
@@ -361,9 +361,9 @@ __export(init_exports, {
|
|
|
361
361
|
import { createInterface } from "node:readline";
|
|
362
362
|
function prompt(rl, question, defaultVal) {
|
|
363
363
|
const suffix = defaultVal ? ` ${c("dim", `[${defaultVal}]`)}` : "";
|
|
364
|
-
return new Promise((
|
|
364
|
+
return new Promise((resolve3) => {
|
|
365
365
|
rl.question(` ${question}${suffix}: `, (answer) => {
|
|
366
|
-
|
|
366
|
+
resolve3(answer.trim() || defaultVal || "");
|
|
367
367
|
});
|
|
368
368
|
});
|
|
369
369
|
}
|
|
@@ -691,8 +691,8 @@ async function tryParseSpec(content) {
|
|
|
691
691
|
}
|
|
692
692
|
async function tryParseYaml(content) {
|
|
693
693
|
try {
|
|
694
|
-
const
|
|
695
|
-
const loadYaml =
|
|
694
|
+
const yaml3 = await import(JS_YAML);
|
|
695
|
+
const loadYaml = yaml3.load || yaml3.default?.load;
|
|
696
696
|
if (loadYaml) return loadYaml(content);
|
|
697
697
|
} catch {
|
|
698
698
|
}
|
|
@@ -1865,6 +1865,745 @@ var init_hooks_cmd = __esm({
|
|
|
1865
1865
|
}
|
|
1866
1866
|
});
|
|
1867
1867
|
|
|
1868
|
+
// src/brood.ts
|
|
1869
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5 } from "node:fs";
|
|
1870
|
+
import { join as join5, resolve } from "node:path";
|
|
1871
|
+
import yaml from "js-yaml";
|
|
1872
|
+
function normalizeStartOn(raw) {
|
|
1873
|
+
if (typeof raw === "string") {
|
|
1874
|
+
return {
|
|
1875
|
+
conditions: [{ event: raw, count: 1 }],
|
|
1876
|
+
timeout: DEFAULT_START_ON_TIMEOUT
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
const timeout = typeof raw.timeout === "number" ? raw.timeout : DEFAULT_START_ON_TIMEOUT;
|
|
1880
|
+
if (raw.all) {
|
|
1881
|
+
const conditions = raw.all.map((item) => {
|
|
1882
|
+
if (typeof item === "string") return { event: item, count: 1 };
|
|
1883
|
+
return { event: item.event, count: item.count ?? 1 };
|
|
1884
|
+
});
|
|
1885
|
+
return { conditions, timeout };
|
|
1886
|
+
}
|
|
1887
|
+
if (raw.event) {
|
|
1888
|
+
return {
|
|
1889
|
+
conditions: [{ event: raw.event, count: raw.count ?? 1 }],
|
|
1890
|
+
timeout
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
throw new Error("startOn must be a string, { event, count? }, or { all: [...] }");
|
|
1894
|
+
}
|
|
1895
|
+
function findBroodFile(fileArg) {
|
|
1896
|
+
if (fileArg) {
|
|
1897
|
+
const p = resolve(fileArg);
|
|
1898
|
+
return existsSync5(p) ? p : null;
|
|
1899
|
+
}
|
|
1900
|
+
for (const name of BROOD_FILES) {
|
|
1901
|
+
const p = join5(process.cwd(), name);
|
|
1902
|
+
if (existsSync5(p)) return p;
|
|
1903
|
+
}
|
|
1904
|
+
return null;
|
|
1905
|
+
}
|
|
1906
|
+
async function parseBroodFile(filePath) {
|
|
1907
|
+
const content = readFileSync5(filePath, "utf8");
|
|
1908
|
+
const raw = filePath.endsWith(".json") ? JSON.parse(content) : parseYaml(content);
|
|
1909
|
+
return validate2(raw);
|
|
1910
|
+
}
|
|
1911
|
+
function parseYaml(content) {
|
|
1912
|
+
return yaml.load(content);
|
|
1913
|
+
}
|
|
1914
|
+
function validate2(raw) {
|
|
1915
|
+
if (!raw || typeof raw !== "object") {
|
|
1916
|
+
throw new Error("brood file must be a YAML/JSON object");
|
|
1917
|
+
}
|
|
1918
|
+
const obj = raw;
|
|
1919
|
+
if (typeof obj.name !== "string" || !obj.name) {
|
|
1920
|
+
throw new Error('brood file requires a "name" field');
|
|
1921
|
+
}
|
|
1922
|
+
if (!obj.hives || typeof obj.hives !== "object") {
|
|
1923
|
+
throw new Error('brood file requires a "hives" map');
|
|
1924
|
+
}
|
|
1925
|
+
const hives = {};
|
|
1926
|
+
const hivesObj = obj.hives;
|
|
1927
|
+
for (const [name, value] of Object.entries(hivesObj)) {
|
|
1928
|
+
if (!value || typeof value !== "object") {
|
|
1929
|
+
throw new Error(`hive "${name}" must be an object`);
|
|
1930
|
+
}
|
|
1931
|
+
const hive = value;
|
|
1932
|
+
const config = {};
|
|
1933
|
+
if (hive.worktree !== void 0) {
|
|
1934
|
+
if (typeof hive.worktree !== "string") throw new Error(`hive "${name}".worktree must be a string`);
|
|
1935
|
+
config.worktree = hive.worktree;
|
|
1936
|
+
}
|
|
1937
|
+
const acpRaw = hive.acp ?? hive.spec ?? hive.protocol;
|
|
1938
|
+
if (acpRaw !== void 0) {
|
|
1939
|
+
if (typeof acpRaw === "string") {
|
|
1940
|
+
config.acp = acpRaw;
|
|
1941
|
+
} else if (typeof acpRaw === "object" && acpRaw !== null && !Array.isArray(acpRaw)) {
|
|
1942
|
+
config.acp = acpRaw;
|
|
1943
|
+
} else {
|
|
1944
|
+
throw new Error(`hive "${name}".acp must be a string (file/URL) or inline spec object`);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
if (hive.port !== void 0) {
|
|
1948
|
+
if (typeof hive.port !== "number") throw new Error(`hive "${name}".port must be a number`);
|
|
1949
|
+
config.port = hive.port;
|
|
1950
|
+
}
|
|
1951
|
+
const agentsRaw = hive.workers ?? hive.agents;
|
|
1952
|
+
if (agentsRaw !== void 0) {
|
|
1953
|
+
if (!Array.isArray(agentsRaw)) throw new Error(`hive "${name}".agents must be an array`);
|
|
1954
|
+
config.agents = agentsRaw.map((a, i) => {
|
|
1955
|
+
if (!a || typeof a !== "object") throw new Error(`hive "${name}".agents[${i}] must be an object`);
|
|
1956
|
+
const agent = a;
|
|
1957
|
+
if (typeof agent.role !== "string") throw new Error(`hive "${name}".agents[${i}].role must be a string`);
|
|
1958
|
+
let tools;
|
|
1959
|
+
if (agent.tools !== void 0) {
|
|
1960
|
+
if (agent.tools === "all") {
|
|
1961
|
+
tools = "all";
|
|
1962
|
+
} else if (Array.isArray(agent.tools) && agent.tools.every((t) => typeof t === "string")) {
|
|
1963
|
+
tools = agent.tools;
|
|
1964
|
+
} else {
|
|
1965
|
+
throw new Error(`hive "${name}".agents[${i}].tools must be 'all' or an array of strings`);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
let coordination;
|
|
1969
|
+
if (agent.coordination !== void 0) {
|
|
1970
|
+
if (typeof agent.coordination === "string" && ["lite", "full", "none"].includes(agent.coordination)) {
|
|
1971
|
+
coordination = agent.coordination;
|
|
1972
|
+
} else if (Array.isArray(agent.coordination) && agent.coordination.every((t) => typeof t === "string")) {
|
|
1973
|
+
coordination = agent.coordination;
|
|
1974
|
+
} else {
|
|
1975
|
+
throw new Error(`hive "${name}".agents[${i}].coordination must be 'lite', 'full', 'none', or an array of strings`);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
let agentType;
|
|
1979
|
+
if (agent.type !== void 0) {
|
|
1980
|
+
if (agent.type !== "worker" && agent.type !== "drone" && agent.type !== "claude") {
|
|
1981
|
+
throw new Error(`hive "${name}".agents[${i}].type must be 'worker', 'drone', or 'claude'`);
|
|
1982
|
+
}
|
|
1983
|
+
agentType = agent.type;
|
|
1984
|
+
}
|
|
1985
|
+
const startOn = agent.startOn !== void 0 ? agent.startOn : void 0;
|
|
1986
|
+
let wakeOn;
|
|
1987
|
+
if (agent.wake_on !== void 0) {
|
|
1988
|
+
if (!agent.wake_on || typeof agent.wake_on !== "object") {
|
|
1989
|
+
throw new Error(`hive "${name}".agents[${i}].wake_on must be an object`);
|
|
1990
|
+
}
|
|
1991
|
+
const wo = agent.wake_on;
|
|
1992
|
+
wakeOn = {
|
|
1993
|
+
types: Array.isArray(wo.types) ? wo.types.filter((t) => typeof t === "string") : void 0,
|
|
1994
|
+
timeout: typeof wo.timeout === "number" ? wo.timeout : void 0,
|
|
1995
|
+
max_wakes: typeof wo.max_wakes === "number" ? wo.max_wakes : void 0
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
return {
|
|
1999
|
+
role: agent.role,
|
|
2000
|
+
count: typeof agent.count === "number" ? agent.count : void 0,
|
|
2001
|
+
type: agentType,
|
|
2002
|
+
model_hint: typeof agent.model_hint === "string" ? agent.model_hint : void 0,
|
|
2003
|
+
prompt: typeof agent.prompt === "string" ? agent.prompt : void 0,
|
|
2004
|
+
pluginDir: typeof agent.plugin_dir === "string" ? agent.plugin_dir : void 0,
|
|
2005
|
+
tools,
|
|
2006
|
+
coordination,
|
|
2007
|
+
startOn,
|
|
2008
|
+
wake_on: wakeOn
|
|
2009
|
+
};
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
const honeycombRaw = hive.honeycomb ?? hive.comb;
|
|
2013
|
+
if (honeycombRaw !== void 0) {
|
|
2014
|
+
if (!honeycombRaw || typeof honeycombRaw !== "object") {
|
|
2015
|
+
throw new Error(`hive "${name}".honeycomb must be an object`);
|
|
2016
|
+
}
|
|
2017
|
+
const hc = honeycombRaw;
|
|
2018
|
+
config.honeycomb = {
|
|
2019
|
+
publishes: Array.isArray(hc.publishes) ? hc.publishes.filter((x) => typeof x === "string") : void 0,
|
|
2020
|
+
subscribes: Array.isArray(hc.subscribes) ? hc.subscribes.filter((x) => typeof x === "string") : void 0
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
const dancesRaw = hive.dances ?? hive.logic;
|
|
2024
|
+
if (dancesRaw !== void 0) {
|
|
2025
|
+
if (typeof dancesRaw !== "string") throw new Error(`hive "${name}".dances must be a string (file path)`);
|
|
2026
|
+
config.dances = dancesRaw;
|
|
2027
|
+
}
|
|
2028
|
+
hives[name] = config;
|
|
2029
|
+
}
|
|
2030
|
+
let provider;
|
|
2031
|
+
if (obj.provider !== void 0) {
|
|
2032
|
+
if (typeof obj.provider !== "string") throw new Error('"provider" must be a string (e.g. "ollama/qwen3:8b")');
|
|
2033
|
+
provider = obj.provider;
|
|
2034
|
+
}
|
|
2035
|
+
let models;
|
|
2036
|
+
if (obj.models !== void 0) {
|
|
2037
|
+
if (!obj.models || typeof obj.models !== "object" || Array.isArray(obj.models)) {
|
|
2038
|
+
throw new Error('"models" must be an object mapping role names to provider strings');
|
|
2039
|
+
}
|
|
2040
|
+
models = {};
|
|
2041
|
+
for (const [role, val] of Object.entries(obj.models)) {
|
|
2042
|
+
if (typeof val !== "string") throw new Error(`models.${role} must be a string`);
|
|
2043
|
+
models[role] = val;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
let env;
|
|
2047
|
+
if (obj.env !== void 0) {
|
|
2048
|
+
if (!obj.env || typeof obj.env !== "object" || Array.isArray(obj.env)) {
|
|
2049
|
+
throw new Error('"env" must be an object mapping variable names to string values');
|
|
2050
|
+
}
|
|
2051
|
+
env = {};
|
|
2052
|
+
for (const [key, val] of Object.entries(obj.env)) {
|
|
2053
|
+
env[key] = String(val);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
let stagger;
|
|
2057
|
+
if (obj.stagger !== void 0) {
|
|
2058
|
+
if (typeof obj.stagger !== "number" || obj.stagger < 0) {
|
|
2059
|
+
throw new Error('"stagger" must be a non-negative number (seconds between agent spawns)');
|
|
2060
|
+
}
|
|
2061
|
+
stagger = obj.stagger;
|
|
2062
|
+
}
|
|
2063
|
+
let dances;
|
|
2064
|
+
const dancesTopRaw = obj.dances ?? obj.logic;
|
|
2065
|
+
if (dancesTopRaw !== void 0) {
|
|
2066
|
+
if (typeof dancesTopRaw !== "string") throw new Error('"dances" must be a string (file path)');
|
|
2067
|
+
dances = dancesTopRaw;
|
|
2068
|
+
}
|
|
2069
|
+
return {
|
|
2070
|
+
name: obj.name,
|
|
2071
|
+
version: typeof obj.version === "string" ? obj.version : void 0,
|
|
2072
|
+
provider,
|
|
2073
|
+
models,
|
|
2074
|
+
env,
|
|
2075
|
+
stagger,
|
|
2076
|
+
dances,
|
|
2077
|
+
hives
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
var DEFAULT_START_ON_TIMEOUT, BROOD_FILES;
|
|
2081
|
+
var init_brood = __esm({
|
|
2082
|
+
"src/brood.ts"() {
|
|
2083
|
+
"use strict";
|
|
2084
|
+
DEFAULT_START_ON_TIMEOUT = 0;
|
|
2085
|
+
BROOD_FILES = ["brood.yaml", "brood.yml", "brood.json"];
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
// src/lib/ipc-broker.ts
|
|
2090
|
+
import { createServer } from "node:net";
|
|
2091
|
+
var IPCBroker;
|
|
2092
|
+
var init_ipc_broker = __esm({
|
|
2093
|
+
"src/lib/ipc-broker.ts"() {
|
|
2094
|
+
"use strict";
|
|
2095
|
+
IPCBroker = class {
|
|
2096
|
+
server = null;
|
|
2097
|
+
hives = /* @__PURE__ */ new Map();
|
|
2098
|
+
socketMap = /* @__PURE__ */ new Map();
|
|
2099
|
+
onHiveConnect;
|
|
2100
|
+
onHiveDisconnect;
|
|
2101
|
+
constructor(opts) {
|
|
2102
|
+
this.onHiveConnect = opts?.onHiveConnect;
|
|
2103
|
+
this.onHiveDisconnect = opts?.onHiveDisconnect;
|
|
2104
|
+
}
|
|
2105
|
+
async listen(socketPath) {
|
|
2106
|
+
return new Promise((resolve3, reject) => {
|
|
2107
|
+
const srv = createServer((socket) => this.onConnection(socket));
|
|
2108
|
+
srv.on("error", reject);
|
|
2109
|
+
srv.listen(socketPath, () => {
|
|
2110
|
+
this.server = srv;
|
|
2111
|
+
resolve3();
|
|
2112
|
+
});
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
async close() {
|
|
2116
|
+
for (const conn of this.hives.values()) {
|
|
2117
|
+
conn.socket.end();
|
|
2118
|
+
}
|
|
2119
|
+
this.hives.clear();
|
|
2120
|
+
this.socketMap.clear();
|
|
2121
|
+
if (this.server) {
|
|
2122
|
+
return new Promise((resolve3) => {
|
|
2123
|
+
this.server.close(() => resolve3());
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
getConnectedHives() {
|
|
2128
|
+
return [...this.hives.keys()];
|
|
2129
|
+
}
|
|
2130
|
+
onConnection(socket) {
|
|
2131
|
+
let buffer = "";
|
|
2132
|
+
socket.setEncoding("utf8");
|
|
2133
|
+
socket.on("data", (chunk) => {
|
|
2134
|
+
buffer += chunk;
|
|
2135
|
+
const lines = buffer.split("\n");
|
|
2136
|
+
buffer = lines.pop();
|
|
2137
|
+
for (const line of lines) {
|
|
2138
|
+
if (!line) continue;
|
|
2139
|
+
try {
|
|
2140
|
+
this.handleMessage(socket, JSON.parse(line));
|
|
2141
|
+
} catch {
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
socket.on("close", () => {
|
|
2146
|
+
const conn = this.socketMap.get(socket);
|
|
2147
|
+
if (conn) {
|
|
2148
|
+
this.hives.delete(conn.name);
|
|
2149
|
+
this.socketMap.delete(socket);
|
|
2150
|
+
this.onHiveDisconnect?.(conn.name);
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
socket.on("error", () => {
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
handleMessage(socket, msg2) {
|
|
2157
|
+
if (msg2.type === "register" && msg2.hive) {
|
|
2158
|
+
const conn = {
|
|
2159
|
+
name: msg2.hive,
|
|
2160
|
+
socket,
|
|
2161
|
+
subscribes: new Set(msg2.subscribes ?? [])
|
|
2162
|
+
};
|
|
2163
|
+
this.hives.set(msg2.hive, conn);
|
|
2164
|
+
this.socketMap.set(socket, conn);
|
|
2165
|
+
this.onHiveConnect?.(msg2.hive);
|
|
2166
|
+
} else if (msg2.type === "event" && msg2.hive && msg2.topic) {
|
|
2167
|
+
this.routeEvent(msg2.hive, msg2.topic, msg2.event);
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
routeEvent(sourceHive, topic, event) {
|
|
2171
|
+
for (const [name, conn] of this.hives) {
|
|
2172
|
+
if (name === sourceHive) continue;
|
|
2173
|
+
if (!conn.subscribes.has(topic)) continue;
|
|
2174
|
+
const forward = JSON.stringify({ type: "forward", topic, event }) + "\n";
|
|
2175
|
+
conn.socket.write(forward);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
|
|
2182
|
+
// src/commands/up.ts
|
|
2183
|
+
var up_exports = {};
|
|
2184
|
+
__export(up_exports, {
|
|
2185
|
+
up: () => up
|
|
2186
|
+
});
|
|
2187
|
+
import { spawn } from "node:child_process";
|
|
2188
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync4, existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6 } from "node:fs";
|
|
2189
|
+
import { join as join6, dirname as dirname2, resolve as resolve2 } from "node:path";
|
|
2190
|
+
import { tmpdir } from "node:os";
|
|
2191
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
2192
|
+
import { createRequire } from "node:module";
|
|
2193
|
+
import yaml2 from "js-yaml";
|
|
2194
|
+
function resolvePackage(pkg, cwd) {
|
|
2195
|
+
const bases = [
|
|
2196
|
+
join6(cwd, "__placeholder.js"),
|
|
2197
|
+
import.meta.url
|
|
2198
|
+
];
|
|
2199
|
+
for (const base of bases) {
|
|
2200
|
+
try {
|
|
2201
|
+
const req = createRequire(base);
|
|
2202
|
+
return req.resolve(pkg);
|
|
2203
|
+
} catch {
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
return null;
|
|
2207
|
+
}
|
|
2208
|
+
function stateDir() {
|
|
2209
|
+
return join6(process.cwd(), ".honeybee");
|
|
2210
|
+
}
|
|
2211
|
+
function stateFile() {
|
|
2212
|
+
return join6(stateDir(), "brood.state.json");
|
|
2213
|
+
}
|
|
2214
|
+
async function up(args2) {
|
|
2215
|
+
if (args2[0] === "--help" || args2[0] === "-h") {
|
|
2216
|
+
console.log(`
|
|
2217
|
+
${c("bold", "wgl up")} \u2014 start a local brood (multi-hive incubator cluster)
|
|
2218
|
+
|
|
2219
|
+
${c("cyan", "USAGE:")}
|
|
2220
|
+
wgl up [options]
|
|
2221
|
+
|
|
2222
|
+
${c("cyan", "OPTIONS:")}
|
|
2223
|
+
--file <path> Path to brood.yaml (default: auto-detect in cwd)
|
|
2224
|
+
-f <path> Alias for --file
|
|
2225
|
+
--base-port <N> Starting port for hives (default: 3100)
|
|
2226
|
+
--provider <str> LLM provider (e.g. cerebras/qwen-3-32b)
|
|
2227
|
+
--spec <path> ACP spec file path (no brood.yaml needed)
|
|
2228
|
+
--dances <path> Dance file path
|
|
2229
|
+
--no-acp Benchmark mode: LLM sees all coordination tools directly
|
|
2230
|
+
|
|
2231
|
+
${c("cyan", "DESCRIPTION:")}
|
|
2232
|
+
Reads brood.yaml, starts an IPC broker, spawns incubator processes
|
|
2233
|
+
per hive, and wires Honeycomb cross-hive event routing between them.
|
|
2234
|
+
|
|
2235
|
+
When hives define agents, incubator spawns Propolis (environment MCP
|
|
2236
|
+
server) and Drone (ReAct agent runtime) child processes within its hive.
|
|
2237
|
+
|
|
2238
|
+
Same brood.yaml works locally (IPC) and managed (Colony).
|
|
2239
|
+
|
|
2240
|
+
${c("cyan", "EXAMPLES:")}
|
|
2241
|
+
wgl up
|
|
2242
|
+
wgl up --file ./my-project/brood.yaml
|
|
2243
|
+
wgl up --base-port 4000
|
|
2244
|
+
`);
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
if (existsSync6(stateFile())) {
|
|
2248
|
+
console.log(error("A brood is already running"));
|
|
2249
|
+
console.log(c("dim", " Run `wgl down` to stop it first"));
|
|
2250
|
+
process.exit(1);
|
|
2251
|
+
}
|
|
2252
|
+
const fileIdx = args2.indexOf("--file");
|
|
2253
|
+
const fileArg = fileIdx !== -1 ? args2[fileIdx + 1] : void 0;
|
|
2254
|
+
const fIdx = args2.indexOf("-f");
|
|
2255
|
+
const fArg = fIdx !== -1 ? args2[fIdx + 1] : void 0;
|
|
2256
|
+
const basePortIdx = args2.indexOf("--base-port");
|
|
2257
|
+
const basePort = basePortIdx !== -1 ? parseInt(args2[basePortIdx + 1], 10) : 3100;
|
|
2258
|
+
const noAcp = args2.includes("--no-acp");
|
|
2259
|
+
const providerIdx = args2.indexOf("--provider");
|
|
2260
|
+
const providerArg = providerIdx !== -1 ? args2[providerIdx + 1] : void 0;
|
|
2261
|
+
const specIdx = args2.indexOf("--spec");
|
|
2262
|
+
const specArg = specIdx !== -1 ? args2[specIdx + 1] : void 0;
|
|
2263
|
+
const dancesIdx = args2.indexOf("--dances");
|
|
2264
|
+
const dancesArg = dancesIdx !== -1 ? args2[dancesIdx + 1] : void 0;
|
|
2265
|
+
const provider = providerArg ?? process.env.WAGGLE_PROVIDER ?? void 0;
|
|
2266
|
+
const specPath = specArg ?? process.env.WAGGLE_SPEC ?? void 0;
|
|
2267
|
+
const dancesPath = dancesArg ?? process.env.WAGGLE_DANCES ?? void 0;
|
|
2268
|
+
let broodPath = findBroodFile(fArg ?? fileArg);
|
|
2269
|
+
let config;
|
|
2270
|
+
if (broodPath) {
|
|
2271
|
+
try {
|
|
2272
|
+
config = await parseBroodFile(broodPath);
|
|
2273
|
+
} catch (err) {
|
|
2274
|
+
console.log(error(`Invalid brood file: ${err.message}`));
|
|
2275
|
+
process.exit(1);
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
} else if (specPath) {
|
|
2279
|
+
const specName = specPath.replace(/\.(acp|yaml|yml|json)$/i, "").split("/").pop() ?? "default";
|
|
2280
|
+
config = {
|
|
2281
|
+
name: specName,
|
|
2282
|
+
provider: provider ?? "ollama/qwen3:8b",
|
|
2283
|
+
dances: dancesPath,
|
|
2284
|
+
hives: {
|
|
2285
|
+
[specName]: {
|
|
2286
|
+
acp: specPath,
|
|
2287
|
+
dances: dancesPath
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
};
|
|
2291
|
+
broodPath = join6(process.cwd(), "brood.yaml");
|
|
2292
|
+
} else {
|
|
2293
|
+
console.log(error("No brood.yaml found and no --spec provided"));
|
|
2294
|
+
console.log(c("dim", " Create a brood.yaml or pass --spec <path>"));
|
|
2295
|
+
process.exit(1);
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
const hiveNames = Object.keys(config.hives);
|
|
2299
|
+
if (hiveNames.length === 0) {
|
|
2300
|
+
console.log(error("brood.yaml has no hives defined"));
|
|
2301
|
+
process.exit(1);
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
const hivesWithAgents = hiveNames.filter((n) => (config.hives[n].agents?.length ?? 0) > 0);
|
|
2305
|
+
const needsHivePackage = hivesWithAgents.some(
|
|
2306
|
+
(n) => config.hives[n].agents?.some((a) => !a.type || a.type === "worker" || a.type === "drone")
|
|
2307
|
+
);
|
|
2308
|
+
const cwd = process.cwd();
|
|
2309
|
+
const incubatorEntry = resolvePackage(INCUBATOR_PKG, cwd);
|
|
2310
|
+
if (!incubatorEntry) {
|
|
2311
|
+
console.log(error("Incubator not installed"));
|
|
2312
|
+
console.log(`
|
|
2313
|
+
Install it with:
|
|
2314
|
+
${c("cyan", "npm install @honeybee-ai/incubator")}
|
|
2315
|
+
`);
|
|
2316
|
+
process.exit(1);
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
let hiveEntry = null;
|
|
2320
|
+
if (needsHivePackage) {
|
|
2321
|
+
hiveEntry = resolvePackage(HIVE_PKG, cwd);
|
|
2322
|
+
if (!hiveEntry) {
|
|
2323
|
+
console.log(error("Hive not installed (required for worker/drone agents)"));
|
|
2324
|
+
console.log(`
|
|
2325
|
+
Install it with:
|
|
2326
|
+
${c("cyan", "npm install @honeybee-ai/hive")}
|
|
2327
|
+
`);
|
|
2328
|
+
process.exit(1);
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
const baseEnv = {
|
|
2333
|
+
...process.env,
|
|
2334
|
+
...config.env
|
|
2335
|
+
};
|
|
2336
|
+
console.log(heading(`Starting brood: ${config.name}`));
|
|
2337
|
+
console.log(label("File", broodPath));
|
|
2338
|
+
console.log(label("Hives", hiveNames.join(", ")));
|
|
2339
|
+
if (provider && broodPath) {
|
|
2340
|
+
config.provider = provider;
|
|
2341
|
+
}
|
|
2342
|
+
if (config.provider) console.log(label("Provider", config.provider));
|
|
2343
|
+
if (config.env) console.log(label("Env", Object.keys(config.env).join(", ")));
|
|
2344
|
+
if (hivesWithAgents.length > 0) console.log(label("Agent hives", hivesWithAgents.join(", ")));
|
|
2345
|
+
if (noAcp) console.log(label("Mode", "no-acp (benchmark \u2014 LLM sees coordination tools)"));
|
|
2346
|
+
console.log();
|
|
2347
|
+
const broodId = randomBytes2(4).toString("hex");
|
|
2348
|
+
const socketDir = join6(tmpdir(), `honeybee-brood-${broodId}`);
|
|
2349
|
+
mkdirSync2(socketDir, { recursive: true });
|
|
2350
|
+
const socketPath = join6(socketDir, "broker.sock");
|
|
2351
|
+
const broker = new IPCBroker({
|
|
2352
|
+
onHiveConnect: (name) => console.log(success(`Hive "${name}" connected to broker`)),
|
|
2353
|
+
onHiveDisconnect: (name) => console.log(warn(`Hive "${name}" disconnected`))
|
|
2354
|
+
});
|
|
2355
|
+
await broker.listen(socketPath);
|
|
2356
|
+
console.log(success("IPC broker started"));
|
|
2357
|
+
const children = /* @__PURE__ */ new Map();
|
|
2358
|
+
const hiveState = {};
|
|
2359
|
+
let port = basePort;
|
|
2360
|
+
let propolisPort = basePort + 100;
|
|
2361
|
+
for (const [name, hive] of Object.entries(config.hives)) {
|
|
2362
|
+
const hivePort = hive.port ?? port++;
|
|
2363
|
+
const hiveCwd = hive.worktree ? resolve2(dirname2(broodPath), hive.worktree) : dirname2(broodPath);
|
|
2364
|
+
const protocolPath = resolveProtocol(hive, broodPath, name);
|
|
2365
|
+
const incubatorArgs = ["--http", `--port=${hivePort}`];
|
|
2366
|
+
if (protocolPath) {
|
|
2367
|
+
incubatorArgs.push(`--protocol=${protocolPath}`);
|
|
2368
|
+
}
|
|
2369
|
+
const dancesField = dancesPath ?? hive.dances ?? config.dances;
|
|
2370
|
+
if (dancesField) {
|
|
2371
|
+
const resolvedDances = resolve2(dirname2(broodPath), dancesField);
|
|
2372
|
+
incubatorArgs.push(`--dances=${resolvedDances}`);
|
|
2373
|
+
}
|
|
2374
|
+
const hiveAgents = hive.agents?.length ? hive.agents : deriveAgentsFromSpec(protocolPath);
|
|
2375
|
+
if (hiveAgents.length) {
|
|
2376
|
+
const pPort = propolisPort++;
|
|
2377
|
+
const worktreePath = hive.worktree ? resolve2(dirname2(broodPath), hive.worktree) : resolve2(dirname2(broodPath));
|
|
2378
|
+
const agentsConfig = {
|
|
2379
|
+
provider: config.provider ?? "ollama/qwen3:8b",
|
|
2380
|
+
stagger: config.stagger ?? 2,
|
|
2381
|
+
noAcp,
|
|
2382
|
+
propolisPort: pPort,
|
|
2383
|
+
worktree: worktreePath,
|
|
2384
|
+
hiveEntry: hiveEntry ?? "",
|
|
2385
|
+
...protocolPath ? { protocolPath } : {},
|
|
2386
|
+
agents: hiveAgents.map((a) => ({
|
|
2387
|
+
role: a.role,
|
|
2388
|
+
count: a.count,
|
|
2389
|
+
type: a.type,
|
|
2390
|
+
tools: a.tools,
|
|
2391
|
+
coordination: a.coordination,
|
|
2392
|
+
modelHint: a.model_hint ?? null,
|
|
2393
|
+
prompt: a.prompt ?? null,
|
|
2394
|
+
startOn: a.startOn ? normalizeStartOn(a.startOn) : null,
|
|
2395
|
+
wakeOn: a.wake_on ? {
|
|
2396
|
+
types: a.wake_on.types ?? null,
|
|
2397
|
+
timeout: a.wake_on.timeout ?? 0,
|
|
2398
|
+
maxWakes: a.wake_on.max_wakes ?? 0
|
|
2399
|
+
} : null
|
|
2400
|
+
})),
|
|
2401
|
+
models: config.models,
|
|
2402
|
+
env: config.env
|
|
2403
|
+
};
|
|
2404
|
+
incubatorArgs.push(`--agents=${JSON.stringify(agentsConfig)}`);
|
|
2405
|
+
incubatorArgs.push("--verbose");
|
|
2406
|
+
const workerCount = hiveAgents.filter((a) => !a.type || a.type === "worker").reduce((sum, a) => sum + (a.count ?? 1), 0);
|
|
2407
|
+
const droneCount = hiveAgents.filter((a) => a.type === "drone").reduce((sum, a) => sum + (a.count ?? 1), 0);
|
|
2408
|
+
const claudeCount = hiveAgents.filter((a) => a.type === "claude").reduce((sum, a) => sum + (a.count ?? 1), 0);
|
|
2409
|
+
const parts = [];
|
|
2410
|
+
if (workerCount > 0) parts.push(`${workerCount} worker${workerCount !== 1 ? "s" : ""}`);
|
|
2411
|
+
if (droneCount > 0) parts.push(`${droneCount} drone${droneCount !== 1 ? "s" : ""}`);
|
|
2412
|
+
if (claudeCount > 0) parts.push(`${claudeCount} claude${claudeCount !== 1 ? "s" : ""}`);
|
|
2413
|
+
console.log(label(`${name}/agents`, `${parts.join(" + ")} (delegated to incubator)`));
|
|
2414
|
+
}
|
|
2415
|
+
const env = {
|
|
2416
|
+
...baseEnv,
|
|
2417
|
+
HONEYCOMB_BROKER_SOCKET: socketPath,
|
|
2418
|
+
HONEYCOMB_HIVE_NAME: name
|
|
2419
|
+
};
|
|
2420
|
+
if (hive.honeycomb?.publishes?.length) {
|
|
2421
|
+
env["HONEYCOMB_PUBLISHES"] = hive.honeycomb.publishes.join(",");
|
|
2422
|
+
}
|
|
2423
|
+
if (hive.honeycomb?.subscribes?.length) {
|
|
2424
|
+
env["HONEYCOMB_SUBSCRIBES"] = hive.honeycomb.subscribes.join(",");
|
|
2425
|
+
}
|
|
2426
|
+
const incChild = spawn(process.execPath, [incubatorEntry, ...incubatorArgs], {
|
|
2427
|
+
env,
|
|
2428
|
+
cwd: hiveCwd,
|
|
2429
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2430
|
+
});
|
|
2431
|
+
incChild.stderr?.on("data", (data) => {
|
|
2432
|
+
const line = data.toString().trim();
|
|
2433
|
+
if (line) console.log(c("dim", `[${name}] ${line}`));
|
|
2434
|
+
});
|
|
2435
|
+
incChild.on("exit", (code) => {
|
|
2436
|
+
children.delete(`incubator:${name}`);
|
|
2437
|
+
if (code !== null && code !== 0) {
|
|
2438
|
+
console.log(warn(`Hive "${name}" incubator exited with code ${code}`));
|
|
2439
|
+
}
|
|
2440
|
+
});
|
|
2441
|
+
if (incChild.pid) {
|
|
2442
|
+
children.set(`incubator:${name}`, incChild);
|
|
2443
|
+
hiveState[name] = { pid: incChild.pid, port: hivePort };
|
|
2444
|
+
console.log(label(name, `incubator port ${hivePort} (pid ${incChild.pid})`));
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
2448
|
+
const state2 = {
|
|
2449
|
+
name: config.name,
|
|
2450
|
+
socketPath,
|
|
2451
|
+
hives: hiveState,
|
|
2452
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2453
|
+
};
|
|
2454
|
+
writeFileSync4(stateFile(), JSON.stringify(state2, null, 2));
|
|
2455
|
+
console.log();
|
|
2456
|
+
console.log(success(`Brood "${config.name}" running (${hiveNames.length} hive${hiveNames.length !== 1 ? "s" : ""})`));
|
|
2457
|
+
console.log(c("dim", " Press Ctrl+C or run `wgl down` to stop"));
|
|
2458
|
+
const shutdown = async () => {
|
|
2459
|
+
console.log("\n" + c("dim", "Shutting down..."));
|
|
2460
|
+
for (const [key, child] of children) {
|
|
2461
|
+
child.kill("SIGTERM");
|
|
2462
|
+
console.log(c("dim", ` Stopped ${key}`));
|
|
2463
|
+
}
|
|
2464
|
+
await broker.close();
|
|
2465
|
+
try {
|
|
2466
|
+
unlinkSync2(socketPath);
|
|
2467
|
+
} catch {
|
|
2468
|
+
}
|
|
2469
|
+
try {
|
|
2470
|
+
unlinkSync2(stateFile());
|
|
2471
|
+
} catch {
|
|
2472
|
+
}
|
|
2473
|
+
console.log(success("Brood stopped"));
|
|
2474
|
+
process.exit(0);
|
|
2475
|
+
};
|
|
2476
|
+
process.on("SIGINT", shutdown);
|
|
2477
|
+
process.on("SIGTERM", shutdown);
|
|
2478
|
+
await new Promise(() => {
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
function deriveAgentsFromSpec(protocolPath) {
|
|
2482
|
+
if (!protocolPath || protocolPath.startsWith("http://") || protocolPath.startsWith("https://")) return [];
|
|
2483
|
+
try {
|
|
2484
|
+
const raw = readFileSync6(protocolPath, "utf-8");
|
|
2485
|
+
const spec = protocolPath.endsWith(".json") ? JSON.parse(raw) : yaml2.load(raw);
|
|
2486
|
+
const roles = spec.roles;
|
|
2487
|
+
if (!roles) return [];
|
|
2488
|
+
const agents = [];
|
|
2489
|
+
for (const [roleName, roleDef] of Object.entries(roles)) {
|
|
2490
|
+
const count = typeof roleDef.agents === "number" ? roleDef.agents : 1;
|
|
2491
|
+
for (let i = 0; i < count; i++) {
|
|
2492
|
+
agents.push({ role: roleName });
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
return agents;
|
|
2496
|
+
} catch {
|
|
2497
|
+
return [];
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
function resolveProtocol(hive, broodPath, hiveName) {
|
|
2501
|
+
const acpField = hive.acp ?? hive.protocol;
|
|
2502
|
+
if (!acpField) return void 0;
|
|
2503
|
+
if (typeof acpField === "string") {
|
|
2504
|
+
if (acpField.startsWith("http://") || acpField.startsWith("https://")) {
|
|
2505
|
+
return acpField;
|
|
2506
|
+
}
|
|
2507
|
+
return resolve2(dirname2(broodPath), acpField);
|
|
2508
|
+
}
|
|
2509
|
+
const tempDir = join6(tmpdir(), `honeybee-protocol-${randomBytes2(4).toString("hex")}`);
|
|
2510
|
+
mkdirSync2(tempDir, { recursive: true });
|
|
2511
|
+
const tempPath = join6(tempDir, `${hiveName}.acp.json`);
|
|
2512
|
+
writeFileSync4(tempPath, JSON.stringify(acpField, null, 2));
|
|
2513
|
+
return tempPath;
|
|
2514
|
+
}
|
|
2515
|
+
var INCUBATOR_PKG, HIVE_PKG;
|
|
2516
|
+
var init_up = __esm({
|
|
2517
|
+
"src/commands/up.ts"() {
|
|
2518
|
+
"use strict";
|
|
2519
|
+
init_format();
|
|
2520
|
+
init_brood();
|
|
2521
|
+
init_ipc_broker();
|
|
2522
|
+
INCUBATOR_PKG = "@honeybee-ai/incubator";
|
|
2523
|
+
HIVE_PKG = "@honeybee-ai/hive";
|
|
2524
|
+
}
|
|
2525
|
+
});
|
|
2526
|
+
|
|
2527
|
+
// src/commands/down.ts
|
|
2528
|
+
var down_exports = {};
|
|
2529
|
+
__export(down_exports, {
|
|
2530
|
+
down: () => down
|
|
2531
|
+
});
|
|
2532
|
+
import { readFileSync as readFileSync7, existsSync as existsSync7, unlinkSync as unlinkSync3, rmSync } from "node:fs";
|
|
2533
|
+
import { join as join7 } from "node:path";
|
|
2534
|
+
function stateFile2() {
|
|
2535
|
+
return join7(process.cwd(), ".honeybee", "brood.state.json");
|
|
2536
|
+
}
|
|
2537
|
+
async function down(args2) {
|
|
2538
|
+
if (args2[0] === "--help" || args2[0] === "-h") {
|
|
2539
|
+
console.log(`
|
|
2540
|
+
${c("bold", "wgl down")} \u2014 stop a running brood
|
|
2541
|
+
|
|
2542
|
+
${c("cyan", "USAGE:")}
|
|
2543
|
+
wgl down
|
|
2544
|
+
|
|
2545
|
+
${c("cyan", "DESCRIPTION:")}
|
|
2546
|
+
Reads .honeybee/brood.state.json, sends SIGTERM to all incubator
|
|
2547
|
+
processes (which clean up their own propolis + drone children),
|
|
2548
|
+
removes the broker socket, and deletes the state file.
|
|
2549
|
+
|
|
2550
|
+
${c("cyan", "EXAMPLES:")}
|
|
2551
|
+
wgl down
|
|
2552
|
+
`);
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
const path = stateFile2();
|
|
2556
|
+
if (!existsSync7(path)) {
|
|
2557
|
+
console.log(error("No running brood found"));
|
|
2558
|
+
console.log(c("dim", " No .honeybee/brood.state.json in current directory"));
|
|
2559
|
+
process.exit(1);
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
let state2;
|
|
2563
|
+
try {
|
|
2564
|
+
state2 = JSON.parse(readFileSync7(path, "utf8"));
|
|
2565
|
+
} catch {
|
|
2566
|
+
console.log(error("Corrupt state file"));
|
|
2567
|
+
process.exit(1);
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
console.log(heading(`Stopping brood: ${state2.name}`));
|
|
2571
|
+
let stopped = 0;
|
|
2572
|
+
for (const [name, info4] of Object.entries(state2.hives)) {
|
|
2573
|
+
try {
|
|
2574
|
+
process.kill(info4.pid, "SIGTERM");
|
|
2575
|
+
console.log(label(name, `incubator stopped (pid ${info4.pid})`));
|
|
2576
|
+
stopped++;
|
|
2577
|
+
} catch {
|
|
2578
|
+
console.log(label(name, c("dim", `not running (pid ${info4.pid})`)));
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
if (state2.socketPath) {
|
|
2582
|
+
try {
|
|
2583
|
+
unlinkSync3(state2.socketPath);
|
|
2584
|
+
} catch {
|
|
2585
|
+
}
|
|
2586
|
+
const { dirname: dirname4 } = await import("node:path");
|
|
2587
|
+
try {
|
|
2588
|
+
rmSync(dirname4(state2.socketPath), { recursive: true, force: true });
|
|
2589
|
+
} catch {
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
try {
|
|
2593
|
+
unlinkSync3(path);
|
|
2594
|
+
} catch {
|
|
2595
|
+
}
|
|
2596
|
+
const hiveCount = Object.keys(state2.hives).length;
|
|
2597
|
+
console.log();
|
|
2598
|
+
console.log(success(`Brood stopped (${hiveCount} hive${hiveCount !== 1 ? "s" : ""} terminated)`));
|
|
2599
|
+
}
|
|
2600
|
+
var init_down = __esm({
|
|
2601
|
+
"src/commands/down.ts"() {
|
|
2602
|
+
"use strict";
|
|
2603
|
+
init_format();
|
|
2604
|
+
}
|
|
2605
|
+
});
|
|
2606
|
+
|
|
1868
2607
|
// src/commands/serve.ts
|
|
1869
2608
|
var serve_exports = {};
|
|
1870
2609
|
__export(serve_exports, {
|
|
@@ -1944,18 +2683,18 @@ var init_serve = __esm({
|
|
|
1944
2683
|
});
|
|
1945
2684
|
|
|
1946
2685
|
// src/lib/global-config.ts
|
|
1947
|
-
import { readFileSync as
|
|
1948
|
-
import { join as
|
|
2686
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "node:fs";
|
|
2687
|
+
import { join as join8 } from "node:path";
|
|
1949
2688
|
import { homedir } from "node:os";
|
|
1950
2689
|
function ensureDir() {
|
|
1951
|
-
if (!
|
|
1952
|
-
|
|
2690
|
+
if (!existsSync8(WGL_DIR)) {
|
|
2691
|
+
mkdirSync3(WGL_DIR, { recursive: true });
|
|
1953
2692
|
}
|
|
1954
2693
|
}
|
|
1955
2694
|
function loadGlobalConfig() {
|
|
1956
|
-
if (!
|
|
2695
|
+
if (!existsSync8(CONFIG_PATH)) return { ...DEFAULTS };
|
|
1957
2696
|
try {
|
|
1958
|
-
const raw = JSON.parse(
|
|
2697
|
+
const raw = JSON.parse(readFileSync8(CONFIG_PATH, "utf8"));
|
|
1959
2698
|
return { ...DEFAULTS, ...raw };
|
|
1960
2699
|
} catch {
|
|
1961
2700
|
return { ...DEFAULTS };
|
|
@@ -1963,7 +2702,7 @@ function loadGlobalConfig() {
|
|
|
1963
2702
|
}
|
|
1964
2703
|
function saveGlobalConfig(config) {
|
|
1965
2704
|
ensureDir();
|
|
1966
|
-
|
|
2705
|
+
writeFileSync5(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
1967
2706
|
}
|
|
1968
2707
|
function setGlobalConfigValue(key, value) {
|
|
1969
2708
|
const config = loadGlobalConfig();
|
|
@@ -1974,8 +2713,8 @@ var WGL_DIR, CONFIG_PATH, DEFAULTS;
|
|
|
1974
2713
|
var init_global_config = __esm({
|
|
1975
2714
|
"src/lib/global-config.ts"() {
|
|
1976
2715
|
"use strict";
|
|
1977
|
-
WGL_DIR =
|
|
1978
|
-
CONFIG_PATH =
|
|
2716
|
+
WGL_DIR = join8(homedir(), ".wgl");
|
|
2717
|
+
CONFIG_PATH = join8(WGL_DIR, "config.json");
|
|
1979
2718
|
DEFAULTS = {
|
|
1980
2719
|
defaultPlatform: "https://hivemind.honeyb.dev",
|
|
1981
2720
|
defaultRole: "developer",
|
|
@@ -1985,11 +2724,11 @@ var init_global_config = __esm({
|
|
|
1985
2724
|
}
|
|
1986
2725
|
});
|
|
1987
2726
|
|
|
1988
|
-
//
|
|
2727
|
+
// ../sdk/dist/http.js
|
|
1989
2728
|
import { request as httpRequest2 } from "node:http";
|
|
1990
2729
|
import { request as httpsRequest2 } from "node:https";
|
|
1991
2730
|
function httpReq(method, url, body, headers = {}) {
|
|
1992
|
-
return new Promise((
|
|
2731
|
+
return new Promise((resolve3, reject) => {
|
|
1993
2732
|
const parsed = new URL(url);
|
|
1994
2733
|
const isHttps = parsed.protocol === "https:";
|
|
1995
2734
|
const reqFn = isHttps ? httpsRequest2 : httpRequest2;
|
|
@@ -2006,13 +2745,13 @@ function httpReq(method, url, body, headers = {}) {
|
|
|
2006
2745
|
res.on("end", () => {
|
|
2007
2746
|
try {
|
|
2008
2747
|
const parsed2 = data ? JSON.parse(data) : {};
|
|
2009
|
-
|
|
2748
|
+
resolve3({
|
|
2010
2749
|
ok: res.statusCode >= 200 && res.statusCode < 300,
|
|
2011
2750
|
status: res.statusCode,
|
|
2012
2751
|
data: parsed2
|
|
2013
2752
|
});
|
|
2014
2753
|
} catch {
|
|
2015
|
-
|
|
2754
|
+
resolve3({ ok: false, status: res.statusCode, data: {} });
|
|
2016
2755
|
}
|
|
2017
2756
|
});
|
|
2018
2757
|
});
|
|
@@ -2028,28 +2767,30 @@ function httpReq(method, url, body, headers = {}) {
|
|
|
2028
2767
|
}
|
|
2029
2768
|
var TIMEOUT2;
|
|
2030
2769
|
var init_http = __esm({
|
|
2031
|
-
"
|
|
2770
|
+
"../sdk/dist/http.js"() {
|
|
2771
|
+
"use strict";
|
|
2032
2772
|
TIMEOUT2 = 1e4;
|
|
2033
2773
|
}
|
|
2034
2774
|
});
|
|
2035
2775
|
|
|
2036
|
-
//
|
|
2037
|
-
import { readFileSync as
|
|
2038
|
-
import { join as
|
|
2776
|
+
// ../sdk/dist/auth.js
|
|
2777
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync4, chmodSync } from "node:fs";
|
|
2778
|
+
import { join as join9 } from "node:path";
|
|
2039
2779
|
import { homedir as homedir2 } from "node:os";
|
|
2040
2780
|
function loadAuthStore() {
|
|
2041
|
-
if (!
|
|
2781
|
+
if (!existsSync9(AUTH_PATH))
|
|
2042
2782
|
return { profiles: {} };
|
|
2043
2783
|
try {
|
|
2044
|
-
return JSON.parse(
|
|
2784
|
+
return JSON.parse(readFileSync9(AUTH_PATH, "utf8"));
|
|
2045
2785
|
} catch {
|
|
2046
2786
|
return { profiles: {} };
|
|
2047
2787
|
}
|
|
2048
2788
|
}
|
|
2049
2789
|
function saveAuthStore(store) {
|
|
2050
|
-
if (!
|
|
2051
|
-
|
|
2052
|
-
|
|
2790
|
+
if (!existsSync9(WGL_DIR2))
|
|
2791
|
+
mkdirSync4(WGL_DIR2, { recursive: true });
|
|
2792
|
+
writeFileSync6(AUTH_PATH, JSON.stringify(store, null, 2) + "\n", { mode: 384 });
|
|
2793
|
+
chmodSync(AUTH_PATH, 384);
|
|
2053
2794
|
}
|
|
2054
2795
|
function getActiveProfile(profileName) {
|
|
2055
2796
|
const store = loadAuthStore();
|
|
@@ -2134,15 +2875,16 @@ async function refreshToken(platform, refreshTokenValue) {
|
|
|
2134
2875
|
}
|
|
2135
2876
|
var WGL_DIR2, AUTH_PATH, GITHUB_CLIENT_ID;
|
|
2136
2877
|
var init_auth = __esm({
|
|
2137
|
-
"
|
|
2878
|
+
"../sdk/dist/auth.js"() {
|
|
2879
|
+
"use strict";
|
|
2138
2880
|
init_http();
|
|
2139
|
-
WGL_DIR2 =
|
|
2140
|
-
AUTH_PATH =
|
|
2881
|
+
WGL_DIR2 = join9(homedir2(), ".wgl");
|
|
2882
|
+
AUTH_PATH = join9(WGL_DIR2, "auth.json");
|
|
2141
2883
|
GITHUB_CLIENT_ID = "Ov23liy8H1qGZdVAk1Vr";
|
|
2142
2884
|
}
|
|
2143
2885
|
});
|
|
2144
2886
|
|
|
2145
|
-
//
|
|
2887
|
+
// ../sdk/dist/platform.js
|
|
2146
2888
|
function createPlatformClient(options) {
|
|
2147
2889
|
const profileName = options?.profileName || "personal";
|
|
2148
2890
|
const maybeProfile = getActiveProfile(profileName);
|
|
@@ -2154,9 +2896,8 @@ function createPlatformClient(options) {
|
|
|
2154
2896
|
const platformUrl = new URL(platform);
|
|
2155
2897
|
const apiBase = `${platformUrl.protocol}//api.${platformUrl.host}/rest/v1`;
|
|
2156
2898
|
let accessToken = profile.accessToken;
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
return;
|
|
2899
|
+
let refreshPromise = null;
|
|
2900
|
+
async function doRefresh() {
|
|
2160
2901
|
try {
|
|
2161
2902
|
const tokens = await refreshToken(profile.platform, profile.refreshToken);
|
|
2162
2903
|
accessToken = tokens.access_token;
|
|
@@ -2170,7 +2911,17 @@ function createPlatformClient(options) {
|
|
|
2170
2911
|
});
|
|
2171
2912
|
} catch {
|
|
2172
2913
|
throw new Error("Session expired. Run `wgl auth login` to re-authenticate.");
|
|
2914
|
+
} finally {
|
|
2915
|
+
refreshPromise = null;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
async function ensureValidToken() {
|
|
2919
|
+
if (!isTokenExpired(profile))
|
|
2920
|
+
return;
|
|
2921
|
+
if (!refreshPromise) {
|
|
2922
|
+
refreshPromise = doRefresh();
|
|
2173
2923
|
}
|
|
2924
|
+
return refreshPromise;
|
|
2174
2925
|
}
|
|
2175
2926
|
function fetch(method, path, body, skipAuth = false) {
|
|
2176
2927
|
const url = `${apiBase}${path}`;
|
|
@@ -2184,21 +2935,11 @@ function createPlatformClient(options) {
|
|
|
2184
2935
|
await ensureValidToken();
|
|
2185
2936
|
const res = await fetch(method, path, body);
|
|
2186
2937
|
if (res.status === 401) {
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
accessToken = tokens.access_token;
|
|
2190
|
-
setProfile(profileName, {
|
|
2191
|
-
platform: profile.platform,
|
|
2192
|
-
email: profile.email,
|
|
2193
|
-
org: profile.org,
|
|
2194
|
-
accessToken: tokens.access_token,
|
|
2195
|
-
refreshToken: tokens.refresh_token,
|
|
2196
|
-
expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
|
|
2197
|
-
});
|
|
2198
|
-
return fetch(method, path, body);
|
|
2199
|
-
} catch {
|
|
2200
|
-
throw new Error("Session expired. Run `wgl auth login` to re-authenticate.");
|
|
2938
|
+
if (!refreshPromise) {
|
|
2939
|
+
refreshPromise = doRefresh();
|
|
2201
2940
|
}
|
|
2941
|
+
await refreshPromise;
|
|
2942
|
+
return fetch(method, path, body);
|
|
2202
2943
|
}
|
|
2203
2944
|
return res;
|
|
2204
2945
|
}
|
|
@@ -2284,20 +3025,34 @@ function createPlatformClient(options) {
|
|
|
2284
3025
|
listCarapaceKeys: () => authedFetch("GET", "/carapace/dashboard/keys"),
|
|
2285
3026
|
createCarapaceKey: (name, mode) => authedFetch("POST", "/carapace/dashboard/keys", { name, mode }),
|
|
2286
3027
|
deleteCarapaceKey: (id) => authedFetch("DELETE", `/carapace/dashboard/keys/${encodeURIComponent(id)}`),
|
|
3028
|
+
// --- Telemetry ---
|
|
3029
|
+
telemetryOverview: (days) => authedFetch("GET", `/carapace/api/telemetry/overview${days ? "?days=" + days : ""}`),
|
|
3030
|
+
telemetryTimeline: (days) => authedFetch("GET", `/carapace/api/telemetry/timeline${days ? "?days=" + days : ""}`),
|
|
3031
|
+
telemetryEvents: (opts) => {
|
|
3032
|
+
const params = new URLSearchParams();
|
|
3033
|
+
if (opts?.limit)
|
|
3034
|
+
params.set("limit", String(opts.limit));
|
|
3035
|
+
if (opts?.offset)
|
|
3036
|
+
params.set("offset", String(opts.offset));
|
|
3037
|
+
const qs = params.toString();
|
|
3038
|
+
return authedFetch("GET", `/carapace/api/telemetry/events${qs ? "?" + qs : ""}`);
|
|
3039
|
+
},
|
|
2287
3040
|
// --- Auth ---
|
|
2288
3041
|
getMe: () => authedFetch("GET", "/auth/me")
|
|
2289
3042
|
};
|
|
2290
3043
|
}
|
|
2291
3044
|
var init_platform = __esm({
|
|
2292
|
-
"
|
|
3045
|
+
"../sdk/dist/platform.js"() {
|
|
3046
|
+
"use strict";
|
|
2293
3047
|
init_http();
|
|
2294
3048
|
init_auth();
|
|
2295
3049
|
}
|
|
2296
3050
|
});
|
|
2297
3051
|
|
|
2298
|
-
//
|
|
3052
|
+
// ../sdk/dist/index.js
|
|
2299
3053
|
var init_dist2 = __esm({
|
|
2300
|
-
"
|
|
3054
|
+
"../sdk/dist/index.js"() {
|
|
3055
|
+
"use strict";
|
|
2301
3056
|
init_platform();
|
|
2302
3057
|
init_auth();
|
|
2303
3058
|
}
|
|
@@ -2545,7 +3300,7 @@ var marketplace_exports = {};
|
|
|
2545
3300
|
__export(marketplace_exports, {
|
|
2546
3301
|
marketplace: () => marketplace
|
|
2547
3302
|
});
|
|
2548
|
-
import { readFileSync as
|
|
3303
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2549
3304
|
import { basename as basename2 } from "node:path";
|
|
2550
3305
|
async function marketplace(args2) {
|
|
2551
3306
|
const sub = args2[0];
|
|
@@ -2720,7 +3475,7 @@ async function install(args2) {
|
|
|
2720
3475
|
}
|
|
2721
3476
|
const safeName = basename2(name).replace(/[/\\]/g, "_");
|
|
2722
3477
|
const filename = `${safeName}.acp.json`;
|
|
2723
|
-
|
|
3478
|
+
writeFileSync7(filename, JSON.stringify(specContent, null, 2) + "\n");
|
|
2724
3479
|
console.log(success(`Downloaded: ${filename}`));
|
|
2725
3480
|
console.log(c("dim", " No local server \u2014 saved to file. Load with: wgl protocol load " + filename));
|
|
2726
3481
|
} catch (err) {
|
|
@@ -2748,7 +3503,7 @@ async function publish(args2) {
|
|
|
2748
3503
|
}
|
|
2749
3504
|
let content;
|
|
2750
3505
|
try {
|
|
2751
|
-
content =
|
|
3506
|
+
content = readFileSync10(file, "utf8");
|
|
2752
3507
|
} catch {
|
|
2753
3508
|
console.log(error(`Cannot read file: ${file}`));
|
|
2754
3509
|
process.exit(1);
|
|
@@ -2830,30 +3585,30 @@ var integrations_exports = {};
|
|
|
2830
3585
|
__export(integrations_exports, {
|
|
2831
3586
|
integrations: () => integrations
|
|
2832
3587
|
});
|
|
2833
|
-
import { readFileSync as
|
|
2834
|
-
import { join as
|
|
3588
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5, existsSync as existsSync10 } from "node:fs";
|
|
3589
|
+
import { join as join10 } from "node:path";
|
|
2835
3590
|
import { homedir as homedir3 } from "node:os";
|
|
2836
3591
|
function configDir() {
|
|
2837
|
-
return
|
|
3592
|
+
return join10(homedir3(), ".config", "honeybee");
|
|
2838
3593
|
}
|
|
2839
3594
|
function configPath() {
|
|
2840
|
-
return
|
|
3595
|
+
return join10(configDir(), "integrations.json");
|
|
2841
3596
|
}
|
|
2842
3597
|
function loadLocalConfig() {
|
|
2843
3598
|
const path = configPath();
|
|
2844
|
-
if (!
|
|
3599
|
+
if (!existsSync10(path)) return {};
|
|
2845
3600
|
try {
|
|
2846
|
-
return JSON.parse(
|
|
3601
|
+
return JSON.parse(readFileSync11(path, "utf8"));
|
|
2847
3602
|
} catch {
|
|
2848
3603
|
return {};
|
|
2849
3604
|
}
|
|
2850
3605
|
}
|
|
2851
3606
|
function saveLocalConfig(config) {
|
|
2852
3607
|
const dir = configDir();
|
|
2853
|
-
if (!
|
|
2854
|
-
|
|
3608
|
+
if (!existsSync10(dir)) {
|
|
3609
|
+
mkdirSync5(dir, { recursive: true });
|
|
2855
3610
|
}
|
|
2856
|
-
|
|
3611
|
+
writeFileSync8(configPath(), JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
2857
3612
|
}
|
|
2858
3613
|
async function integrations(args2) {
|
|
2859
3614
|
const sub = args2[0];
|
|
@@ -3026,9 +3781,13 @@ async function install2(args2) {
|
|
|
3026
3781
|
}
|
|
3027
3782
|
const manifest = res.data;
|
|
3028
3783
|
const npmPackage = manifest.npm_package || name;
|
|
3029
|
-
|
|
3784
|
+
if (!/^(@[a-z0-9-~][a-z0-9._-~]*\/)?[a-z0-9-~][a-z0-9._-~]*(@[^;|&`$\s]+)?$/.test(npmPackage)) {
|
|
3785
|
+
console.log(error(`Invalid npm package name: ${npmPackage}`));
|
|
3786
|
+
process.exit(1);
|
|
3787
|
+
}
|
|
3788
|
+
const { execFileSync } = await import("node:child_process");
|
|
3030
3789
|
console.log(c("dim", ` Installing ${npmPackage}...`));
|
|
3031
|
-
|
|
3790
|
+
execFileSync("npm", ["install", "-g", npmPackage], { stdio: "inherit" });
|
|
3032
3791
|
const config = loadLocalConfig();
|
|
3033
3792
|
config[name] = {
|
|
3034
3793
|
package: npmPackage,
|
|
@@ -3125,10 +3884,10 @@ async function publish2(args2) {
|
|
|
3125
3884
|
}
|
|
3126
3885
|
let content;
|
|
3127
3886
|
try {
|
|
3128
|
-
content =
|
|
3887
|
+
content = readFileSync11(manifestPath, "utf8");
|
|
3129
3888
|
} catch {
|
|
3130
3889
|
try {
|
|
3131
|
-
content =
|
|
3890
|
+
content = readFileSync11(join10(manifestPath, "manifest.json"), "utf8");
|
|
3132
3891
|
} catch {
|
|
3133
3892
|
console.log(error(`Cannot read manifest: ${manifestPath}`));
|
|
3134
3893
|
process.exit(1);
|
|
@@ -3196,7 +3955,7 @@ var swarm_exports = {};
|
|
|
3196
3955
|
__export(swarm_exports, {
|
|
3197
3956
|
swarm: () => swarm
|
|
3198
3957
|
});
|
|
3199
|
-
import { readFileSync as
|
|
3958
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
3200
3959
|
async function swarm(args2) {
|
|
3201
3960
|
const sub = args2[0];
|
|
3202
3961
|
if (!sub || sub === "--help" || sub === "-h") {
|
|
@@ -3280,7 +4039,7 @@ async function create(args2) {
|
|
|
3280
4039
|
if (protoIdx !== -1) {
|
|
3281
4040
|
const protoFile = args2[protoIdx + 1];
|
|
3282
4041
|
try {
|
|
3283
|
-
const content =
|
|
4042
|
+
const content = readFileSync12(protoFile, "utf8");
|
|
3284
4043
|
const parsed = JSON.parse(content);
|
|
3285
4044
|
opts.protocol_name = parsed.name || protoFile;
|
|
3286
4045
|
opts.protocol_content = content;
|
|
@@ -3587,7 +4346,7 @@ var scan_exports = {};
|
|
|
3587
4346
|
__export(scan_exports, {
|
|
3588
4347
|
scan: () => scan
|
|
3589
4348
|
});
|
|
3590
|
-
import { readFileSync as
|
|
4349
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
3591
4350
|
async function scan(args2) {
|
|
3592
4351
|
if (args2[0] === "--help" || args2[0] === "-h") {
|
|
3593
4352
|
console.log(`
|
|
@@ -3635,7 +4394,7 @@ ${c("cyan", "EXAMPLES:")}
|
|
|
3635
4394
|
return;
|
|
3636
4395
|
}
|
|
3637
4396
|
try {
|
|
3638
|
-
text =
|
|
4397
|
+
text = readFileSync13(filePath, "utf8");
|
|
3639
4398
|
} catch {
|
|
3640
4399
|
console.log(error(`Cannot read file: ${filePath}`));
|
|
3641
4400
|
process.exit(1);
|
|
@@ -3735,6 +4494,157 @@ var init_scan = __esm({
|
|
|
3735
4494
|
}
|
|
3736
4495
|
});
|
|
3737
4496
|
|
|
4497
|
+
// src/commands/telemetry.ts
|
|
4498
|
+
var telemetry_exports = {};
|
|
4499
|
+
__export(telemetry_exports, {
|
|
4500
|
+
telemetry: () => telemetry
|
|
4501
|
+
});
|
|
4502
|
+
async function telemetry(args2) {
|
|
4503
|
+
const sub = args2[0];
|
|
4504
|
+
if (sub === "--help" || sub === "-h" || !sub) {
|
|
4505
|
+
console.log(`
|
|
4506
|
+
${c("bold", "wgl telemetry")} \u2014 view telemetry data from Carapace
|
|
4507
|
+
|
|
4508
|
+
${c("cyan", "USAGE:")}
|
|
4509
|
+
wgl telemetry overview Aggregate counters (scans, threats, latency)
|
|
4510
|
+
wgl telemetry events Recent telemetry events
|
|
4511
|
+
wgl telemetry timeline Daily breakdown by event type
|
|
4512
|
+
|
|
4513
|
+
${c("cyan", "OPTIONS:")}
|
|
4514
|
+
--days N Time window in days (default: 30, max: 90)
|
|
4515
|
+
--limit N Number of events to show (default: 20, max: 100)
|
|
4516
|
+
--json JSON output (pipe-friendly)
|
|
4517
|
+
|
|
4518
|
+
${c("cyan", "EXAMPLES:")}
|
|
4519
|
+
wgl telemetry overview
|
|
4520
|
+
wgl telemetry overview --days 7
|
|
4521
|
+
wgl telemetry events --limit 10
|
|
4522
|
+
wgl telemetry timeline --json
|
|
4523
|
+
`);
|
|
4524
|
+
return;
|
|
4525
|
+
}
|
|
4526
|
+
let client;
|
|
4527
|
+
try {
|
|
4528
|
+
client = createPlatformClient();
|
|
4529
|
+
} catch {
|
|
4530
|
+
console.log(error("Not logged in. Run `wgl auth login` first."));
|
|
4531
|
+
process.exit(1);
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4534
|
+
const jsonOutput = args2.includes("--json");
|
|
4535
|
+
const daysIdx = args2.indexOf("--days");
|
|
4536
|
+
const days = daysIdx !== -1 ? parseInt(args2[daysIdx + 1], 10) || 30 : void 0;
|
|
4537
|
+
const limitIdx = args2.indexOf("--limit");
|
|
4538
|
+
const limit = limitIdx !== -1 ? parseInt(args2[limitIdx + 1], 10) || 20 : void 0;
|
|
4539
|
+
switch (sub) {
|
|
4540
|
+
case "overview":
|
|
4541
|
+
await showOverview(client, days, jsonOutput);
|
|
4542
|
+
break;
|
|
4543
|
+
case "events":
|
|
4544
|
+
await showEvents(client, limit, jsonOutput);
|
|
4545
|
+
break;
|
|
4546
|
+
case "timeline":
|
|
4547
|
+
await showTimeline(client, days, jsonOutput);
|
|
4548
|
+
break;
|
|
4549
|
+
default:
|
|
4550
|
+
console.log(error(`Unknown subcommand: ${sub}`));
|
|
4551
|
+
console.log("Run `wgl telemetry --help` for usage");
|
|
4552
|
+
process.exit(2);
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
async function showOverview(client, days, json) {
|
|
4556
|
+
const res = await client.telemetryOverview(days);
|
|
4557
|
+
if (!res.ok) {
|
|
4558
|
+
console.log(error(`Failed to fetch overview (${res.status})`));
|
|
4559
|
+
process.exit(1);
|
|
4560
|
+
return;
|
|
4561
|
+
}
|
|
4562
|
+
const data = res.data;
|
|
4563
|
+
if (json) {
|
|
4564
|
+
console.log(JSON.stringify(data, null, 2));
|
|
4565
|
+
return;
|
|
4566
|
+
}
|
|
4567
|
+
console.log(heading(`Telemetry Overview (${data.days} days)`));
|
|
4568
|
+
console.log(table([
|
|
4569
|
+
["Scans", String(data.totalScans)],
|
|
4570
|
+
["Threats Blocked", data.threatsBlocked > 0 ? c("red", String(data.threatsBlocked)) : "0"],
|
|
4571
|
+
["MCP Proxy Requests", String(data.totalMcpRequests)],
|
|
4572
|
+
["LLM Proxy Requests", String(data.totalProxyRequests)],
|
|
4573
|
+
["Avg Latency", `${data.avgLatencyMs}ms`]
|
|
4574
|
+
]));
|
|
4575
|
+
console.log();
|
|
4576
|
+
}
|
|
4577
|
+
async function showEvents(client, limit, json) {
|
|
4578
|
+
const res = await client.telemetryEvents({ limit: limit ?? 20 });
|
|
4579
|
+
if (!res.ok) {
|
|
4580
|
+
console.log(error(`Failed to fetch events (${res.status})`));
|
|
4581
|
+
process.exit(1);
|
|
4582
|
+
return;
|
|
4583
|
+
}
|
|
4584
|
+
const page = res.data;
|
|
4585
|
+
if (json) {
|
|
4586
|
+
console.log(JSON.stringify(page, null, 2));
|
|
4587
|
+
return;
|
|
4588
|
+
}
|
|
4589
|
+
console.log(heading(`Recent Events (${page.events.length} of ${page.total})`));
|
|
4590
|
+
if (page.events.length === 0) {
|
|
4591
|
+
console.log(` ${c("dim", "No telemetry events yet.")}`);
|
|
4592
|
+
console.log();
|
|
4593
|
+
return;
|
|
4594
|
+
}
|
|
4595
|
+
for (const event of page.events) {
|
|
4596
|
+
const typeColor = event.eventType === "threat_detected" ? "red" : event.eventType.startsWith("agent_") ? "cyan" : event.eventType.startsWith("llm_") ? "yellow" : "dim";
|
|
4597
|
+
const ts = new Date(event.createdAt).toLocaleString();
|
|
4598
|
+
console.log(` ${c("dim", ts)} ${c(typeColor, event.eventType.padEnd(18))}`);
|
|
4599
|
+
if (event.metadata) {
|
|
4600
|
+
const meta = Object.entries(event.metadata).slice(0, 4).map(([k, v]) => `${k}=${typeof v === "object" ? JSON.stringify(v) : v}`).join(" ");
|
|
4601
|
+
if (meta) console.log(` ${c("dim", meta)}`);
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
console.log();
|
|
4605
|
+
}
|
|
4606
|
+
async function showTimeline(client, days, json) {
|
|
4607
|
+
const res = await client.telemetryTimeline(days);
|
|
4608
|
+
if (!res.ok) {
|
|
4609
|
+
console.log(error(`Failed to fetch timeline (${res.status})`));
|
|
4610
|
+
process.exit(1);
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
const data = res.data;
|
|
4614
|
+
if (json) {
|
|
4615
|
+
console.log(JSON.stringify(data, null, 2));
|
|
4616
|
+
return;
|
|
4617
|
+
}
|
|
4618
|
+
console.log(heading(`Telemetry Timeline (${data.days} days)`));
|
|
4619
|
+
if (data.timeline.length === 0) {
|
|
4620
|
+
console.log(` ${c("dim", "No data for this period.")}`);
|
|
4621
|
+
console.log();
|
|
4622
|
+
return;
|
|
4623
|
+
}
|
|
4624
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
4625
|
+
for (const entry of data.timeline) {
|
|
4626
|
+
const key = entry.date;
|
|
4627
|
+
if (!byDate.has(key)) byDate.set(key, []);
|
|
4628
|
+
byDate.get(key).push({ type: entry.event_type, count: entry.count });
|
|
4629
|
+
}
|
|
4630
|
+
for (const [date, entries] of byDate) {
|
|
4631
|
+
const total = entries.reduce((s, e) => s + e.count, 0);
|
|
4632
|
+
console.log(` ${c("bold", date)} ${c("dim", `(${total} events)`)}`);
|
|
4633
|
+
for (const e of entries) {
|
|
4634
|
+
const bar = "|".repeat(Math.min(e.count, 40));
|
|
4635
|
+
console.log(` ${e.type.padEnd(18)} ${c("cyan", bar)} ${e.count}`);
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
console.log();
|
|
4639
|
+
}
|
|
4640
|
+
var init_telemetry = __esm({
|
|
4641
|
+
"src/commands/telemetry.ts"() {
|
|
4642
|
+
"use strict";
|
|
4643
|
+
init_dist2();
|
|
4644
|
+
init_format();
|
|
4645
|
+
}
|
|
4646
|
+
});
|
|
4647
|
+
|
|
3738
4648
|
// src/commands/completion.ts
|
|
3739
4649
|
var completion_exports = {};
|
|
3740
4650
|
__export(completion_exports, {
|
|
@@ -3931,28 +4841,28 @@ var upgrade_exports = {};
|
|
|
3931
4841
|
__export(upgrade_exports, {
|
|
3932
4842
|
upgrade: () => upgrade
|
|
3933
4843
|
});
|
|
3934
|
-
import { readFileSync as
|
|
3935
|
-
import { join as
|
|
4844
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
4845
|
+
import { join as join11, dirname as dirname3 } from "node:path";
|
|
3936
4846
|
import { request as httpsRequest3 } from "node:https";
|
|
3937
4847
|
import { execSync } from "node:child_process";
|
|
3938
4848
|
function getCurrentVersion() {
|
|
3939
|
-
if (true) return "1.0.
|
|
4849
|
+
if (true) return "1.0.2";
|
|
3940
4850
|
try {
|
|
3941
|
-
const pkgPath =
|
|
3942
|
-
return JSON.parse(
|
|
4851
|
+
const pkgPath = join11(dirname3(new URL(import.meta.url).pathname), "..", "package.json");
|
|
4852
|
+
return JSON.parse(readFileSync14(pkgPath, "utf8")).version;
|
|
3943
4853
|
} catch {
|
|
3944
4854
|
return "0.0.0-dev";
|
|
3945
4855
|
}
|
|
3946
4856
|
}
|
|
3947
4857
|
function fetchLatestVersion() {
|
|
3948
|
-
return new Promise((
|
|
4858
|
+
return new Promise((resolve3, reject) => {
|
|
3949
4859
|
const req = httpsRequest3(REGISTRY_URL, { timeout: 1e4 }, (res) => {
|
|
3950
4860
|
let data = "";
|
|
3951
4861
|
res.on("data", (chunk) => data += chunk);
|
|
3952
4862
|
res.on("end", () => {
|
|
3953
4863
|
try {
|
|
3954
4864
|
const parsed = JSON.parse(data);
|
|
3955
|
-
|
|
4865
|
+
resolve3(parsed.version);
|
|
3956
4866
|
} catch {
|
|
3957
4867
|
reject(new Error("Failed to parse registry response"));
|
|
3958
4868
|
}
|
|
@@ -4082,6 +4992,10 @@ ${c("cyan", "CONTROL:")}
|
|
|
4082
4992
|
pause [reason] Pause coordination
|
|
4083
4993
|
resume Resume coordination
|
|
4084
4994
|
|
|
4995
|
+
${c("cyan", "BROOD:")}
|
|
4996
|
+
up Start local brood (multi-hive cluster)
|
|
4997
|
+
down Stop a running brood
|
|
4998
|
+
|
|
4085
4999
|
${c("cyan", "SERVER & HOOKS:")}
|
|
4086
5000
|
serve Start local incubator server
|
|
4087
5001
|
hooks install Install Claude Code hooks
|
|
@@ -4122,6 +5036,11 @@ ${c("cyan", "CLOUD:")}
|
|
|
4122
5036
|
swarm keys Manage API keys
|
|
4123
5037
|
swarm logs Tail swarm events
|
|
4124
5038
|
|
|
5039
|
+
${c("cyan", "TELEMETRY:")}
|
|
5040
|
+
telemetry overview Aggregate counters (scans, threats, latency)
|
|
5041
|
+
telemetry events Recent telemetry events
|
|
5042
|
+
telemetry timeline Daily breakdown by event type
|
|
5043
|
+
|
|
4125
5044
|
${c("cyan", "TOOLS:")}
|
|
4126
5045
|
scan <text> Scan text for prompt injection
|
|
4127
5046
|
completion <shell> Generate shell completion script
|
|
@@ -4153,12 +5072,12 @@ async function main() {
|
|
|
4153
5072
|
}
|
|
4154
5073
|
if (command === "--version" || command === "-v") {
|
|
4155
5074
|
if (true) {
|
|
4156
|
-
console.log("1.0.
|
|
5075
|
+
console.log("1.0.2");
|
|
4157
5076
|
} else {
|
|
4158
|
-
const { readFileSync:
|
|
4159
|
-
const { join:
|
|
4160
|
-
const pkgPath =
|
|
4161
|
-
const pkg = JSON.parse(
|
|
5077
|
+
const { readFileSync: readFileSync15 } = await null;
|
|
5078
|
+
const { join: join12, dirname: dirname4 } = await null;
|
|
5079
|
+
const pkgPath = join12(dirname4(new URL(import.meta.url).pathname), "..", "package.json");
|
|
5080
|
+
const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
|
|
4162
5081
|
console.log(pkg.version);
|
|
4163
5082
|
}
|
|
4164
5083
|
return;
|
|
@@ -4170,8 +5089,8 @@ async function main() {
|
|
|
4170
5089
|
break;
|
|
4171
5090
|
}
|
|
4172
5091
|
case "join": {
|
|
4173
|
-
const { join:
|
|
4174
|
-
await
|
|
5092
|
+
const { join: join12 } = await Promise.resolve().then(() => (init_join(), join_exports));
|
|
5093
|
+
await join12(commandArgs);
|
|
4175
5094
|
break;
|
|
4176
5095
|
}
|
|
4177
5096
|
case "status": {
|
|
@@ -4249,6 +5168,16 @@ async function main() {
|
|
|
4249
5168
|
await hooksCmd2(commandArgs);
|
|
4250
5169
|
break;
|
|
4251
5170
|
}
|
|
5171
|
+
case "up": {
|
|
5172
|
+
const { up: up2 } = await Promise.resolve().then(() => (init_up(), up_exports));
|
|
5173
|
+
await up2(commandArgs);
|
|
5174
|
+
break;
|
|
5175
|
+
}
|
|
5176
|
+
case "down": {
|
|
5177
|
+
const { down: down2 } = await Promise.resolve().then(() => (init_down(), down_exports));
|
|
5178
|
+
await down2(commandArgs);
|
|
5179
|
+
break;
|
|
5180
|
+
}
|
|
4252
5181
|
case "serve": {
|
|
4253
5182
|
const { serve: serve2 } = await Promise.resolve().then(() => (init_serve(), serve_exports));
|
|
4254
5183
|
await serve2(commandArgs);
|
|
@@ -4284,6 +5213,11 @@ async function main() {
|
|
|
4284
5213
|
await scan2(commandArgs);
|
|
4285
5214
|
break;
|
|
4286
5215
|
}
|
|
5216
|
+
case "telemetry": {
|
|
5217
|
+
const { telemetry: telemetry2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
|
|
5218
|
+
await telemetry2(commandArgs);
|
|
5219
|
+
break;
|
|
5220
|
+
}
|
|
4287
5221
|
case "completion": {
|
|
4288
5222
|
const { completion: completion2 } = await Promise.resolve().then(() => (init_completion(), completion_exports));
|
|
4289
5223
|
await completion2(commandArgs);
|