jfl 0.2.3 → 0.2.5
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 +399 -423
- package/dist/commands/agent.d.ts +7 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +170 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +134 -2
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/digest.d.ts +6 -0
- package/dist/commands/digest.d.ts.map +1 -0
- package/dist/commands/digest.js +126 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +236 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/flows.d.ts +7 -0
- package/dist/commands/flows.d.ts.map +1 -0
- package/dist/commands/flows.js +264 -0
- package/dist/commands/flows.js.map +1 -0
- package/dist/commands/hooks.d.ts +13 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +304 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/improve.d.ts +11 -0
- package/dist/commands/improve.d.ts.map +1 -0
- package/dist/commands/improve.js +77 -0
- package/dist/commands/improve.js.map +1 -0
- package/dist/commands/scope.d.ts +7 -0
- package/dist/commands/scope.d.ts.map +1 -0
- package/dist/commands/scope.js +227 -0
- package/dist/commands/scope.js.map +1 -0
- package/dist/commands/service-validate.js +7 -1
- package/dist/commands/service-validate.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +23 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +6 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/index.js +243 -46
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-manifest.d.ts +35 -0
- package/dist/lib/agent-manifest.d.ts.map +1 -0
- package/dist/lib/agent-manifest.js +75 -0
- package/dist/lib/agent-manifest.js.map +1 -0
- package/dist/lib/flow-engine.d.ts +34 -0
- package/dist/lib/flow-engine.d.ts.map +1 -0
- package/dist/lib/flow-engine.js +366 -0
- package/dist/lib/flow-engine.js.map +1 -0
- package/dist/lib/hook-transformer.d.ts +11 -0
- package/dist/lib/hook-transformer.d.ts.map +1 -0
- package/dist/lib/hook-transformer.js +74 -0
- package/dist/lib/hook-transformer.js.map +1 -0
- package/dist/lib/kuva.d.ts +45 -0
- package/dist/lib/kuva.d.ts.map +1 -0
- package/dist/lib/kuva.js +131 -0
- package/dist/lib/kuva.js.map +1 -0
- package/dist/lib/map-event-bus.d.ts +2 -0
- package/dist/lib/map-event-bus.d.ts.map +1 -1
- package/dist/lib/map-event-bus.js +44 -4
- package/dist/lib/map-event-bus.js.map +1 -1
- package/dist/lib/memory-indexer.d.ts.map +1 -1
- package/dist/lib/memory-indexer.js +26 -2
- package/dist/lib/memory-indexer.js.map +1 -1
- package/dist/lib/model-pricing.d.ts +11 -0
- package/dist/lib/model-pricing.d.ts.map +1 -0
- package/dist/lib/model-pricing.js +27 -0
- package/dist/lib/model-pricing.js.map +1 -0
- package/dist/lib/peter-parker-bridge.d.ts +1 -0
- package/dist/lib/peter-parker-bridge.d.ts.map +1 -1
- package/dist/lib/peter-parker-bridge.js +29 -0
- package/dist/lib/peter-parker-bridge.js.map +1 -1
- package/dist/lib/service-gtm.d.ts +7 -0
- package/dist/lib/service-gtm.d.ts.map +1 -1
- package/dist/lib/service-gtm.js.map +1 -1
- package/dist/lib/stratus-client.d.ts +1 -0
- package/dist/lib/stratus-client.d.ts.map +1 -1
- package/dist/lib/stratus-client.js +33 -2
- package/dist/lib/stratus-client.js.map +1 -1
- package/dist/lib/stratus-rollout-test.d.ts +10 -0
- package/dist/lib/stratus-rollout-test.d.ts.map +1 -0
- package/dist/lib/stratus-rollout-test.js +412 -0
- package/dist/lib/stratus-rollout-test.js.map +1 -0
- package/dist/lib/telemetry-digest.d.ts +10 -0
- package/dist/lib/telemetry-digest.d.ts.map +1 -0
- package/dist/lib/telemetry-digest.js +359 -0
- package/dist/lib/telemetry-digest.js.map +1 -0
- package/dist/lib/telemetry.d.ts +35 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +320 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/training-tuples.d.ts +33 -0
- package/dist/lib/training-tuples.d.ts.map +1 -0
- package/dist/lib/training-tuples.js +273 -0
- package/dist/lib/training-tuples.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +17 -0
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/types/flows.d.ts +69 -0
- package/dist/types/flows.d.ts.map +1 -0
- package/dist/types/flows.js +10 -0
- package/dist/types/flows.js.map +1 -0
- package/dist/types/map.d.ts +10 -1
- package/dist/types/map.d.ts.map +1 -1
- package/dist/types/map.js.map +1 -1
- package/dist/types/telemetry-digest.d.ts +73 -0
- package/dist/types/telemetry-digest.d.ts.map +1 -0
- package/dist/types/telemetry-digest.js +5 -0
- package/dist/types/telemetry-digest.js.map +1 -0
- package/dist/types/telemetry.d.ts +69 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/telemetry.js +5 -0
- package/dist/types/telemetry.js.map +1 -0
- 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/dist/utils/settings-validator.d.ts +3 -2
- package/dist/utils/settings-validator.d.ts.map +1 -1
- package/dist/utils/settings-validator.js +25 -6
- package/dist/utils/settings-validator.js.map +1 -1
- package/package.json +3 -2
- package/scripts/session/fix-tracked-logs.sh +97 -0
- package/scripts/session/session-cleanup.sh +4 -1
- package/scripts/session/session-end.sh +10 -0
- package/scripts/session/session-init.sh +16 -0
- package/scripts/session/session-sync.sh +10 -0
- package/template/scripts/session/session-sync.sh +10 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsKH,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B7H"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @purpose Manage narrowly-scoped agents — init scaffolding, list, status
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
import { generateManifest, generatePolicy, generateLifecycle } from "../lib/agent-manifest.js";
|
|
8
|
+
function getAgentsDir() {
|
|
9
|
+
return path.join(process.cwd(), ".jfl", "agents");
|
|
10
|
+
}
|
|
11
|
+
function getFlowsDir() {
|
|
12
|
+
return path.join(process.cwd(), ".jfl", "flows");
|
|
13
|
+
}
|
|
14
|
+
async function initAgent(name, options = {}) {
|
|
15
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
16
|
+
console.log(chalk.red(`\n Invalid agent name: "${name}"`));
|
|
17
|
+
console.log(chalk.gray(" Use lowercase letters, numbers, and hyphens only\n"));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const agentDir = path.join(getAgentsDir(), name);
|
|
21
|
+
if (fs.existsSync(agentDir)) {
|
|
22
|
+
console.log(chalk.yellow(`\n Agent "${name}" already exists at .jfl/agents/${name}/\n`));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
26
|
+
const manifestContent = generateManifest(name, options.description);
|
|
27
|
+
fs.writeFileSync(path.join(agentDir, "manifest.yaml"), manifestContent);
|
|
28
|
+
const policyContent = generatePolicy();
|
|
29
|
+
fs.writeFileSync(path.join(agentDir, "policy.json"), policyContent);
|
|
30
|
+
const triggerPattern = "session:ended";
|
|
31
|
+
const lifecycleContent = generateLifecycle(name, triggerPattern);
|
|
32
|
+
const flowsDir = getFlowsDir();
|
|
33
|
+
fs.mkdirSync(flowsDir, { recursive: true });
|
|
34
|
+
fs.writeFileSync(path.join(flowsDir, `${name}.yaml`), lifecycleContent);
|
|
35
|
+
console.log(chalk.bold(`\n Agent scaffolded: ${name}\n`));
|
|
36
|
+
console.log(chalk.gray(" Created:"));
|
|
37
|
+
console.log(` .jfl/agents/${name}/manifest.yaml`);
|
|
38
|
+
console.log(` .jfl/agents/${name}/policy.json`);
|
|
39
|
+
console.log(` .jfl/flows/${name}.yaml`);
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(chalk.gray(" Next steps:"));
|
|
42
|
+
console.log(` 1. Edit manifest.yaml — set triggers, capabilities, runtime`);
|
|
43
|
+
console.log(` 2. Edit policy.json — set cost limits, approval gates`);
|
|
44
|
+
console.log(` 3. Edit .jfl/flows/${name}.yaml — customize lifecycle flow`);
|
|
45
|
+
console.log(` 4. Run ${chalk.cyan("jfl agent status " + name)} to verify`);
|
|
46
|
+
console.log();
|
|
47
|
+
}
|
|
48
|
+
async function listAgents() {
|
|
49
|
+
const agentsDir = getAgentsDir();
|
|
50
|
+
console.log(chalk.bold("\n Registered Agents\n"));
|
|
51
|
+
if (!fs.existsSync(agentsDir)) {
|
|
52
|
+
console.log(chalk.gray(" No agents registered."));
|
|
53
|
+
console.log(chalk.gray(` Run ${chalk.cyan("jfl agent init <name>")} to create one.\n`));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const entries = fs.readdirSync(agentsDir).filter(f => fs.statSync(path.join(agentsDir, f)).isDirectory());
|
|
57
|
+
if (entries.length === 0) {
|
|
58
|
+
console.log(chalk.gray(" No agents registered."));
|
|
59
|
+
console.log(chalk.gray(` Run ${chalk.cyan("jfl agent init <name>")} to create one.\n`));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const name of entries) {
|
|
63
|
+
const manifestPath = path.join(agentsDir, name, "manifest.yaml");
|
|
64
|
+
const policyPath = path.join(agentsDir, name, "policy.json");
|
|
65
|
+
const hasManifest = fs.existsSync(manifestPath);
|
|
66
|
+
const hasPolicy = fs.existsSync(policyPath);
|
|
67
|
+
let description = "";
|
|
68
|
+
let agentType = "";
|
|
69
|
+
if (hasManifest) {
|
|
70
|
+
try {
|
|
71
|
+
const { parse } = await import("yaml");
|
|
72
|
+
const manifest = parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
73
|
+
description = manifest.description || "";
|
|
74
|
+
agentType = manifest.type || "";
|
|
75
|
+
}
|
|
76
|
+
catch { }
|
|
77
|
+
}
|
|
78
|
+
const status = hasManifest && hasPolicy ? chalk.green("ok") : chalk.yellow("incomplete");
|
|
79
|
+
const typeTag = agentType ? chalk.gray(` [${agentType}]`) : "";
|
|
80
|
+
const desc = description ? chalk.gray(` — ${description}`) : "";
|
|
81
|
+
console.log(` ${status} ${chalk.bold(name)}${typeTag}${desc}`);
|
|
82
|
+
}
|
|
83
|
+
console.log();
|
|
84
|
+
}
|
|
85
|
+
async function statusAgent(name) {
|
|
86
|
+
const agentDir = path.join(getAgentsDir(), name);
|
|
87
|
+
if (!fs.existsSync(agentDir)) {
|
|
88
|
+
console.log(chalk.red(`\n Agent "${name}" not found.`));
|
|
89
|
+
console.log(chalk.gray(` Run ${chalk.cyan("jfl agent init " + name)} to create it.\n`));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log(chalk.bold(`\n Agent: ${name}\n`));
|
|
93
|
+
const manifestPath = path.join(agentDir, "manifest.yaml");
|
|
94
|
+
const policyPath = path.join(agentDir, "policy.json");
|
|
95
|
+
const flowPath = path.join(getFlowsDir(), `${name}.yaml`);
|
|
96
|
+
const checks = [
|
|
97
|
+
{ file: "manifest.yaml", path: manifestPath },
|
|
98
|
+
{ file: "policy.json", path: policyPath },
|
|
99
|
+
{ file: `flows/${name}.yaml`, path: flowPath },
|
|
100
|
+
];
|
|
101
|
+
for (const check of checks) {
|
|
102
|
+
if (fs.existsSync(check.path)) {
|
|
103
|
+
console.log(chalk.green(" [ok] ") + check.file);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(chalk.red(" [!!] ") + check.file + chalk.gray(" — missing"));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (fs.existsSync(manifestPath)) {
|
|
110
|
+
try {
|
|
111
|
+
const { parse } = await import("yaml");
|
|
112
|
+
const manifest = parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(chalk.gray(" Type: ") + (manifest.type || "unknown"));
|
|
115
|
+
console.log(chalk.gray(" Version: ") + (manifest.version || "0.0.0"));
|
|
116
|
+
if (manifest.triggers?.length) {
|
|
117
|
+
const triggers = manifest.triggers.map((t) => t.pattern || t.schedule).join(", ");
|
|
118
|
+
console.log(chalk.gray(" Triggers: ") + triggers);
|
|
119
|
+
}
|
|
120
|
+
if (manifest.capabilities?.length) {
|
|
121
|
+
console.log(chalk.gray(" Capabilities: ") + manifest.capabilities.join(", "));
|
|
122
|
+
}
|
|
123
|
+
if (manifest.runtime?.command) {
|
|
124
|
+
console.log(chalk.gray(" Runtime: ") + manifest.runtime.command + " " + (manifest.runtime.args || []).join(" "));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
}
|
|
129
|
+
if (fs.existsSync(policyPath)) {
|
|
130
|
+
try {
|
|
131
|
+
const policy = JSON.parse(fs.readFileSync(policyPath, "utf-8"));
|
|
132
|
+
console.log(chalk.gray(" Cost limit: ") + `$${policy.cost_limit_usd}`);
|
|
133
|
+
console.log(chalk.gray(" Approval: ") + policy.approval_gate);
|
|
134
|
+
console.log(chalk.gray(" Max conc.: ") + policy.max_concurrent);
|
|
135
|
+
}
|
|
136
|
+
catch { }
|
|
137
|
+
}
|
|
138
|
+
console.log();
|
|
139
|
+
}
|
|
140
|
+
export async function agentCommand(action, nameOrOptions, options) {
|
|
141
|
+
switch (action) {
|
|
142
|
+
case "init":
|
|
143
|
+
if (!nameOrOptions) {
|
|
144
|
+
console.log(chalk.red("\n Agent name required."));
|
|
145
|
+
console.log(chalk.gray(" Usage: jfl agent init <name>\n"));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
await initAgent(nameOrOptions, options || {});
|
|
149
|
+
break;
|
|
150
|
+
case "list":
|
|
151
|
+
await listAgents();
|
|
152
|
+
break;
|
|
153
|
+
case "status":
|
|
154
|
+
if (!nameOrOptions) {
|
|
155
|
+
console.log(chalk.red("\n Agent name required."));
|
|
156
|
+
console.log(chalk.gray(" Usage: jfl agent status <name>\n"));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
await statusAgent(nameOrOptions);
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
console.log(chalk.bold("\n jfl agent — Manage narrowly-scoped agents\n"));
|
|
163
|
+
console.log(chalk.gray(" Commands:"));
|
|
164
|
+
console.log(" jfl agent init <name> Scaffold a new agent (manifest + policy + flows)");
|
|
165
|
+
console.log(" jfl agent list List registered agents");
|
|
166
|
+
console.log(" jfl agent status <name> Show agent health and config");
|
|
167
|
+
console.log();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/commands/agent.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;AAoiCH,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,iBAwenE"}
|
|
@@ -21,7 +21,10 @@ import { getProjectPort } from "../utils/context-hub-port.js";
|
|
|
21
21
|
import { getConfigValue, setConfig } from "../utils/jfl-config.js";
|
|
22
22
|
import Conf from "conf";
|
|
23
23
|
import { MAPEventBus } from "../lib/map-event-bus.js";
|
|
24
|
+
import { FlowEngine } from "../lib/flow-engine.js";
|
|
24
25
|
import { WebSocketServer } from "ws";
|
|
26
|
+
import { telemetry } from "../lib/telemetry.js";
|
|
27
|
+
import { transformHookPayload } from "../lib/hook-transformer.js";
|
|
25
28
|
const PID_FILE = ".jfl/context-hub.pid";
|
|
26
29
|
const LOG_FILE = ".jfl/logs/context-hub.log";
|
|
27
30
|
const TOKEN_FILE = ".jfl/context-hub.token";
|
|
@@ -417,6 +420,32 @@ function getUnifiedContext(projectRoot, query, taskType) {
|
|
|
417
420
|
// ============================================================================
|
|
418
421
|
function createServer(projectRoot, port, eventBus) {
|
|
419
422
|
const server = http.createServer((req, res) => {
|
|
423
|
+
const requestStart = Date.now();
|
|
424
|
+
const pathname = new URL(req.url || "/", `http://localhost:${port}`).pathname;
|
|
425
|
+
// Intercept writeHead to capture status code for telemetry
|
|
426
|
+
let capturedStatus = 200;
|
|
427
|
+
const originalWriteHead = res.writeHead.bind(res);
|
|
428
|
+
res.writeHead = function (statusCode, ...args) {
|
|
429
|
+
capturedStatus = statusCode;
|
|
430
|
+
return originalWriteHead(statusCode, ...args);
|
|
431
|
+
};
|
|
432
|
+
// Track request on response finish (skip health/OPTIONS/dashboard)
|
|
433
|
+
const shouldTrack = req.method !== "OPTIONS"
|
|
434
|
+
&& pathname !== "/health"
|
|
435
|
+
&& !pathname.startsWith("/dashboard");
|
|
436
|
+
if (shouldTrack) {
|
|
437
|
+
res.on('finish', () => {
|
|
438
|
+
telemetry.track({
|
|
439
|
+
category: 'context_hub',
|
|
440
|
+
event: 'context_hub:request',
|
|
441
|
+
endpoint: pathname,
|
|
442
|
+
method: req.method,
|
|
443
|
+
status_code: capturedStatus,
|
|
444
|
+
duration_ms: Date.now() - requestStart,
|
|
445
|
+
hub_port: port,
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
420
449
|
// CORS - include Authorization header
|
|
421
450
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
422
451
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
@@ -446,8 +475,56 @@ function createServer(projectRoot, port, eventBus) {
|
|
|
446
475
|
});
|
|
447
476
|
return;
|
|
448
477
|
}
|
|
478
|
+
// Hook ingestion (Claude Code HTTP hooks)
|
|
479
|
+
// No auth required — localhost-only. Always returns 200.
|
|
480
|
+
if (url.pathname === "/api/hooks" && req.method === "POST") {
|
|
481
|
+
const remoteAddr = req.socket.remoteAddress || "";
|
|
482
|
+
const isLocalhost = remoteAddr === "127.0.0.1" || remoteAddr === "::1" || remoteAddr === "::ffff:127.0.0.1";
|
|
483
|
+
if (!isLocalhost) {
|
|
484
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
485
|
+
res.end(JSON.stringify({ error: "localhost only" }));
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
let body = "";
|
|
489
|
+
let bodySize = 0;
|
|
490
|
+
const MAX_BODY = 64 * 1024;
|
|
491
|
+
req.on("data", (chunk) => {
|
|
492
|
+
bodySize += typeof chunk === "string" ? chunk.length : chunk.byteLength;
|
|
493
|
+
if (bodySize <= MAX_BODY) {
|
|
494
|
+
body += chunk;
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
req.on("end", () => {
|
|
498
|
+
try {
|
|
499
|
+
if (bodySize > MAX_BODY) {
|
|
500
|
+
console.warn(`[hooks] Dropped oversized payload: ${bodySize} bytes`);
|
|
501
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
502
|
+
res.end(JSON.stringify({ ok: true, dropped: true }));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
const payload = JSON.parse(body);
|
|
506
|
+
const partial = transformHookPayload(payload);
|
|
507
|
+
if (eventBus) {
|
|
508
|
+
eventBus.emit(partial);
|
|
509
|
+
}
|
|
510
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
511
|
+
res.end(JSON.stringify({ ok: true }));
|
|
512
|
+
}
|
|
513
|
+
catch (err) {
|
|
514
|
+
console.warn(`[hooks] Parse error: ${err.message}`);
|
|
515
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
516
|
+
res.end(JSON.stringify({ ok: true, parse_error: true }));
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
449
521
|
// All other endpoints require auth
|
|
450
522
|
if (!validateAuth(req, projectRoot, url)) {
|
|
523
|
+
telemetry.track({
|
|
524
|
+
category: 'context_hub',
|
|
525
|
+
event: 'context_hub:auth_failed',
|
|
526
|
+
endpoint: pathname,
|
|
527
|
+
});
|
|
451
528
|
res.writeHead(401, { "Content-Type": "application/json" });
|
|
452
529
|
res.end(JSON.stringify({
|
|
453
530
|
error: "Unauthorized",
|
|
@@ -479,6 +556,15 @@ function createServer(projectRoot, port, eventBus) {
|
|
|
479
556
|
if (maxItems && context.items.length > maxItems) {
|
|
480
557
|
context.items = context.items.slice(0, maxItems);
|
|
481
558
|
}
|
|
559
|
+
telemetry.track({
|
|
560
|
+
category: 'context_hub',
|
|
561
|
+
event: 'context_hub:context_loaded',
|
|
562
|
+
item_count: context.items.length,
|
|
563
|
+
journal_count: context.items.filter(i => i.source === 'journal').length,
|
|
564
|
+
knowledge_count: context.items.filter(i => i.source === 'knowledge').length,
|
|
565
|
+
code_count: context.items.filter(i => i.source === 'code').length,
|
|
566
|
+
query_length: query ? query.length : 0,
|
|
567
|
+
});
|
|
482
568
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
483
569
|
res.end(JSON.stringify(context));
|
|
484
570
|
}
|
|
@@ -501,10 +587,19 @@ function createServer(projectRoot, port, eventBus) {
|
|
|
501
587
|
res.end(JSON.stringify({ error: "query required" }));
|
|
502
588
|
return;
|
|
503
589
|
}
|
|
590
|
+
const searchStart = Date.now();
|
|
504
591
|
const context = getUnifiedContext(projectRoot, query);
|
|
505
592
|
context.items = context.items
|
|
506
593
|
.filter(item => item.relevance && item.relevance > 0)
|
|
507
594
|
.slice(0, maxItems);
|
|
595
|
+
telemetry.track({
|
|
596
|
+
category: 'context_hub',
|
|
597
|
+
event: 'context_hub:search',
|
|
598
|
+
result_count: context.items.length,
|
|
599
|
+
duration_ms: Date.now() - searchStart,
|
|
600
|
+
has_query: true,
|
|
601
|
+
query_length: query.length,
|
|
602
|
+
});
|
|
508
603
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
509
604
|
res.end(JSON.stringify(context));
|
|
510
605
|
}
|
|
@@ -1319,7 +1414,14 @@ export async function contextHubCommand(action, options = {}) {
|
|
|
1319
1414
|
process.on("uncaughtException", (err) => {
|
|
1320
1415
|
console.error(`Uncaught exception: ${err.message}`);
|
|
1321
1416
|
console.error(err.stack);
|
|
1322
|
-
|
|
1417
|
+
telemetry.track({
|
|
1418
|
+
category: 'error',
|
|
1419
|
+
event: 'error:hub_crash',
|
|
1420
|
+
error_type: err.constructor.name,
|
|
1421
|
+
error_code: err.code || undefined,
|
|
1422
|
+
hub_port: port,
|
|
1423
|
+
hub_uptime_s: isListening ? Math.floor((Date.now() - hubStartTime) / 1000) : 0,
|
|
1424
|
+
});
|
|
1323
1425
|
});
|
|
1324
1426
|
process.on("unhandledRejection", (reason, promise) => {
|
|
1325
1427
|
console.error(`Unhandled rejection at ${promise}: ${reason}`);
|
|
@@ -1327,17 +1429,30 @@ export async function contextHubCommand(action, options = {}) {
|
|
|
1327
1429
|
});
|
|
1328
1430
|
server.on("error", (err) => {
|
|
1329
1431
|
console.error(`Server error: ${err.message}`);
|
|
1432
|
+
telemetry.track({
|
|
1433
|
+
category: 'error',
|
|
1434
|
+
event: 'error:hub_server',
|
|
1435
|
+
error_type: err.constructor.name,
|
|
1436
|
+
error_code: err.code || undefined,
|
|
1437
|
+
hub_port: port,
|
|
1438
|
+
});
|
|
1330
1439
|
if (err.code === "EADDRINUSE") {
|
|
1331
1440
|
console.error(`Port ${port} is already in use. Exiting.`);
|
|
1332
1441
|
process.exit(1);
|
|
1333
1442
|
}
|
|
1334
|
-
// For other errors, don't exit
|
|
1335
1443
|
});
|
|
1444
|
+
const hubStartTime = Date.now();
|
|
1336
1445
|
server.listen(port, async () => {
|
|
1337
1446
|
isListening = true;
|
|
1338
1447
|
const timestamp = new Date().toISOString();
|
|
1339
1448
|
console.log(`[${timestamp}] Context Hub listening on port ${port}`);
|
|
1340
1449
|
console.log(`[${timestamp}] PID: ${process.pid}`);
|
|
1450
|
+
telemetry.track({
|
|
1451
|
+
category: 'context_hub',
|
|
1452
|
+
event: 'context_hub:started',
|
|
1453
|
+
hub_port: port,
|
|
1454
|
+
duration_ms: Date.now() - hubStartTime,
|
|
1455
|
+
});
|
|
1341
1456
|
// Initialize memory system
|
|
1342
1457
|
try {
|
|
1343
1458
|
await initializeDatabase();
|
|
@@ -1355,6 +1470,17 @@ export async function contextHubCommand(action, options = {}) {
|
|
|
1355
1470
|
console.error(`[${timestamp}] Failed to initialize memory system:`, err.message);
|
|
1356
1471
|
// Don't exit - memory is optional
|
|
1357
1472
|
}
|
|
1473
|
+
// Start flow engine
|
|
1474
|
+
try {
|
|
1475
|
+
const flowEngine = new FlowEngine(eventBus, projectRoot);
|
|
1476
|
+
const flowCount = await flowEngine.start();
|
|
1477
|
+
if (flowCount > 0) {
|
|
1478
|
+
console.log(`[${timestamp}] Flow engine started with ${flowCount} active flow(s)`);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
catch (err) {
|
|
1482
|
+
console.error(`[${timestamp}] Failed to start flow engine:`, err.message);
|
|
1483
|
+
}
|
|
1358
1484
|
console.log(`[${timestamp}] MAP event bus initialized (buffer: 1000, subscribers: ${eventBus.getSubscriberCount()})`);
|
|
1359
1485
|
console.log(`[${timestamp}] Ready to serve requests`);
|
|
1360
1486
|
});
|
|
@@ -1378,6 +1504,12 @@ export async function contextHubCommand(action, options = {}) {
|
|
|
1378
1504
|
console.log(`[${timestamp}] Received ${signal}`);
|
|
1379
1505
|
console.log(`[${timestamp}] PID: ${process.pid}, Parent PID: ${process.ppid}`);
|
|
1380
1506
|
console.log(`[${timestamp}] Shutting down...`);
|
|
1507
|
+
telemetry.track({
|
|
1508
|
+
category: 'context_hub',
|
|
1509
|
+
event: 'context_hub:stopped',
|
|
1510
|
+
hub_port: port,
|
|
1511
|
+
hub_uptime_s: Math.floor((Date.now() - hubStartTime) / 1000),
|
|
1512
|
+
});
|
|
1381
1513
|
server.close(() => {
|
|
1382
1514
|
eventBus.destroy();
|
|
1383
1515
|
console.log(`[${new Date().toISOString()}] Server closed`);
|