jfl 0.3.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +469 -36
- package/dist/commands/ci-setup.d.ts +5 -0
- package/dist/commands/ci-setup.d.ts.map +1 -0
- package/dist/commands/ci-setup.js +82 -0
- package/dist/commands/ci-setup.js.map +1 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +154 -0
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/flows.d.ts +4 -1
- package/dist/commands/flows.d.ts.map +1 -1
- package/dist/commands/flows.js +160 -1
- package/dist/commands/flows.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +42 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/peter.d.ts +2 -1
- package/dist/commands/peter.d.ts.map +1 -1
- package/dist/commands/peter.js +415 -2
- package/dist/commands/peter.js.map +1 -1
- package/dist/commands/pi.d.ts +21 -0
- package/dist/commands/pi.d.ts.map +1 -0
- package/dist/commands/pi.js +154 -0
- package/dist/commands/pi.js.map +1 -0
- package/dist/commands/portfolio.d.ts.map +1 -1
- package/dist/commands/portfolio.js +22 -69
- package/dist/commands/portfolio.js.map +1 -1
- package/dist/commands/predict.d.ts +6 -0
- package/dist/commands/predict.d.ts.map +1 -0
- package/dist/commands/predict.js +234 -0
- package/dist/commands/predict.js.map +1 -0
- package/dist/commands/synopsis.d.ts +44 -0
- package/dist/commands/synopsis.d.ts.map +1 -1
- package/dist/commands/synopsis.js +1 -1
- package/dist/commands/synopsis.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +107 -5
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/viz.d.ts +7 -0
- package/dist/commands/viz.d.ts.map +1 -0
- package/dist/commands/viz.js +460 -0
- package/dist/commands/viz.js.map +1 -0
- package/dist/dashboard/index.d.ts +4 -5
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +57 -146
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard-static/assets/index-B6kRK9Rq.js +116 -0
- package/dist/dashboard-static/assets/index-BpdKJPLu.css +1 -0
- package/dist/dashboard-static/index.html +16 -0
- package/dist/index.js +126 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/flow-engine.d.ts +3 -0
- package/dist/lib/flow-engine.d.ts.map +1 -1
- package/dist/lib/flow-engine.js +70 -1
- package/dist/lib/flow-engine.js.map +1 -1
- package/dist/lib/hub-client.d.ts +80 -0
- package/dist/lib/hub-client.d.ts.map +1 -0
- package/dist/lib/hub-client.js +46 -0
- package/dist/lib/hub-client.js.map +1 -0
- package/dist/lib/predictor.d.ts +99 -0
- package/dist/lib/predictor.d.ts.map +1 -0
- package/dist/lib/predictor.js +394 -0
- package/dist/lib/predictor.js.map +1 -0
- package/dist/lib/service-gtm.d.ts +86 -51
- package/dist/lib/service-gtm.d.ts.map +1 -1
- package/dist/lib/service-gtm.js +417 -242
- package/dist/lib/service-gtm.js.map +1 -1
- package/dist/lib/telemetry-agent.d.ts +57 -0
- package/dist/lib/telemetry-agent.d.ts.map +1 -0
- package/dist/lib/telemetry-agent.js +268 -0
- package/dist/lib/telemetry-agent.js.map +1 -0
- package/dist/lib/telemetry-digest.d.ts.map +1 -1
- package/dist/lib/telemetry-digest.js +17 -17
- package/dist/lib/telemetry-digest.js.map +1 -1
- package/dist/lib/telemetry.d.ts +1 -0
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +14 -6
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/mcp/context-hub-mcp.js +0 -0
- package/dist/mcp/service-registry-mcp.js +0 -0
- package/dist/types/map.d.ts +1 -1
- package/dist/types/map.d.ts.map +1 -1
- package/dist/types/map.js.map +1 -1
- package/dist/utils/jfl-paths.d.ts +1 -0
- package/dist/utils/jfl-paths.d.ts.map +1 -1
- package/dist/utils/jfl-paths.js +1 -0
- package/dist/utils/jfl-paths.js.map +1 -1
- package/package.json +7 -2
- package/scripts/generate-changesets.sh +113 -0
- package/scripts/pp-branch-pr.sh +115 -0
- package/template/.github/workflows/jfl-eval.yml +448 -0
- package/template/.github/workflows/jfl-review.yml +371 -0
- package/template/.jfl/flows/self-driving.yaml +190 -0
- package/dist/dashboard/components.d.ts +0 -7
- package/dist/dashboard/components.d.ts.map +0 -1
- package/dist/dashboard/components.js +0 -575
- package/dist/dashboard/components.js.map +0 -1
- package/dist/dashboard/pages.d.ts +0 -7
- package/dist/dashboard/pages.d.ts.map +0 -1
- package/dist/dashboard/pages.js +0 -1580
- package/dist/dashboard/pages.js.map +0 -1
- package/dist/dashboard/styles.d.ts +0 -7
- package/dist/dashboard/styles.d.ts.map +0 -1
- package/dist/dashboard/styles.js +0 -1110
- package/dist/dashboard/styles.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-setup.d.ts","sourceRoot":"","sources":["../../src/commands/ci-setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAsEpD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @purpose CLI command for `jfl ci setup` — deploys eval + review CI workflows to a project
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
6
|
+
import { join, dirname } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const TEMPLATE_DIR = join(__dirname, "../../template/.github/workflows");
|
|
12
|
+
const WORKFLOW_FILES = ["jfl-eval.yml", "jfl-review.yml"];
|
|
13
|
+
function getRepoSlug() {
|
|
14
|
+
try {
|
|
15
|
+
const remote = execSync("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
16
|
+
const match = remote.match(/github\.com[:/](.+?)(?:\.git)?$/);
|
|
17
|
+
return match?.[1] ?? "OWNER/REPO";
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return "OWNER/REPO";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function ciSetupCommand() {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
const targetDir = join(cwd, ".github", "workflows");
|
|
26
|
+
if (!existsSync(TEMPLATE_DIR)) {
|
|
27
|
+
console.log(chalk.red("\n Template workflows not found at: " + TEMPLATE_DIR));
|
|
28
|
+
console.log(chalk.gray(" This usually means the jfl CLI package is incomplete. Try: npm install -g jfl\n"));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
if (!existsSync(join(cwd, ".github"))) {
|
|
32
|
+
mkdirSync(join(cwd, ".github"), { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
if (!existsSync(targetDir)) {
|
|
35
|
+
mkdirSync(targetDir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
let deployed = 0;
|
|
38
|
+
let skipped = 0;
|
|
39
|
+
for (const file of WORKFLOW_FILES) {
|
|
40
|
+
const src = join(TEMPLATE_DIR, file);
|
|
41
|
+
const dest = join(targetDir, file);
|
|
42
|
+
if (!existsSync(src)) {
|
|
43
|
+
console.log(chalk.yellow(` Template missing: ${file} — skipping`));
|
|
44
|
+
skipped++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const templateContent = readFileSync(src, "utf-8");
|
|
48
|
+
if (existsSync(dest)) {
|
|
49
|
+
const existingContent = readFileSync(dest, "utf-8");
|
|
50
|
+
if (existingContent === templateContent) {
|
|
51
|
+
console.log(chalk.gray(` ${file} — already up to date`));
|
|
52
|
+
deployed++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
console.log(chalk.yellow(` ${file} — exists and differs from template, overwriting`));
|
|
56
|
+
}
|
|
57
|
+
writeFileSync(dest, templateContent);
|
|
58
|
+
console.log(chalk.green(` ${file} — deployed`));
|
|
59
|
+
deployed++;
|
|
60
|
+
}
|
|
61
|
+
const repoSlug = getRepoSlug();
|
|
62
|
+
console.log();
|
|
63
|
+
if (deployed > 0) {
|
|
64
|
+
console.log(chalk.green(" CI workflows deployed to .github/workflows/"));
|
|
65
|
+
}
|
|
66
|
+
if (skipped > 0) {
|
|
67
|
+
console.log(chalk.yellow(` ${skipped} workflow(s) skipped (template missing)`));
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
console.log(chalk.bold(" Required GitHub secrets") + chalk.gray(` (set at github.com/${repoSlug}/settings/secrets):`));
|
|
71
|
+
console.log(chalk.cyan(" OPENAI_API_KEY") + chalk.gray(" — For AI quality assessment and code review"));
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(chalk.bold(" Optional:"));
|
|
74
|
+
console.log(chalk.cyan(" OPENROUTER_API_KEY") + chalk.gray(" — Fallback if OpenAI unavailable"));
|
|
75
|
+
console.log(chalk.cyan(" JFL_HUB_URL") + chalk.gray(" — Context Hub URL for real-time dashboard updates"));
|
|
76
|
+
console.log(chalk.cyan(" JFL_HUB_TOKEN") + chalk.gray(" — Auth token for hub API"));
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.gray(" The eval workflow runs on PRs from Peter Parker (pp/ branches)."));
|
|
79
|
+
console.log(chalk.gray(" To trigger manually, add the 'run-eval' or 'ai-review' label to any PR."));
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=ci-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-setup.js","sourceRoot":"","sources":["../../src/commands/ci-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-hub.d.ts","sourceRoot":"","sources":["../../src/commands/context-hub.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"context-hub.d.ts","sourceRoot":"","sources":["../../src/commands/context-hub.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAg8CH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAiBjF;AA2ND,wBAAsB,qBAAqB,CAAC,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAiHxF;AAMD,wBAAsB,iBAAiB,CACrC,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,iBA+fnE"}
|
|
@@ -632,10 +632,16 @@ function createServer(projectRoot, port, eventBus, flowEngine) {
|
|
|
632
632
|
scope: cfg.context_scope || null,
|
|
633
633
|
registered_services: (cfg.registered_services || []).map((s) => ({
|
|
634
634
|
name: s.name,
|
|
635
|
+
path: s.path,
|
|
635
636
|
type: s.type,
|
|
636
637
|
status: s.status,
|
|
637
638
|
context_scope: s.context_scope || null,
|
|
638
639
|
})),
|
|
640
|
+
openclaw_agents: (cfg.openclaw_agents || []).map((a) => ({
|
|
641
|
+
id: a.id,
|
|
642
|
+
runtime: a.runtime,
|
|
643
|
+
registered_at: a.registered_at,
|
|
644
|
+
})),
|
|
639
645
|
gtm_parent: cfg.gtm_parent || null,
|
|
640
646
|
portfolio_parent: cfg.portfolio_parent || null,
|
|
641
647
|
};
|
|
@@ -876,6 +882,38 @@ function createServer(projectRoot, port, eventBus, flowEngine) {
|
|
|
876
882
|
}
|
|
877
883
|
return;
|
|
878
884
|
}
|
|
885
|
+
// Synopsis (work summary)
|
|
886
|
+
if (url.pathname === "/api/synopsis" && req.method === "GET") {
|
|
887
|
+
try {
|
|
888
|
+
const hours = parseInt(url.searchParams.get("hours") || "24", 10);
|
|
889
|
+
const author = url.searchParams.get("author") || undefined;
|
|
890
|
+
const { generateSynopsis } = await import("./synopsis.js");
|
|
891
|
+
const synopsis = generateSynopsis(projectRoot, hours, author);
|
|
892
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
893
|
+
res.end(JSON.stringify(synopsis));
|
|
894
|
+
}
|
|
895
|
+
catch (err) {
|
|
896
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
897
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
898
|
+
}
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
// Prediction accuracy (Stratus)
|
|
902
|
+
if (url.pathname === "/api/eval/predictions" && req.method === "GET") {
|
|
903
|
+
try {
|
|
904
|
+
const { Predictor } = await import("../lib/predictor.js");
|
|
905
|
+
const predictor = new Predictor({ projectRoot });
|
|
906
|
+
const accuracy = predictor.getAccuracy();
|
|
907
|
+
const recent = predictor.getHistory(20).reverse();
|
|
908
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
909
|
+
res.end(JSON.stringify({ accuracy, recent }));
|
|
910
|
+
}
|
|
911
|
+
catch (err) {
|
|
912
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
913
|
+
res.end(JSON.stringify({ accuracy: { total: 0, resolved: 0, direction_accuracy: 0, mean_delta_error: 0, calibration: 0 }, recent: [] }));
|
|
914
|
+
}
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
879
917
|
// Cross-project health
|
|
880
918
|
if (url.pathname === "/api/projects" && req.method === "GET") {
|
|
881
919
|
const tracked = getTrackedProjects();
|
|
@@ -1005,6 +1043,39 @@ function createServer(projectRoot, port, eventBus, flowEngine) {
|
|
|
1005
1043
|
}
|
|
1006
1044
|
return;
|
|
1007
1045
|
}
|
|
1046
|
+
// Telemetry agent status
|
|
1047
|
+
if (url.pathname === "/api/telemetry/agent" && req.method === "GET") {
|
|
1048
|
+
const agent = server.__telemetryAgent;
|
|
1049
|
+
if (agent) {
|
|
1050
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1051
|
+
res.end(JSON.stringify(agent.getStatus()));
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1055
|
+
res.end(JSON.stringify({ running: false, lastRun: '', runCount: 0, lastInsights: [] }));
|
|
1056
|
+
}
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
// Telemetry agent: trigger manual run
|
|
1060
|
+
if (url.pathname === "/api/telemetry/agent/run" && req.method === "POST") {
|
|
1061
|
+
const agent = server.__telemetryAgent;
|
|
1062
|
+
if (agent) {
|
|
1063
|
+
try {
|
|
1064
|
+
const insights = await agent.run();
|
|
1065
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1066
|
+
res.end(JSON.stringify({ ok: true, insights }));
|
|
1067
|
+
}
|
|
1068
|
+
catch (err) {
|
|
1069
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1070
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1075
|
+
res.end(JSON.stringify({ error: "Telemetry agent not running" }));
|
|
1076
|
+
}
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1008
1079
|
// Flow definitions
|
|
1009
1080
|
if (url.pathname === "/api/flows" && req.method === "GET") {
|
|
1010
1081
|
if (!flowEngine) {
|
|
@@ -1061,6 +1132,72 @@ function createServer(projectRoot, port, eventBus, flowEngine) {
|
|
|
1061
1132
|
});
|
|
1062
1133
|
return;
|
|
1063
1134
|
}
|
|
1135
|
+
if (url.pathname.match(/^\/api\/flows\/[^/]+\/toggle$/) && req.method === "POST") {
|
|
1136
|
+
if (!flowEngine) {
|
|
1137
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1138
|
+
res.end(JSON.stringify({ error: "Flow engine not initialized" }));
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
const flowName = decodeURIComponent(url.pathname.split("/")[3]);
|
|
1142
|
+
let body = "";
|
|
1143
|
+
req.on("data", chunk => body += chunk);
|
|
1144
|
+
req.on("end", () => {
|
|
1145
|
+
try {
|
|
1146
|
+
const { enabled } = JSON.parse(body || "{}");
|
|
1147
|
+
const result = flowEngine.toggleFlow(flowName, enabled);
|
|
1148
|
+
if (!result) {
|
|
1149
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1150
|
+
res.end(JSON.stringify({ error: "Flow not found" }));
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1154
|
+
res.end(JSON.stringify({ ok: true, flow: flowName, enabled: result.enabled }));
|
|
1155
|
+
}
|
|
1156
|
+
catch (err) {
|
|
1157
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1158
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
1159
|
+
}
|
|
1160
|
+
});
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
if (url.pathname === "/api/actions/spawn" && req.method === "POST") {
|
|
1164
|
+
let body = "";
|
|
1165
|
+
req.on("data", chunk => body += chunk);
|
|
1166
|
+
req.on("end", () => {
|
|
1167
|
+
try {
|
|
1168
|
+
const { command, args, cwd, event_type, event_data } = JSON.parse(body || "{}");
|
|
1169
|
+
if (!command) {
|
|
1170
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1171
|
+
res.end(JSON.stringify({ error: "command required" }));
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const env = { ...process.env };
|
|
1175
|
+
delete env.ANTHROPIC_API_KEY;
|
|
1176
|
+
delete env.CLAUDE_CODE_ENTRYPOINT;
|
|
1177
|
+
const child = spawn(command, args || [], {
|
|
1178
|
+
cwd: cwd || projectRoot,
|
|
1179
|
+
detached: true,
|
|
1180
|
+
stdio: "ignore",
|
|
1181
|
+
env,
|
|
1182
|
+
});
|
|
1183
|
+
child.unref();
|
|
1184
|
+
if (event_type && eventBus) {
|
|
1185
|
+
eventBus.emit({
|
|
1186
|
+
type: event_type,
|
|
1187
|
+
source: "dashboard:action",
|
|
1188
|
+
data: event_data || { command, args, pid: child.pid },
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1192
|
+
res.end(JSON.stringify({ ok: true, pid: child.pid }));
|
|
1193
|
+
}
|
|
1194
|
+
catch (err) {
|
|
1195
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1196
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1064
1201
|
// 404
|
|
1065
1202
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1066
1203
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
@@ -1728,6 +1865,23 @@ export async function contextHubCommand(action, options = {}) {
|
|
|
1728
1865
|
catch (err) {
|
|
1729
1866
|
console.error(`[${timestamp}] Failed to start flow engine:`, err.message);
|
|
1730
1867
|
}
|
|
1868
|
+
// Start telemetry agent (periodic pattern detection)
|
|
1869
|
+
try {
|
|
1870
|
+
const { TelemetryAgent } = await import("../lib/telemetry-agent.js");
|
|
1871
|
+
const telemetryAgent = new TelemetryAgent({
|
|
1872
|
+
projectRoot,
|
|
1873
|
+
intervalMs: 30 * 60 * 1000,
|
|
1874
|
+
emitEvent: (type, data, source) => {
|
|
1875
|
+
eventBus.emit({ type: type, data, source: source || 'telemetry-agent' });
|
|
1876
|
+
},
|
|
1877
|
+
});
|
|
1878
|
+
telemetryAgent.start();
|
|
1879
|
+
server.__telemetryAgent = telemetryAgent;
|
|
1880
|
+
console.log(`[${timestamp}] Telemetry agent started (interval: 30m)`);
|
|
1881
|
+
}
|
|
1882
|
+
catch (err) {
|
|
1883
|
+
console.error(`[${timestamp}] Failed to start telemetry agent:`, err.message);
|
|
1884
|
+
}
|
|
1731
1885
|
console.log(`[${timestamp}] MAP event bus initialized (buffer: 1000, subscribers: ${eventBus.getSubscriberCount()})`);
|
|
1732
1886
|
console.log(`[${timestamp}] Ready to serve requests`);
|
|
1733
1887
|
});
|