@legioncodeinc/honeycomb 0.1.8 → 0.1.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/bundle/cli.js +496 -74
- package/daemon/dashboard-app.js +23 -23
- package/daemon/index.js +1576 -769
- package/daemon/restart-helper.js +41 -0
- package/embeddings/embed-daemon.js +1 -1
- package/harnesses/claude-code/.claude-plugin/plugin.json +1 -1
- package/harnesses/claude-code/bundle/capture.js +45 -31
- package/harnesses/claude-code/bundle/index.js +45 -31
- package/harnesses/claude-code/bundle/pre-tool-use.js +45 -31
- package/harnesses/claude-code/bundle/session-end.js +45 -31
- package/harnesses/claude-code/bundle/session-start.js +45 -31
- package/harnesses/codex/bundle/capture.js +45 -31
- package/harnesses/codex/bundle/index.js +45 -31
- package/harnesses/codex/bundle/pre-tool-use.js +45 -31
- package/harnesses/codex/bundle/session-start.js +45 -31
- package/harnesses/codex/package.json +1 -1
- package/harnesses/cursor/bundle/capture.js +45 -31
- package/harnesses/cursor/bundle/index.js +45 -31
- package/harnesses/cursor/bundle/pre-tool-use.js +45 -31
- package/harnesses/cursor/bundle/session-end.js +45 -31
- package/harnesses/cursor/bundle/session-start.js +45 -31
- package/harnesses/openclaw/dist/index.js +1 -1
- package/harnesses/openclaw/openclaw.plugin.json +1 -1
- package/harnesses/openclaw/package.json +1 -1
- package/mcp/bundle/server.js +1 -1
- package/package.json +1 -1
package/bundle/cli.js
CHANGED
|
@@ -6,38 +6,52 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// dist/src/commands/contracts.js
|
|
9
|
+
var VERB_GROUPS = Object.freeze([
|
|
10
|
+
{ key: "memory", label: "Memory & recall" },
|
|
11
|
+
{ key: "knowledge", label: "Knowledge & skills" },
|
|
12
|
+
{ key: "agents", label: "Agents, routing & config" },
|
|
13
|
+
{ key: "account", label: "Account & workspaces" },
|
|
14
|
+
{ key: "system", label: "Setup & system" }
|
|
15
|
+
]);
|
|
9
16
|
var VERB_TABLE = Object.freeze([
|
|
10
|
-
|
|
11
|
-
{ verb: "
|
|
12
|
-
{ verb: "
|
|
13
|
-
{ verb: "
|
|
14
|
-
{ verb: "
|
|
15
|
-
{ verb: "
|
|
16
|
-
{ verb: "
|
|
17
|
-
|
|
18
|
-
{ verb: "
|
|
19
|
-
{ verb: "
|
|
20
|
-
{ verb: "
|
|
21
|
-
{ verb: "
|
|
22
|
-
{ verb: "
|
|
23
|
-
{ verb: "
|
|
24
|
-
{ verb: "
|
|
25
|
-
|
|
26
|
-
{ verb: "
|
|
27
|
-
{ verb: "
|
|
28
|
-
{ verb: "
|
|
29
|
-
{ verb: "
|
|
30
|
-
|
|
31
|
-
{ verb: "
|
|
32
|
-
{ verb: "
|
|
33
|
-
{ verb: "whoami", cls: "auth", summary: "show the authenticated user, org, and workspace (GET /me)" },
|
|
34
|
-
{ verb: "org", cls: "auth", summary: "list/switch org (passthrough to the auth dispatcher)" },
|
|
35
|
-
{ verb: "workspace", cls: "auth", summary: "list/switch/use workspace (passthrough to the auth dispatcher)" },
|
|
36
|
-
{ verb: "workspaces", cls: "auth", summary: "list workspaces in the active org (alias of `workspace list`)" },
|
|
37
|
-
{ verb: "project", cls: "auth", summary: "list/bind/use projects + show the resolved per-folder scope (049d)" },
|
|
38
|
-
|
|
39
|
-
{ verb: "
|
|
40
|
-
{ verb: "
|
|
17
|
+
// Memory & recall — the product's core write/read/lifecycle surface.
|
|
18
|
+
{ verb: "remember", cls: "storage", group: "memory", summary: "write a memory through the daemon (--type fact|convention|preference|decision|gotcha|reference)" },
|
|
19
|
+
{ verb: "recall", cls: "storage", group: "memory", summary: "recall memories through the daemon" },
|
|
20
|
+
{ verb: "memory", cls: "storage", group: "memory", summary: "lifecycle: conflicts (list/resolve), stale-refs (list), inspect <id> --lifecycle (058d)" },
|
|
21
|
+
{ verb: "sessions", cls: "storage", group: "memory", summary: "list/prune captured sessions through the daemon" },
|
|
22
|
+
{ verb: "pollinate", cls: "storage", group: "memory", summary: "trigger a pollinating consolidation pass on the daemon (009/026)" },
|
|
23
|
+
{ verb: "maintenance", cls: "storage", group: "memory", summary: "run version-history compaction over version-bumped tables (030)" },
|
|
24
|
+
// Knowledge & skills — skills, assets, ontology, the codebase graph, and goals.
|
|
25
|
+
{ verb: "skill", cls: "storage", group: "knowledge", summary: "skillify scope/pull/unpull/force/promote through the daemon (promote = cross-project, 049c)" },
|
|
26
|
+
{ verb: "skillify", cls: "storage", group: "knowledge", summary: "pull team skills from the daemon (016c)" },
|
|
27
|
+
{ verb: "asset", cls: "storage", group: "knowledge", summary: "register/promote/demote/style skills+agents through the tier\xD7style lattice (033)" },
|
|
28
|
+
{ verb: "ontology", cls: "storage", group: "knowledge", summary: "inspect/propose ontology changes through the daemon" },
|
|
29
|
+
{ verb: "graph", cls: "storage", group: "knowledge", summary: "build/query the codebase graph through the daemon" },
|
|
30
|
+
{ verb: "sources", cls: "storage", group: "knowledge", summary: "connect/index/purge sources through the daemon" },
|
|
31
|
+
{ verb: "goal", cls: "storage", group: "knowledge", summary: "manage goals/KPIs through the daemon" },
|
|
32
|
+
// Agents, routing & config — agent turns, inference routes, secrets, and vault settings.
|
|
33
|
+
{ verb: "agent", cls: "storage", group: "agents", summary: "run an agent turn through the daemon" },
|
|
34
|
+
{ verb: "route", cls: "storage", group: "agents", summary: "manage inference routes through the daemon" },
|
|
35
|
+
{ verb: "secret", cls: "storage", group: "agents", summary: "manage named secrets through the daemon" },
|
|
36
|
+
{ verb: "settings", cls: "storage", group: "agents", summary: "get/set/list vault settings + provider\u2192model selector through the daemon" },
|
|
37
|
+
// Account & workspaces — auth, identity, and the org/workspace/project scope surface.
|
|
38
|
+
{ verb: "login", cls: "auth", group: "account", summary: "authenticate via device flow, or --token <key> for headless (023)" },
|
|
39
|
+
{ verb: "logout", cls: "auth", group: "account", summary: "remove the shared credentials and sign out (023)" },
|
|
40
|
+
{ verb: "whoami", cls: "auth", group: "account", summary: "show the authenticated user, org, and workspace (GET /me)" },
|
|
41
|
+
{ verb: "org", cls: "auth", group: "account", summary: "list/switch org (passthrough to the auth dispatcher)" },
|
|
42
|
+
{ verb: "workspace", cls: "auth", group: "account", summary: "list/switch/use workspace (passthrough to the auth dispatcher)" },
|
|
43
|
+
{ verb: "workspaces", cls: "auth", group: "account", summary: "list workspaces in the active org (alias of `workspace list`)" },
|
|
44
|
+
{ verb: "project", cls: "auth", group: "account", summary: "list/bind/use projects + show the resolved per-folder scope (049d)" },
|
|
45
|
+
// Setup & system — install/onboard, daemon lifecycle, dashboard, hooks, telemetry, update.
|
|
46
|
+
{ verb: "setup", cls: "local", group: "system", summary: "detect assistants, wire hooks, bring up the daemon" },
|
|
47
|
+
{ verb: "install", cls: "local", group: "system", summary: "bring up the daemon (health-gated) + open the dashboard (PRD-050a)" },
|
|
48
|
+
{ verb: "status", cls: "local", group: "system", summary: "daemon connectivity + login + D1\u2013D5 environment health" },
|
|
49
|
+
{ verb: "daemon", cls: "local", group: "system", summary: "start | stop | status the loopback daemon (3850)" },
|
|
50
|
+
{ verb: "dashboard", cls: "local", group: "system", summary: "launch the daemon-served dashboard (020b)" },
|
|
51
|
+
{ verb: "hook", cls: "local", group: "system", summary: "inspect/wire harness hooks" },
|
|
52
|
+
{ verb: "telemetry", cls: "local", group: "system", summary: "show exactly what adoption telemetry has been / would be sent (--show, PRD-050e)" },
|
|
53
|
+
{ verb: "update", cls: "local", group: "system", summary: "self-update the CLI, daemon, and bundles" },
|
|
54
|
+
{ verb: "uninstall", cls: "local", group: "system", summary: "reverse only Honeycomb's changes" }
|
|
41
55
|
]);
|
|
42
56
|
function lookupVerb(verb) {
|
|
43
57
|
return VERB_TABLE.find((v) => v.verb === verb);
|
|
@@ -514,6 +528,15 @@ var PROVIDER_CATALOG = Object.freeze([
|
|
|
514
528
|
// Suggestions only — OpenRouter accepts a free-form `vendor/model` id (passthrough).
|
|
515
529
|
models: Object.freeze(["anthropic/claude-sonnet-4.6", "openai/gpt-4o"]),
|
|
516
530
|
openEnded: true
|
|
531
|
+
}),
|
|
532
|
+
Object.freeze({
|
|
533
|
+
// PRD-063a: Portkey is a GATEWAY, not a model vendor — its `portkey.config` id is
|
|
534
|
+
// free-form (a config or virtual-key id copied from the Portkey dashboard), so it is
|
|
535
|
+
// `openEnded: true` like OpenRouter and carries NO curated model list of its own.
|
|
536
|
+
id: "portkey",
|
|
537
|
+
label: "Portkey",
|
|
538
|
+
models: Object.freeze([]),
|
|
539
|
+
openEnded: true
|
|
517
540
|
})
|
|
518
541
|
]);
|
|
519
542
|
function providerEntry(provider) {
|
|
@@ -16488,10 +16511,10 @@ function flagValue3(argv, flag) {
|
|
|
16488
16511
|
return v !== void 0 && !v.startsWith("--") ? v : void 0;
|
|
16489
16512
|
}
|
|
16490
16513
|
function parseSkillId(raw) {
|
|
16491
|
-
const
|
|
16492
|
-
if (
|
|
16514
|
+
const sep4 = raw.lastIndexOf("--");
|
|
16515
|
+
if (sep4 <= 0)
|
|
16493
16516
|
return { name: raw, author: "" };
|
|
16494
|
-
return { name: raw.slice(0,
|
|
16517
|
+
return { name: raw.slice(0, sep4), author: raw.slice(sep4 + 2) };
|
|
16495
16518
|
}
|
|
16496
16519
|
function buildSkillRequest(argv) {
|
|
16497
16520
|
const sub = subcommandOf(argv);
|
|
@@ -17235,7 +17258,7 @@ function buildAllowedProperties(input) {
|
|
|
17235
17258
|
}
|
|
17236
17259
|
var systemTelemetryClock = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
17237
17260
|
var DEFAULT_EMIT_TIMEOUT_MS = 2e3;
|
|
17238
|
-
var HONEYCOMB_VERSION = true ? "0.1.
|
|
17261
|
+
var HONEYCOMB_VERSION = true ? "0.1.9" : "0.0.0-dev";
|
|
17239
17262
|
async function emitTelemetry(event, opts, deps = {}) {
|
|
17240
17263
|
const env = deps.env ?? process.env;
|
|
17241
17264
|
const key = deps.posthogKey ?? POSTHOG_KEY;
|
|
@@ -17378,7 +17401,7 @@ function renderGlassBoxText(view) {
|
|
|
17378
17401
|
// dist/src/shared/constants.js
|
|
17379
17402
|
var DAEMON_PORT = 3850;
|
|
17380
17403
|
var DAEMON_HOST = "127.0.0.1";
|
|
17381
|
-
var HONEYCOMB_VERSION2 = true ? "0.1.
|
|
17404
|
+
var HONEYCOMB_VERSION2 = true ? "0.1.9" : "0.0.0-dev";
|
|
17382
17405
|
var PRODUCT_SLUG = "honeycomb";
|
|
17383
17406
|
|
|
17384
17407
|
// dist/src/commands/install.js
|
|
@@ -17461,6 +17484,19 @@ function openDashboardWithFallback(opener, out) {
|
|
|
17461
17484
|
const opened = opener(loopback);
|
|
17462
17485
|
out(opened ? `\u2192 opening dashboard at ${loopback}\u2026` : `\u2192 dashboard is ready at ${loopback} (open it in your browser).`);
|
|
17463
17486
|
}
|
|
17487
|
+
async function reportDaemonSupervision(deps, out) {
|
|
17488
|
+
if (deps.lifecycle === void 0)
|
|
17489
|
+
return;
|
|
17490
|
+
try {
|
|
17491
|
+
const status3 = await deps.lifecycle.status();
|
|
17492
|
+
if (status3.serviceManager !== void 0) {
|
|
17493
|
+
out(`\u2713 daemon registered as an OS service (${status3.serviceManager}): it restarts on crash and starts on boot.`);
|
|
17494
|
+
} else {
|
|
17495
|
+
out("note: daemon running as a detached process (OS service registration unavailable on this host).");
|
|
17496
|
+
}
|
|
17497
|
+
} catch {
|
|
17498
|
+
}
|
|
17499
|
+
}
|
|
17464
17500
|
async function runInstallCommand(argv, deps) {
|
|
17465
17501
|
const out = deps.out ?? ((line) => console.log(line));
|
|
17466
17502
|
const opener = deps.openDashboard ?? openLocalDashboardUrl;
|
|
@@ -17477,6 +17513,7 @@ async function runInstallCommand(argv, deps) {
|
|
|
17477
17513
|
return { exitCode: 1 };
|
|
17478
17514
|
}
|
|
17479
17515
|
out(`\u2713 daemon up on ${DAEMON_HOST}:${DAEMON_PORT}.`);
|
|
17516
|
+
await reportDaemonSupervision(deps, out);
|
|
17480
17517
|
const wrote = writeInstalledMarker(ref, deps.dir, out);
|
|
17481
17518
|
if (wrote)
|
|
17482
17519
|
out(`\u2713 onboarding marked installed (ref: ${ref}).`);
|
|
@@ -17535,12 +17572,26 @@ function parseInvocation(argv) {
|
|
|
17535
17572
|
const tail = verb === "" ? argv.slice(i) : argv.slice(i + 1);
|
|
17536
17573
|
return { verb, argv: tail, flags };
|
|
17537
17574
|
}
|
|
17575
|
+
var HONEYCOMB_BANNER = [
|
|
17576
|
+
" __ __ __",
|
|
17577
|
+
" / \\__/ \\__/ \\ H O N E Y C O M B",
|
|
17578
|
+
" \\__/ \\__/ \\__/",
|
|
17579
|
+
" / \\__/ \\__/ \\ shared agent memory for your coding tools",
|
|
17580
|
+
" \\__/ \\__/ \\__/"
|
|
17581
|
+
].join("\n");
|
|
17538
17582
|
function usageText() {
|
|
17539
|
-
const lines = [`${PRODUCT_SLUG} v${HONEYCOMB_VERSION2}`, "", "usage: honeycomb <command> [options]", ""
|
|
17540
|
-
|
|
17541
|
-
|
|
17583
|
+
const lines = [HONEYCOMB_BANNER, "", `${PRODUCT_SLUG} v${HONEYCOMB_VERSION2}`, "", "usage: honeycomb <command> [options]", ""];
|
|
17584
|
+
const pad = VERB_TABLE.reduce((w, s2) => Math.max(w, s2.verb.length), 0) + 2;
|
|
17585
|
+
for (const { key, label } of VERB_GROUPS) {
|
|
17586
|
+
const rows = VERB_TABLE.filter((s2) => s2.group === key);
|
|
17587
|
+
if (rows.length === 0)
|
|
17588
|
+
continue;
|
|
17589
|
+
lines.push(`${label}:`);
|
|
17590
|
+
for (const spec of rows)
|
|
17591
|
+
lines.push(` ${spec.verb.padEnd(pad)}${spec.summary}`);
|
|
17592
|
+
lines.push("");
|
|
17542
17593
|
}
|
|
17543
|
-
lines.push("
|
|
17594
|
+
lines.push("global flags: --help --version --json --dry-run");
|
|
17544
17595
|
return lines.join("\n");
|
|
17545
17596
|
}
|
|
17546
17597
|
function lifecycleOf(deps) {
|
|
@@ -17663,13 +17714,14 @@ function createDispatcher() {
|
|
|
17663
17714
|
|
|
17664
17715
|
// dist/src/cli/runtime.js
|
|
17665
17716
|
import { spawn } from "node:child_process";
|
|
17666
|
-
import {
|
|
17667
|
-
import {
|
|
17717
|
+
import { mkdirSync as mkdirSync8, mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
17718
|
+
import { homedir as homedir13 } from "node:os";
|
|
17719
|
+
import { dirname as dirname8, join as join13, resolve as resolve8 } from "node:path";
|
|
17668
17720
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
17669
17721
|
|
|
17670
17722
|
// dist/src/daemon/runtime/auth/deeplake-issuer.js
|
|
17671
17723
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
17672
|
-
var realSleeper = (ms) => new Promise((
|
|
17724
|
+
var realSleeper = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
17673
17725
|
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
17674
17726
|
var DEEPLAKE_ORG_HEADER = "X-Activeloop-Org-Id";
|
|
17675
17727
|
var DEEPLAKE_CLIENT_VALUE = "honeycomb";
|
|
@@ -20119,6 +20171,273 @@ async function launchDashboard(options = {}) {
|
|
|
20119
20171
|
return renderDashboard(source);
|
|
20120
20172
|
}
|
|
20121
20173
|
|
|
20174
|
+
// dist/src/cli/daemon-service.js
|
|
20175
|
+
import { createRequire } from "node:module";
|
|
20176
|
+
import { homedir as homedir12 } from "node:os";
|
|
20177
|
+
import { join as join12, normalize, resolve as resolve7, sep as sep3 } from "node:path";
|
|
20178
|
+
var SERVICE_LABEL = "ai.honeycomb.daemon";
|
|
20179
|
+
var SERVICE_TASK_NAME = "HoneycombDaemon";
|
|
20180
|
+
var SERVICE_MODE_ENV = "HONEYCOMB_DAEMON_SERVICE";
|
|
20181
|
+
function detectServiceManager(env = process.env, platform2 = process.platform) {
|
|
20182
|
+
if ((env[SERVICE_MODE_ENV] ?? "").trim().toLowerCase() === "spawn")
|
|
20183
|
+
return null;
|
|
20184
|
+
if (platform2 === "darwin")
|
|
20185
|
+
return "launchd";
|
|
20186
|
+
if (platform2 === "win32")
|
|
20187
|
+
return "schtasks";
|
|
20188
|
+
if (platform2 === "linux") {
|
|
20189
|
+
const xdg = (env.XDG_RUNTIME_DIR ?? "").trim();
|
|
20190
|
+
if (xdg.length > 0)
|
|
20191
|
+
return "systemd-user";
|
|
20192
|
+
return null;
|
|
20193
|
+
}
|
|
20194
|
+
return null;
|
|
20195
|
+
}
|
|
20196
|
+
function defaultServiceRunner() {
|
|
20197
|
+
const require2 = createRequire(import.meta.url);
|
|
20198
|
+
const cp = require2("node:child_process");
|
|
20199
|
+
const fs = require2("node:fs");
|
|
20200
|
+
return {
|
|
20201
|
+
run(cmd, args) {
|
|
20202
|
+
const out = cp.execFileSync(cmd, [...args], {
|
|
20203
|
+
encoding: "utf8",
|
|
20204
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
20205
|
+
timeout: 15e3,
|
|
20206
|
+
windowsHide: true
|
|
20207
|
+
});
|
|
20208
|
+
return typeof out === "string" ? out.trim() : "";
|
|
20209
|
+
},
|
|
20210
|
+
writeFile(path, contents) {
|
|
20211
|
+
fs.mkdirSync(join12(path, ".."), { recursive: true });
|
|
20212
|
+
fs.writeFileSync(path, contents, { encoding: "utf8" });
|
|
20213
|
+
},
|
|
20214
|
+
removeFile(path) {
|
|
20215
|
+
try {
|
|
20216
|
+
fs.rmSync(path, { force: true });
|
|
20217
|
+
} catch {
|
|
20218
|
+
}
|
|
20219
|
+
},
|
|
20220
|
+
fileExists(path) {
|
|
20221
|
+
try {
|
|
20222
|
+
return fs.existsSync(path);
|
|
20223
|
+
} catch {
|
|
20224
|
+
return false;
|
|
20225
|
+
}
|
|
20226
|
+
}
|
|
20227
|
+
};
|
|
20228
|
+
}
|
|
20229
|
+
function containedUnitPath(home, segments) {
|
|
20230
|
+
const resolvedHome = normalize(resolve7(home));
|
|
20231
|
+
const candidate = normalize(resolve7(resolvedHome, ...segments));
|
|
20232
|
+
const homeWithSep = resolvedHome.endsWith(sep3) ? resolvedHome : resolvedHome + sep3;
|
|
20233
|
+
if (candidate !== resolvedHome && !candidate.startsWith(homeWithSep)) {
|
|
20234
|
+
throw new Error("resolved service unit path escapes the home dir");
|
|
20235
|
+
}
|
|
20236
|
+
return candidate;
|
|
20237
|
+
}
|
|
20238
|
+
function launchdPlistPath(home) {
|
|
20239
|
+
return containedUnitPath(home, ["Library", "LaunchAgents", `${SERVICE_LABEL}.plist`]);
|
|
20240
|
+
}
|
|
20241
|
+
function systemdUnitPath(home) {
|
|
20242
|
+
return containedUnitPath(home, [".config", "systemd", "user", `${SERVICE_LABEL}.service`]);
|
|
20243
|
+
}
|
|
20244
|
+
function xmlEscape(value) {
|
|
20245
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20246
|
+
}
|
|
20247
|
+
function renderLaunchdPlist(spec) {
|
|
20248
|
+
const argv = [spec.nodePath, ...spec.nodeFlags, spec.entry];
|
|
20249
|
+
const argvXml = argv.map((a) => ` <string>${xmlEscape(a)}</string>`).join("\n");
|
|
20250
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
20251
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
20252
|
+
<plist version="1.0">
|
|
20253
|
+
<dict>
|
|
20254
|
+
<key>Label</key>
|
|
20255
|
+
<string>${SERVICE_LABEL}</string>
|
|
20256
|
+
<key>ProgramArguments</key>
|
|
20257
|
+
<array>
|
|
20258
|
+
${argvXml}
|
|
20259
|
+
</array>
|
|
20260
|
+
<key>WorkingDirectory</key>
|
|
20261
|
+
<string>${xmlEscape(spec.workspace)}</string>
|
|
20262
|
+
<key>EnvironmentVariables</key>
|
|
20263
|
+
<dict>
|
|
20264
|
+
<key>HONEYCOMB_WORKSPACE</key>
|
|
20265
|
+
<string>${xmlEscape(spec.workspace)}</string>
|
|
20266
|
+
</dict>
|
|
20267
|
+
<key>RunAtLoad</key>
|
|
20268
|
+
<true/>
|
|
20269
|
+
<key>KeepAlive</key>
|
|
20270
|
+
<true/>
|
|
20271
|
+
<key>ProcessType</key>
|
|
20272
|
+
<string>Background</string>
|
|
20273
|
+
</dict>
|
|
20274
|
+
</plist>
|
|
20275
|
+
`;
|
|
20276
|
+
}
|
|
20277
|
+
function renderSystemdUnit(spec) {
|
|
20278
|
+
const execStart = [spec.nodePath, ...spec.nodeFlags, spec.entry].map((a) => `"${a}"`).join(" ");
|
|
20279
|
+
return `[Unit]
|
|
20280
|
+
Description=Honeycomb primary daemon (127.0.0.1:3850)
|
|
20281
|
+
After=network.target
|
|
20282
|
+
|
|
20283
|
+
[Service]
|
|
20284
|
+
Type=simple
|
|
20285
|
+
ExecStart=${execStart}
|
|
20286
|
+
WorkingDirectory=${spec.workspace}
|
|
20287
|
+
Environment=HONEYCOMB_WORKSPACE=${spec.workspace}
|
|
20288
|
+
Restart=always
|
|
20289
|
+
RestartSec=5
|
|
20290
|
+
|
|
20291
|
+
[Install]
|
|
20292
|
+
WantedBy=default.target
|
|
20293
|
+
`;
|
|
20294
|
+
}
|
|
20295
|
+
function assertCmdSafe(value) {
|
|
20296
|
+
if (/[&|<>^"%\r\n]/.test(value)) {
|
|
20297
|
+
throw new Error("unsafe character in service path; refusing to build schtasks /TR command");
|
|
20298
|
+
}
|
|
20299
|
+
}
|
|
20300
|
+
function buildSchtasksCreateArgs(spec) {
|
|
20301
|
+
assertCmdSafe(spec.workspace);
|
|
20302
|
+
assertCmdSafe(spec.nodePath);
|
|
20303
|
+
assertCmdSafe(spec.entry);
|
|
20304
|
+
const nodeFlags = spec.nodeFlags.length > 0 ? `${spec.nodeFlags.join(" ")} ` : "";
|
|
20305
|
+
const tr = `cmd /c "cd /d "${spec.workspace}" && set HONEYCOMB_WORKSPACE=${spec.workspace} && "${spec.nodePath}" ${nodeFlags}"${spec.entry}""`;
|
|
20306
|
+
return [
|
|
20307
|
+
"/Create",
|
|
20308
|
+
"/TN",
|
|
20309
|
+
SERVICE_TASK_NAME,
|
|
20310
|
+
"/TR",
|
|
20311
|
+
tr,
|
|
20312
|
+
"/SC",
|
|
20313
|
+
"ONLOGON",
|
|
20314
|
+
"/RL",
|
|
20315
|
+
"LIMITED",
|
|
20316
|
+
"/F"
|
|
20317
|
+
];
|
|
20318
|
+
}
|
|
20319
|
+
function specHome(spec) {
|
|
20320
|
+
return spec.home ?? homedir12();
|
|
20321
|
+
}
|
|
20322
|
+
function createDaemonServiceController(manager, runner = defaultServiceRunner()) {
|
|
20323
|
+
if (manager === "launchd")
|
|
20324
|
+
return launchdController(runner);
|
|
20325
|
+
if (manager === "systemd-user")
|
|
20326
|
+
return systemdController(runner);
|
|
20327
|
+
return schtasksController(runner);
|
|
20328
|
+
}
|
|
20329
|
+
function launchdController(runner) {
|
|
20330
|
+
function domain2() {
|
|
20331
|
+
return `gui/${process.getuid?.() ?? 501}`;
|
|
20332
|
+
}
|
|
20333
|
+
return {
|
|
20334
|
+
manager: "launchd",
|
|
20335
|
+
register(spec) {
|
|
20336
|
+
const path = launchdPlistPath(specHome(spec));
|
|
20337
|
+
runner.writeFile(path, renderLaunchdPlist(spec));
|
|
20338
|
+
runner.run("launchctl", ["bootstrap", domain2(), path]);
|
|
20339
|
+
return { ok: true, manager: "launchd" };
|
|
20340
|
+
},
|
|
20341
|
+
unregister(spec) {
|
|
20342
|
+
const path = launchdPlistPath(specHome(spec));
|
|
20343
|
+
try {
|
|
20344
|
+
runner.run("launchctl", ["bootout", `${domain2()}/${SERVICE_LABEL}`]);
|
|
20345
|
+
} catch {
|
|
20346
|
+
}
|
|
20347
|
+
runner.removeFile(path);
|
|
20348
|
+
return { ok: true, manager: "launchd" };
|
|
20349
|
+
},
|
|
20350
|
+
restart(_spec) {
|
|
20351
|
+
runner.run("launchctl", ["kickstart", "-k", `${domain2()}/${SERVICE_LABEL}`]);
|
|
20352
|
+
return { ok: true, manager: "launchd" };
|
|
20353
|
+
},
|
|
20354
|
+
stop(_spec) {
|
|
20355
|
+
runner.run("launchctl", ["kill", "SIGTERM", `${domain2()}/${SERVICE_LABEL}`]);
|
|
20356
|
+
return { ok: true, manager: "launchd" };
|
|
20357
|
+
},
|
|
20358
|
+
isRegistered(spec) {
|
|
20359
|
+
return runner.fileExists(launchdPlistPath(specHome(spec)));
|
|
20360
|
+
}
|
|
20361
|
+
};
|
|
20362
|
+
}
|
|
20363
|
+
function systemdController(runner) {
|
|
20364
|
+
const unit = `${SERVICE_LABEL}.service`;
|
|
20365
|
+
return {
|
|
20366
|
+
manager: "systemd-user",
|
|
20367
|
+
register(spec) {
|
|
20368
|
+
const path = systemdUnitPath(specHome(spec));
|
|
20369
|
+
runner.writeFile(path, renderSystemdUnit(spec));
|
|
20370
|
+
runner.run("systemctl", ["--user", "daemon-reload"]);
|
|
20371
|
+
runner.run("systemctl", ["--user", "enable", "--now", unit]);
|
|
20372
|
+
return { ok: true, manager: "systemd-user" };
|
|
20373
|
+
},
|
|
20374
|
+
unregister(spec) {
|
|
20375
|
+
try {
|
|
20376
|
+
runner.run("systemctl", ["--user", "disable", "--now", unit]);
|
|
20377
|
+
} catch {
|
|
20378
|
+
}
|
|
20379
|
+
runner.removeFile(systemdUnitPath(specHome(spec)));
|
|
20380
|
+
try {
|
|
20381
|
+
runner.run("systemctl", ["--user", "daemon-reload"]);
|
|
20382
|
+
} catch {
|
|
20383
|
+
}
|
|
20384
|
+
return { ok: true, manager: "systemd-user" };
|
|
20385
|
+
},
|
|
20386
|
+
restart(_spec) {
|
|
20387
|
+
runner.run("systemctl", ["--user", "restart", unit]);
|
|
20388
|
+
return { ok: true, manager: "systemd-user" };
|
|
20389
|
+
},
|
|
20390
|
+
stop(_spec) {
|
|
20391
|
+
runner.run("systemctl", ["--user", "stop", unit]);
|
|
20392
|
+
return { ok: true, manager: "systemd-user" };
|
|
20393
|
+
},
|
|
20394
|
+
isRegistered(spec) {
|
|
20395
|
+
return runner.fileExists(systemdUnitPath(specHome(spec)));
|
|
20396
|
+
}
|
|
20397
|
+
};
|
|
20398
|
+
}
|
|
20399
|
+
function schtasksController(runner) {
|
|
20400
|
+
return {
|
|
20401
|
+
manager: "schtasks",
|
|
20402
|
+
register(spec) {
|
|
20403
|
+
runner.run("schtasks", buildSchtasksCreateArgs(spec));
|
|
20404
|
+
runner.run("schtasks", ["/Run", "/TN", SERVICE_TASK_NAME]);
|
|
20405
|
+
return { ok: true, manager: "schtasks" };
|
|
20406
|
+
},
|
|
20407
|
+
unregister(_spec) {
|
|
20408
|
+
try {
|
|
20409
|
+
runner.run("schtasks", ["/End", "/TN", SERVICE_TASK_NAME]);
|
|
20410
|
+
} catch {
|
|
20411
|
+
}
|
|
20412
|
+
try {
|
|
20413
|
+
runner.run("schtasks", ["/Delete", "/TN", SERVICE_TASK_NAME, "/F"]);
|
|
20414
|
+
} catch {
|
|
20415
|
+
}
|
|
20416
|
+
return { ok: true, manager: "schtasks" };
|
|
20417
|
+
},
|
|
20418
|
+
restart(spec) {
|
|
20419
|
+
try {
|
|
20420
|
+
runner.run("schtasks", ["/End", "/TN", SERVICE_TASK_NAME]);
|
|
20421
|
+
} catch {
|
|
20422
|
+
}
|
|
20423
|
+
runner.run("schtasks", ["/Run", "/TN", SERVICE_TASK_NAME]);
|
|
20424
|
+
return { ok: true, manager: "schtasks" };
|
|
20425
|
+
},
|
|
20426
|
+
stop(_spec) {
|
|
20427
|
+
runner.run("schtasks", ["/End", "/TN", SERVICE_TASK_NAME]);
|
|
20428
|
+
return { ok: true, manager: "schtasks" };
|
|
20429
|
+
},
|
|
20430
|
+
isRegistered(_spec) {
|
|
20431
|
+
try {
|
|
20432
|
+
runner.run("schtasks", ["/Query", "/TN", SERVICE_TASK_NAME]);
|
|
20433
|
+
return true;
|
|
20434
|
+
} catch {
|
|
20435
|
+
return false;
|
|
20436
|
+
}
|
|
20437
|
+
}
|
|
20438
|
+
};
|
|
20439
|
+
}
|
|
20440
|
+
|
|
20122
20441
|
// dist/src/cli/runtime.js
|
|
20123
20442
|
function daemonBaseUrl2() {
|
|
20124
20443
|
return `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
@@ -20136,19 +20455,38 @@ function tenancyHeaders(creds) {
|
|
|
20136
20455
|
var DAEMON_NODE_FLAGS = ["--experimental-sqlite"];
|
|
20137
20456
|
function resolveDaemonEntry() {
|
|
20138
20457
|
const here = dirname8(fileURLToPath3(import.meta.url));
|
|
20139
|
-
const bundledSibling =
|
|
20140
|
-
const devSibling =
|
|
20458
|
+
const bundledSibling = resolve8(here, "..", "daemon", "index.js");
|
|
20459
|
+
const devSibling = resolve8(here, "..", "..", "..", "daemon", "index.js");
|
|
20141
20460
|
return process.env.HONEYCOMB_DAEMON_ENTRY ?? bundledSibling ?? devSibling;
|
|
20142
20461
|
}
|
|
20143
20462
|
var DEFAULT_START_TIMEOUT_MS = 45e3;
|
|
20144
20463
|
var START_POLL_INTERVAL_MS = 150;
|
|
20145
20464
|
function runtimeDir() {
|
|
20146
|
-
return
|
|
20465
|
+
return join13(homedir13(), ".honeycomb");
|
|
20466
|
+
}
|
|
20467
|
+
function resolveDaemonWorkspace() {
|
|
20468
|
+
const fromEnv = process.env.HONEYCOMB_WORKSPACE;
|
|
20469
|
+
const candidates = [fromEnv !== void 0 && fromEnv.length > 0 ? fromEnv : process.cwd(), runtimeDir()];
|
|
20470
|
+
for (const dir of candidates) {
|
|
20471
|
+
if (canWriteDir(dir))
|
|
20472
|
+
return dir;
|
|
20473
|
+
}
|
|
20474
|
+
return runtimeDir();
|
|
20475
|
+
}
|
|
20476
|
+
function canWriteDir(dir) {
|
|
20477
|
+
try {
|
|
20478
|
+
mkdirSync8(dir, { recursive: true });
|
|
20479
|
+
const probe = mkdtempSync(join13(dir, ".hc-spawn-probe-"));
|
|
20480
|
+
rmSync2(probe, { recursive: true, force: true });
|
|
20481
|
+
return true;
|
|
20482
|
+
} catch {
|
|
20483
|
+
return false;
|
|
20484
|
+
}
|
|
20147
20485
|
}
|
|
20148
20486
|
async function readDaemonPid() {
|
|
20149
20487
|
const { readFile: readFile2 } = await import("node:fs/promises");
|
|
20150
20488
|
try {
|
|
20151
|
-
const raw = (await readFile2(
|
|
20489
|
+
const raw = (await readFile2(join13(runtimeDir(), "daemon.pid"), "utf8")).trim();
|
|
20152
20490
|
const pid = Number.parseInt(raw, 10);
|
|
20153
20491
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
20154
20492
|
} catch {
|
|
@@ -20163,44 +20501,128 @@ function isPidAlive(pid) {
|
|
|
20163
20501
|
return err?.code === "EPERM";
|
|
20164
20502
|
}
|
|
20165
20503
|
}
|
|
20166
|
-
function
|
|
20504
|
+
function buildServiceSpec() {
|
|
20505
|
+
return {
|
|
20506
|
+
nodePath: process.execPath,
|
|
20507
|
+
entry: resolveDaemonEntry(),
|
|
20508
|
+
nodeFlags: DAEMON_NODE_FLAGS,
|
|
20509
|
+
workspace: resolveDaemonWorkspace()
|
|
20510
|
+
};
|
|
20511
|
+
}
|
|
20512
|
+
async function spawnDaemonAndWait(client) {
|
|
20513
|
+
const entry = resolveDaemonEntry();
|
|
20514
|
+
const workspace = resolveDaemonWorkspace();
|
|
20515
|
+
const child = spawn(process.execPath, [...DAEMON_NODE_FLAGS, entry], {
|
|
20516
|
+
detached: true,
|
|
20517
|
+
stdio: "ignore",
|
|
20518
|
+
cwd: workspace,
|
|
20519
|
+
env: { ...process.env, HONEYCOMB_WORKSPACE: workspace },
|
|
20520
|
+
// Hide the transient console window on Windows: a detached daemon spawn is never an
|
|
20521
|
+
// interactive terminal the user needs to see.
|
|
20522
|
+
windowsHide: true
|
|
20523
|
+
});
|
|
20524
|
+
child.unref();
|
|
20525
|
+
const deadline = Date.now() + DEFAULT_START_TIMEOUT_MS;
|
|
20526
|
+
while (Date.now() < deadline) {
|
|
20527
|
+
await new Promise((r) => setTimeout(r, START_POLL_INTERVAL_MS));
|
|
20528
|
+
if (await client.ping())
|
|
20529
|
+
return { started: true, alreadyRunning: false };
|
|
20530
|
+
}
|
|
20531
|
+
return { started: false, alreadyRunning: false };
|
|
20532
|
+
}
|
|
20533
|
+
async function waitForHealth(client) {
|
|
20534
|
+
const deadline = Date.now() + DEFAULT_START_TIMEOUT_MS;
|
|
20535
|
+
while (Date.now() < deadline) {
|
|
20536
|
+
if (await client.ping())
|
|
20537
|
+
return true;
|
|
20538
|
+
await new Promise((r) => setTimeout(r, START_POLL_INTERVAL_MS));
|
|
20539
|
+
}
|
|
20540
|
+
return false;
|
|
20541
|
+
}
|
|
20542
|
+
async function signalDaemonStop() {
|
|
20543
|
+
const pid = await readDaemonPid();
|
|
20544
|
+
if (pid === null || !isPidAlive(pid))
|
|
20545
|
+
return false;
|
|
20546
|
+
try {
|
|
20547
|
+
process.kill(pid, "SIGTERM");
|
|
20548
|
+
return true;
|
|
20549
|
+
} catch {
|
|
20550
|
+
return false;
|
|
20551
|
+
}
|
|
20552
|
+
}
|
|
20553
|
+
function buildDaemonLifecycle(client, options = {}) {
|
|
20554
|
+
const manager = options.serviceManager !== void 0 ? options.serviceManager : detectServiceManager();
|
|
20555
|
+
const controllerFor = options.controllerFor ?? ((m) => createDaemonServiceController(m));
|
|
20556
|
+
let controller = null;
|
|
20557
|
+
function serviceController() {
|
|
20558
|
+
if (manager === null)
|
|
20559
|
+
return null;
|
|
20560
|
+
if (controller === null) {
|
|
20561
|
+
try {
|
|
20562
|
+
controller = controllerFor(manager);
|
|
20563
|
+
} catch {
|
|
20564
|
+
return null;
|
|
20565
|
+
}
|
|
20566
|
+
}
|
|
20567
|
+
return controller;
|
|
20568
|
+
}
|
|
20167
20569
|
return {
|
|
20168
20570
|
async start() {
|
|
20169
20571
|
if (await client.ping())
|
|
20170
20572
|
return { started: false, alreadyRunning: true };
|
|
20171
|
-
const
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20175
|
-
|
|
20176
|
-
|
|
20177
|
-
|
|
20178
|
-
|
|
20179
|
-
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
while (Date.now() < deadline) {
|
|
20183
|
-
await new Promise((r) => setTimeout(r, START_POLL_INTERVAL_MS));
|
|
20184
|
-
if (await client.ping())
|
|
20185
|
-
return { started: true, alreadyRunning: false };
|
|
20186
|
-
}
|
|
20187
|
-
return { started: false, alreadyRunning: false };
|
|
20573
|
+
const svc = serviceController();
|
|
20574
|
+
if (svc !== null) {
|
|
20575
|
+
try {
|
|
20576
|
+
svc.register(buildServiceSpec());
|
|
20577
|
+
if (await waitForHealth(client))
|
|
20578
|
+
return { started: true, alreadyRunning: false };
|
|
20579
|
+
return { started: false, alreadyRunning: false };
|
|
20580
|
+
} catch {
|
|
20581
|
+
}
|
|
20582
|
+
}
|
|
20583
|
+
return spawnDaemonAndWait(client);
|
|
20188
20584
|
},
|
|
20189
20585
|
async stop() {
|
|
20190
|
-
const
|
|
20191
|
-
if (
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
|
|
20196
|
-
|
|
20197
|
-
return { stopped: false };
|
|
20586
|
+
const svc = serviceController();
|
|
20587
|
+
if (svc !== null) {
|
|
20588
|
+
try {
|
|
20589
|
+
svc.stop(buildServiceSpec());
|
|
20590
|
+
return { stopped: true };
|
|
20591
|
+
} catch {
|
|
20592
|
+
}
|
|
20198
20593
|
}
|
|
20594
|
+
return { stopped: await signalDaemonStop() };
|
|
20199
20595
|
},
|
|
20200
20596
|
async status() {
|
|
20201
20597
|
const pid = await readDaemonPid();
|
|
20202
20598
|
const running = pid !== null && isPidAlive(pid);
|
|
20203
|
-
|
|
20599
|
+
const svc = serviceController();
|
|
20600
|
+
let serviceManager;
|
|
20601
|
+
if (svc !== null) {
|
|
20602
|
+
try {
|
|
20603
|
+
if (svc.isRegistered(buildServiceSpec()))
|
|
20604
|
+
serviceManager = svc.manager;
|
|
20605
|
+
} catch {
|
|
20606
|
+
}
|
|
20607
|
+
}
|
|
20608
|
+
if (running) {
|
|
20609
|
+
return serviceManager !== void 0 ? { running, pid, port: DAEMON_PORT, serviceManager } : { running, pid, port: DAEMON_PORT };
|
|
20610
|
+
}
|
|
20611
|
+
return serviceManager !== void 0 ? { running: false, port: DAEMON_PORT, serviceManager } : { running: false, port: DAEMON_PORT };
|
|
20612
|
+
},
|
|
20613
|
+
async restart() {
|
|
20614
|
+
const svc = serviceController();
|
|
20615
|
+
if (svc !== null && svc.isRegistered(buildServiceSpec())) {
|
|
20616
|
+
try {
|
|
20617
|
+
svc.restart(buildServiceSpec());
|
|
20618
|
+
const ok2 = await waitForHealth(client);
|
|
20619
|
+
return { restarted: ok2, viaService: true };
|
|
20620
|
+
} catch {
|
|
20621
|
+
}
|
|
20622
|
+
}
|
|
20623
|
+
await signalDaemonStop();
|
|
20624
|
+
const { started, alreadyRunning } = await spawnDaemonAndWait(client);
|
|
20625
|
+
return { restarted: started || alreadyRunning, viaService: false };
|
|
20204
20626
|
}
|
|
20205
20627
|
};
|
|
20206
20628
|
}
|