triflux 10.3.4 → 10.7.0
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/LICENSE +21 -21
- package/bin/tfx-doctor-tui.mjs +1 -1
- package/bin/tfx-doctor.mjs +6 -1
- package/bin/tfx-profile.mjs +1 -1
- package/bin/tfx-setup-tui.mjs +1 -1
- package/bin/tfx-setup.mjs +6 -1
- package/bin/triflux.mjs +2396 -1140
- package/hooks/agent-route-guard.mjs +12 -8
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +19 -7
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +108 -24
- package/hooks/hook-registry.json +11 -0
- package/hooks/keyword-rules.json +6 -10
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/pipeline-stop.mjs +3 -6
- package/hooks/safety-guard.mjs +99 -28
- package/hooks/session-start-fast.mjs +143 -0
- package/hooks/subagent-verifier.mjs +5 -4
- package/hub/account-broker.mjs +256 -60
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +95 -57
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +67 -30
- package/hub/bridge.mjs +0 -1
- package/hub/cli-adapter-base.mjs +200 -48
- package/hub/codex-adapter.mjs +76 -96
- package/hub/codex-compat.mjs +3 -3
- package/hub/codex-preflight.mjs +63 -37
- package/hub/delegator/contracts.mjs +19 -23
- package/hub/delegator/index.mjs +3 -3
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +5 -5
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +89 -30
- package/hub/intent.mjs +161 -38
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/mcp-response-cache.mjs +66 -32
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +35 -37
- package/hub/lib/process-utils.mjs +106 -37
- package/hub/lib/spawn-trace.mjs +527 -0
- package/hub/lib/ssh-command.mjs +34 -4
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +57 -48
- package/hub/promote-penalties.mjs +25 -7
- package/hub/quality/deslop.mjs +70 -49
- package/hub/research.mjs +32 -25
- package/hub/router.mjs +240 -107
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +76 -28
- package/hub/server.mjs +4 -4
- package/hub/session-fingerprint.mjs +126 -60
- package/hub/state.mjs +84 -43
- package/hub/store-adapter.mjs +59 -26
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +22 -7
- package/hub/team/ansi.mjs +186 -122
- package/hub/team/backend.mjs +28 -10
- package/hub/team/cli/commands/attach.mjs +29 -9
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +32 -11
- package/hub/team/cli/commands/focus.mjs +38 -11
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +11 -4
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -31
- package/hub/team/cli/commands/start/parse-args.mjs +38 -11
- package/hub/team/cli/commands/start/start-headless.mjs +112 -36
- package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
- package/hub/team/cli/commands/start/start-mux.mjs +70 -21
- package/hub/team/cli/commands/start/start-wt.mjs +29 -12
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +1 -1
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +30 -8
- package/hub/team/cli/services/attach-fallback.mjs +31 -11
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +11 -4
- package/hub/team/cli/services/native-control.mjs +48 -21
- package/hub/team/cli/services/runtime-mode.mjs +2 -1
- package/hub/team/cli/services/state-store.mjs +25 -8
- package/hub/team/cli/services/task-model.mjs +16 -6
- package/hub/team/conductor-mesh-bridge.mjs +24 -23
- package/hub/team/conductor.mjs +8 -4
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +41 -21
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/handoff.mjs +31 -15
- package/hub/team/headless.mjs +2 -1
- package/hub/team/health-probe.mjs +69 -54
- package/hub/team/launcher-template.mjs +16 -13
- package/hub/team/native-supervisor.mjs +65 -21
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +119 -76
- package/hub/team/orchestrator.mjs +9 -4
- package/hub/team/pane.mjs +12 -7
- package/hub/team/process-cleanup.mjs +25 -16
- package/hub/team/psmux.mjs +491 -201
- package/hub/team/remote-probe.mjs +68 -52
- package/hub/team/remote-session.mjs +117 -59
- package/hub/team/remote-watcher.mjs +61 -33
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +3 -1
- package/hub/team/session.mjs +98 -34
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-locks.mjs +15 -13
- package/hub/team/swarm-planner.mjs +32 -21
- package/hub/team/swarm-reconciler.mjs +48 -23
- package/hub/team/tui-lite.mjs +266 -68
- package/hub/team/tui-remote-adapter.mjs +14 -10
- package/hub/team/tui-viewer.mjs +99 -43
- package/hub/team/tui.mjs +708 -271
- package/hub/team/worktree-lifecycle.mjs +152 -58
- package/hub/team/wt-manager.mjs +24 -14
- package/hub/token-mode.mjs +71 -71
- package/hub/tray.mjs +66 -23
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +192 -141
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +8 -8
- package/hub/workers/gemini-worker.mjs +115 -84
- package/hub/workers/interface.mjs +6 -1
- package/hub/workers/worker-utils.mjs +21 -14
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +162 -26
- package/hud/context-monitor.mjs +82 -41
- package/hud/hud-qos-status.mjs +129 -49
- package/hud/mission-board.mjs +6 -3
- package/hud/providers/claude.mjs +226 -115
- package/hud/providers/codex.mjs +62 -22
- package/hud/providers/gemini.mjs +168 -56
- package/hud/renderers.mjs +384 -119
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +78 -38
- package/mesh/index.mjs +11 -5
- package/mesh/mesh-budget.mjs +18 -9
- package/mesh/mesh-heartbeat.mjs +1 -1
- package/mesh/mesh-queue.mjs +3 -5
- package/mesh/mesh-router.mjs +5 -4
- package/package.json +2 -1
- package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
- package/scripts/__tests__/keyword-detector.test.mjs +77 -28
- package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
- package/scripts/__tests__/remote-spawn.test.mjs +10 -4
- package/scripts/__tests__/session-start-fast.test.mjs +36 -0
- package/scripts/__tests__/skill-template.test.mjs +98 -50
- package/scripts/__tests__/smoke.test.mjs +1 -1
- package/scripts/__tests__/spawn-trace.test.mjs +102 -0
- package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
- package/scripts/cache-doctor.mjs +11 -4
- package/scripts/cache-warmup.mjs +96 -37
- package/scripts/claudemd-sync.mjs +27 -17
- package/scripts/codex-gateway-preflight.mjs +52 -37
- package/scripts/codex-mcp-gateway-sync.mjs +59 -39
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/config-audit.mjs +232 -0
- package/scripts/convert-to-tmpl.mjs +54 -0
- package/scripts/cross-review-gate.mjs +35 -12
- package/scripts/cross-review-tracker.mjs +21 -8
- package/scripts/demo.mjs +35 -17
- package/scripts/doctor-diagnose.mjs +284 -0
- package/scripts/gen-skill-docs.mjs +7 -2
- package/scripts/gen-skill-manifest.mjs +2 -1
- package/scripts/headless-guard.mjs +86 -48
- package/scripts/hub-ensure.mjs +45 -26
- package/scripts/keyword-detector.mjs +41 -20
- package/scripts/keyword-rules-expander.mjs +47 -30
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +6 -3
- package/scripts/lib/env-probe.mjs +47 -28
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/keyword-rules.mjs +43 -19
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +377 -239
- package/scripts/lib/mcp-guard-engine.mjs +194 -79
- package/scripts/lib/mcp-manifest.mjs +23 -13
- package/scripts/lib/mcp-server-catalog.mjs +300 -63
- package/scripts/lib/psmux-info.mjs +11 -6
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-template.mjs +30 -7
- package/scripts/mcp-check.mjs +58 -39
- package/scripts/mcp-gateway-config.mjs +83 -39
- package/scripts/mcp-gateway-ensure.mjs +43 -35
- package/scripts/mcp-gateway-integration-test.mjs +70 -58
- package/scripts/mcp-gateway-start.mjs +126 -60
- package/scripts/mcp-gateway-verify.mjs +24 -22
- package/scripts/mcp-safety-guard.mjs +44 -11
- package/scripts/notion-read.mjs +199 -84
- package/scripts/pack.mjs +94 -89
- package/scripts/preflight-cache.mjs +27 -10
- package/scripts/preinstall.mjs +42 -13
- package/scripts/remote-spawn.mjs +309 -94
- package/scripts/run.cjs +8 -5
- package/scripts/session-spawn-helper.mjs +130 -39
- package/scripts/session-stale-cleanup.mjs +123 -0
- package/scripts/setup.mjs +941 -492
- package/scripts/test-lock.mjs +20 -7
- package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
- package/scripts/tfx-batch-stats.mjs +32 -11
- package/scripts/tfx-gate-activate.mjs +11 -4
- package/scripts/tfx-route-post.mjs +87 -20
- package/scripts/tfx-route-worker.mjs +57 -51
- package/scripts/tfx-route.sh +41 -124
- package/scripts/tmp-cleanup.mjs +21 -7
- package/scripts/token-snapshot.mjs +204 -85
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
- package/skills/.omc/state/idle-notif-cooldown.json +3 -0
- package/skills/.omc/state/last-tool-error.json +7 -0
- package/skills/.omc/state/subagent-tracking.json +7 -0
- package/skills/_templates/base.md +1 -6
- package/skills/merge-worktree/SKILL.md.tmpl +144 -0
- package/skills/shared/telemetry-segment.md +6 -0
- package/skills/star-prompt/SKILL.md.tmpl +222 -0
- package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
- package/skills/tfx-analysis/skill.json +1 -6
- package/skills/tfx-auto/SKILL.md +1 -0
- package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
- package/skills/tfx-auto-codex/skill.json +1 -3
- package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
- package/skills/tfx-autopilot/skill.json +1 -5
- package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
- package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
- package/skills/tfx-autoroute/skill.json +1 -7
- package/skills/tfx-codex/SKILL.md +1 -0
- package/skills/tfx-codex/skill.json +1 -3
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
- package/skills/tfx-codex-swarm/evals/evals.json +1 -1
- package/skills/tfx-codex-swarm/skill.json +1 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
- package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
- package/skills/tfx-debate/SKILL.md.tmpl +192 -0
- package/skills/tfx-debate/skill.json +1 -7
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
- package/skills/tfx-deep-analysis/skill.json +1 -5
- package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
- package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
- package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
- package/skills/tfx-deep-qa/skill.json +1 -6
- package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
- package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
- package/skills/tfx-doctor/SKILL.md +21 -0
- package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
- package/skills/tfx-doctor/skill.json +1 -3
- package/skills/tfx-find/SKILL.md +1 -0
- package/skills/tfx-forge/SKILL.md.tmpl +187 -0
- package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
- package/skills/tfx-fullcycle/skill.json +1 -6
- package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
- package/skills/tfx-gemini/skill.json +1 -3
- package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
- package/skills/tfx-hooks/skill.json +1 -3
- package/skills/tfx-hub/SKILL.md.tmpl +212 -0
- package/skills/tfx-hub/skill.json +1 -3
- package/skills/tfx-index/SKILL.md +1 -0
- package/skills/tfx-index/skill.json +1 -6
- package/skills/tfx-interview/SKILL.md.tmpl +285 -0
- package/skills/tfx-multi/SKILL.md.tmpl +183 -0
- package/skills/tfx-multi/skill.json +1 -3
- package/skills/tfx-panel/SKILL.md.tmpl +189 -0
- package/skills/tfx-panel/skill.json +1 -7
- package/skills/tfx-persist/SKILL.md.tmpl +270 -0
- package/skills/tfx-persist/skill.json +1 -7
- package/skills/tfx-plan/SKILL.md +1 -0
- package/skills/tfx-plan/skill.json +1 -6
- package/skills/tfx-profile/SKILL.md.tmpl +239 -0
- package/skills/tfx-profile/skill.json +1 -3
- package/skills/tfx-prune/SKILL.md.tmpl +200 -0
- package/skills/tfx-prune/skill.json +1 -7
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
- package/skills/tfx-psmux-rules/skill.json +1 -4
- package/skills/tfx-qa/SKILL.md +1 -0
- package/skills/tfx-qa/skill.json +1 -6
- package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
- package/skills/tfx-ralph/skill.json +1 -4
- package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
- package/skills/tfx-remote-setup/skill.json +1 -3
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
- package/skills/tfx-remote-spawn/references/hosts.json +16 -0
- package/skills/tfx-remote-spawn/skill.json +1 -4
- package/skills/tfx-research/SKILL.md +1 -0
- package/skills/tfx-review/SKILL.md +1 -0
- package/skills/tfx-review/skill.json +1 -6
- package/skills/tfx-setup/SKILL.md.tmpl +504 -0
- package/skills/tfx-setup/skill.json +1 -3
- package/skills/tfx-swarm/SKILL.md +22 -0
- package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
- package/tui/codex-profile.mjs +88 -33
- package/tui/core.mjs +45 -15
- package/tui/doctor.mjs +75 -28
- package/tui/gemini-profile.mjs +74 -29
- package/tui/monitor-data.mjs +8 -4
- package/tui/monitor.mjs +71 -27
- package/tui/setup.mjs +133 -42
package/hub/router.mjs
CHANGED
|
@@ -1,45 +1,56 @@
|
|
|
1
1
|
// hub/router.mjs — 실시간 라우팅/수신함 상태 관리자
|
|
2
2
|
// SQLite는 감사 로그만 담당하고, 실제 배달 상태는 메모리에서 관리한다.
|
|
3
|
-
import { EventEmitter, once } from
|
|
4
|
-
import { uuidv7 } from
|
|
3
|
+
import { EventEmitter, once } from "node:events";
|
|
4
|
+
import { uuidv7 } from "./lib/uuidv7.mjs";
|
|
5
5
|
|
|
6
|
-
const ASSIGN_PENDING_STATUSES = new Set([
|
|
6
|
+
const ASSIGN_PENDING_STATUSES = new Set(["queued", "running"]);
|
|
7
7
|
|
|
8
8
|
function uniqueStrings(values = []) {
|
|
9
|
-
return Array.from(
|
|
9
|
+
return Array.from(
|
|
10
|
+
new Set(
|
|
11
|
+
(values || []).map((value) => String(value || "").trim()).filter(Boolean),
|
|
12
|
+
),
|
|
13
|
+
);
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
function clampAssignDuration(
|
|
16
|
+
function clampAssignDuration(
|
|
17
|
+
value,
|
|
18
|
+
fallback = 600000,
|
|
19
|
+
min = 1000,
|
|
20
|
+
max = 86400000,
|
|
21
|
+
) {
|
|
13
22
|
const num = Number(value);
|
|
14
23
|
if (!Number.isFinite(num)) return fallback;
|
|
15
24
|
return Math.max(min, Math.min(Math.trunc(num), max));
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
function normalizeAssignTerminalStatus(input, metadata = {}) {
|
|
19
|
-
const status = String(input ||
|
|
28
|
+
const status = String(input || "")
|
|
29
|
+
.trim()
|
|
30
|
+
.toLowerCase();
|
|
20
31
|
const resultTag = String(
|
|
21
|
-
metadata?.result
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (status ===
|
|
28
|
-
if (status ===
|
|
29
|
-
if (status ===
|
|
30
|
-
if (status ===
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (resultTag ===
|
|
35
|
-
|
|
36
|
-
return
|
|
32
|
+
metadata?.result ?? metadata?.status ?? metadata?.outcome ?? "",
|
|
33
|
+
)
|
|
34
|
+
.trim()
|
|
35
|
+
.toLowerCase();
|
|
36
|
+
|
|
37
|
+
if (status === "queued") return "queued";
|
|
38
|
+
if (status === "running" || status === "in_progress") return "running";
|
|
39
|
+
if (status === "timed_out" || status === "timeout") return "timed_out";
|
|
40
|
+
if (status === "failed" || status === "error") return "failed";
|
|
41
|
+
if (status === "succeeded" || status === "success") return "succeeded";
|
|
42
|
+
|
|
43
|
+
if (status === "completed") {
|
|
44
|
+
if (resultTag === "failed" || resultTag === "error") return "failed";
|
|
45
|
+
if (resultTag === "timed_out" || resultTag === "timeout")
|
|
46
|
+
return "timed_out";
|
|
47
|
+
return "succeeded";
|
|
37
48
|
}
|
|
38
49
|
|
|
39
|
-
if (resultTag ===
|
|
40
|
-
if (resultTag ===
|
|
41
|
-
if (resultTag ===
|
|
42
|
-
return
|
|
50
|
+
if (resultTag === "failed" || resultTag === "error") return "failed";
|
|
51
|
+
if (resultTag === "timed_out" || resultTag === "timeout") return "timed_out";
|
|
52
|
+
if (resultTag === "succeeded" || resultTag === "success") return "succeeded";
|
|
53
|
+
return "succeeded";
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
function normalizeAgentTopics(store, agentId, runtimeTopics) {
|
|
@@ -84,7 +95,9 @@ export function createRouter(store) {
|
|
|
84
95
|
|
|
85
96
|
function upsertRuntimeTopics(agentId, topics, { replace = true } = {}) {
|
|
86
97
|
const normalized = uniqueStrings(topics);
|
|
87
|
-
const current = replace
|
|
98
|
+
const current = replace
|
|
99
|
+
? new Set()
|
|
100
|
+
: new Set(runtimeTopics.get(agentId) || []);
|
|
88
101
|
for (const topic of normalized) current.add(topic);
|
|
89
102
|
runtimeTopics.set(agentId, current);
|
|
90
103
|
store.updateAgentTopics(agentId, Array.from(current));
|
|
@@ -124,12 +137,12 @@ export function createRouter(store) {
|
|
|
124
137
|
delivered_at_ms: null,
|
|
125
138
|
acked_at_ms: null,
|
|
126
139
|
});
|
|
127
|
-
deliveryEmitter.emit(
|
|
140
|
+
deliveryEmitter.emit("message", agentId, message);
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
function resolveRecipients(msg) {
|
|
131
144
|
const to = msg.to_agent ?? msg.to;
|
|
132
|
-
if (!to?.startsWith(
|
|
145
|
+
if (!to?.startsWith("topic:")) {
|
|
133
146
|
return [to];
|
|
134
147
|
}
|
|
135
148
|
|
|
@@ -144,7 +157,10 @@ export function createRouter(store) {
|
|
|
144
157
|
return Array.from(recipients);
|
|
145
158
|
}
|
|
146
159
|
|
|
147
|
-
function sortedPending(
|
|
160
|
+
function sortedPending(
|
|
161
|
+
agentId,
|
|
162
|
+
{ max_messages = 20, include_topics = null } = {},
|
|
163
|
+
) {
|
|
148
164
|
const queue = ensureAgentQueue(agentId);
|
|
149
165
|
const topicFilter = include_topics?.length ? new Set(include_topics) : null;
|
|
150
166
|
const now = Date.now();
|
|
@@ -173,8 +189,8 @@ export function createRouter(store) {
|
|
|
173
189
|
delivery.attempts += 1;
|
|
174
190
|
if (!delivery.delivered_at_ms) {
|
|
175
191
|
delivery.delivered_at_ms = Date.now();
|
|
176
|
-
record.message.status =
|
|
177
|
-
store.updateMessageStatus(messageId,
|
|
192
|
+
record.message.status = "delivered";
|
|
193
|
+
store.updateMessageStatus(messageId, "delivered");
|
|
178
194
|
recordLatency(delivery.delivered_at_ms - record.message.created_at_ms);
|
|
179
195
|
return true;
|
|
180
196
|
}
|
|
@@ -195,8 +211,8 @@ export function createRouter(store) {
|
|
|
195
211
|
count += 1;
|
|
196
212
|
|
|
197
213
|
if (record.ackedBy.size >= record.recipients.size) {
|
|
198
|
-
record.message.status =
|
|
199
|
-
store.updateMessageStatus(id,
|
|
214
|
+
record.message.status = "acked";
|
|
215
|
+
store.updateMessageStatus(id, "acked");
|
|
200
216
|
removeMessage(id);
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -204,7 +220,17 @@ export function createRouter(store) {
|
|
|
204
220
|
return count;
|
|
205
221
|
}
|
|
206
222
|
|
|
207
|
-
function dispatchMessage({
|
|
223
|
+
function dispatchMessage({
|
|
224
|
+
type,
|
|
225
|
+
from,
|
|
226
|
+
to,
|
|
227
|
+
topic,
|
|
228
|
+
priority = 5,
|
|
229
|
+
ttl_ms = 300000,
|
|
230
|
+
payload = {},
|
|
231
|
+
trace_id,
|
|
232
|
+
correlation_id,
|
|
233
|
+
}) {
|
|
208
234
|
const msg = store.auditLog({
|
|
209
235
|
type,
|
|
210
236
|
from,
|
|
@@ -222,10 +248,10 @@ export function createRouter(store) {
|
|
|
222
248
|
for (const agentId of recipients) {
|
|
223
249
|
queueMessage(agentId, msg);
|
|
224
250
|
}
|
|
225
|
-
msg.status =
|
|
226
|
-
store.updateMessageStatus(msg.id,
|
|
251
|
+
msg.status = "delivered";
|
|
252
|
+
store.updateMessageStatus(msg.id, "delivered");
|
|
227
253
|
}
|
|
228
|
-
if (msg.type ===
|
|
254
|
+
if (msg.type === "response") {
|
|
229
255
|
responseEmitter.emit(msg.correlation_id, msg.payload);
|
|
230
256
|
}
|
|
231
257
|
return { msg, recipients };
|
|
@@ -259,10 +285,10 @@ export function createRouter(store) {
|
|
|
259
285
|
function notifyAssignSupervisor(job, event, extra = {}) {
|
|
260
286
|
if (!job?.supervisor_agent) return null;
|
|
261
287
|
const { msg } = dispatchMessage({
|
|
262
|
-
type:
|
|
263
|
-
from: job.worker_agent ||
|
|
288
|
+
type: "event",
|
|
289
|
+
from: job.worker_agent || "assign-router",
|
|
264
290
|
to: job.supervisor_agent,
|
|
265
|
-
topic:
|
|
291
|
+
topic: "assign.result",
|
|
266
292
|
priority: Math.max(5, job.priority || 5),
|
|
267
293
|
ttl_ms: job.ttl_ms || job.timeout_ms || 600000,
|
|
268
294
|
payload: {
|
|
@@ -276,16 +302,16 @@ export function createRouter(store) {
|
|
|
276
302
|
return msg;
|
|
277
303
|
}
|
|
278
304
|
|
|
279
|
-
function dispatchAssignJob(job, reason =
|
|
305
|
+
function dispatchAssignJob(job, reason = "dispatch") {
|
|
280
306
|
const { msg, recipients } = dispatchMessage({
|
|
281
|
-
type:
|
|
307
|
+
type: "handoff",
|
|
282
308
|
from: job.supervisor_agent,
|
|
283
309
|
to: job.worker_agent,
|
|
284
|
-
topic: job.topic ||
|
|
310
|
+
topic: job.topic || "assign.job",
|
|
285
311
|
priority: job.priority || 5,
|
|
286
312
|
ttl_ms: job.ttl_ms || job.timeout_ms || 600000,
|
|
287
313
|
payload: {
|
|
288
|
-
kind:
|
|
314
|
+
kind: "assign.job",
|
|
289
315
|
reason,
|
|
290
316
|
assign_job_id: job.job_id,
|
|
291
317
|
attempt: job.attempt,
|
|
@@ -307,15 +333,23 @@ export function createRouter(store) {
|
|
|
307
333
|
return { job: updated || job, recipients, message_id: msg.id };
|
|
308
334
|
}
|
|
309
335
|
|
|
310
|
-
function scheduleAssignRetry(
|
|
336
|
+
function scheduleAssignRetry(
|
|
337
|
+
job,
|
|
338
|
+
reason,
|
|
339
|
+
error = null,
|
|
340
|
+
requested_by = "system",
|
|
341
|
+
) {
|
|
311
342
|
if (!job) {
|
|
312
|
-
return {
|
|
343
|
+
return {
|
|
344
|
+
ok: false,
|
|
345
|
+
error: { code: "ASSIGN_NOT_FOUND", message: "assign job not found" },
|
|
346
|
+
};
|
|
313
347
|
}
|
|
314
348
|
if (job.retry_count >= job.max_retries) {
|
|
315
349
|
return {
|
|
316
350
|
ok: false,
|
|
317
351
|
error: {
|
|
318
|
-
code:
|
|
352
|
+
code: "ASSIGN_RETRY_EXHAUSTED",
|
|
319
353
|
message: `retry exhausted for ${job.job_id}`,
|
|
320
354
|
},
|
|
321
355
|
};
|
|
@@ -326,8 +360,8 @@ export function createRouter(store) {
|
|
|
326
360
|
timeout_ms: job.timeout_ms,
|
|
327
361
|
ttl_ms: job.ttl_ms,
|
|
328
362
|
});
|
|
329
|
-
const dispatched = dispatchAssignJob(queued,
|
|
330
|
-
notifyAssignSupervisor(dispatched.job,
|
|
363
|
+
const dispatched = dispatchAssignJob(queued, "retry");
|
|
364
|
+
notifyAssignSupervisor(dispatched.job, "retry_scheduled", {
|
|
331
365
|
retry_reason: reason,
|
|
332
366
|
requested_by,
|
|
333
367
|
});
|
|
@@ -344,18 +378,26 @@ export function createRouter(store) {
|
|
|
344
378
|
}
|
|
345
379
|
|
|
346
380
|
function handleAssignTimeout(job) {
|
|
347
|
-
const timedOut = store.updateAssignStatus(job.job_id,
|
|
348
|
-
error: job.error ?? { message:
|
|
381
|
+
const timedOut = store.updateAssignStatus(job.job_id, "timed_out", {
|
|
382
|
+
error: job.error ?? { message: "assign job timed out" },
|
|
349
383
|
});
|
|
350
384
|
|
|
351
385
|
if (timedOut.retry_count < timedOut.max_retries) {
|
|
352
|
-
return scheduleAssignRetry(
|
|
386
|
+
return scheduleAssignRetry(
|
|
387
|
+
timedOut,
|
|
388
|
+
"timed_out",
|
|
389
|
+
timedOut.error,
|
|
390
|
+
"sweeper",
|
|
391
|
+
);
|
|
353
392
|
}
|
|
354
393
|
|
|
355
|
-
notifyAssignSupervisor(timedOut,
|
|
356
|
-
completion_reason:
|
|
394
|
+
notifyAssignSupervisor(timedOut, "completed", {
|
|
395
|
+
completion_reason: "timed_out",
|
|
357
396
|
});
|
|
358
|
-
return {
|
|
397
|
+
return {
|
|
398
|
+
ok: true,
|
|
399
|
+
data: buildAssignSnapshot(timedOut, { completion_reason: "timed_out" }),
|
|
400
|
+
};
|
|
359
401
|
}
|
|
360
402
|
|
|
361
403
|
const router = {
|
|
@@ -382,7 +424,7 @@ export function createRouter(store) {
|
|
|
382
424
|
},
|
|
383
425
|
|
|
384
426
|
updateAgentStatus(agentId, status) {
|
|
385
|
-
if (status ===
|
|
427
|
+
if (status === "offline") {
|
|
386
428
|
runtimeTopics.delete(agentId);
|
|
387
429
|
}
|
|
388
430
|
return store.updateAgentStatus(agentId, status);
|
|
@@ -397,7 +439,7 @@ export function createRouter(store) {
|
|
|
397
439
|
for (const agentId of recipients) {
|
|
398
440
|
queueMessage(agentId, msg);
|
|
399
441
|
}
|
|
400
|
-
store.updateMessageStatus(msg.id,
|
|
442
|
+
store.updateMessageStatus(msg.id, "delivered");
|
|
401
443
|
return recipients.length;
|
|
402
444
|
},
|
|
403
445
|
|
|
@@ -421,13 +463,19 @@ export function createRouter(store) {
|
|
|
421
463
|
return markDelivered(agentId, messageId);
|
|
422
464
|
},
|
|
423
465
|
|
|
424
|
-
drainAgent(
|
|
466
|
+
drainAgent(
|
|
467
|
+
agentId,
|
|
468
|
+
{ max_messages = 20, include_topics = null, auto_ack = false } = {},
|
|
469
|
+
) {
|
|
425
470
|
const messages = sortedPending(agentId, { max_messages, include_topics });
|
|
426
471
|
for (const message of messages) {
|
|
427
472
|
markDelivered(agentId, message.id);
|
|
428
473
|
}
|
|
429
474
|
if (auto_ack && messages.length) {
|
|
430
|
-
ackMessages(
|
|
475
|
+
ackMessages(
|
|
476
|
+
messages.map((message) => message.id),
|
|
477
|
+
agentId,
|
|
478
|
+
);
|
|
431
479
|
}
|
|
432
480
|
return messages;
|
|
433
481
|
},
|
|
@@ -437,15 +485,23 @@ export function createRouter(store) {
|
|
|
437
485
|
},
|
|
438
486
|
|
|
439
487
|
async handleAsk({
|
|
440
|
-
from,
|
|
441
|
-
|
|
442
|
-
|
|
488
|
+
from,
|
|
489
|
+
to,
|
|
490
|
+
topic,
|
|
491
|
+
question,
|
|
492
|
+
context_refs,
|
|
493
|
+
payload = {},
|
|
494
|
+
priority = 5,
|
|
495
|
+
ttl_ms = 300000,
|
|
496
|
+
await_response_ms = 0,
|
|
497
|
+
trace_id,
|
|
498
|
+
correlation_id,
|
|
443
499
|
}) {
|
|
444
500
|
const cid = correlation_id || uuidv7();
|
|
445
501
|
const tid = trace_id || uuidv7();
|
|
446
502
|
|
|
447
503
|
const { msg } = dispatchMessage({
|
|
448
|
-
type:
|
|
504
|
+
type: "request",
|
|
449
505
|
from,
|
|
450
506
|
to,
|
|
451
507
|
topic,
|
|
@@ -459,7 +515,12 @@ export function createRouter(store) {
|
|
|
459
515
|
if (await_response_ms <= 0) {
|
|
460
516
|
return {
|
|
461
517
|
ok: true,
|
|
462
|
-
data: {
|
|
518
|
+
data: {
|
|
519
|
+
request_message_id: msg.id,
|
|
520
|
+
correlation_id: cid,
|
|
521
|
+
trace_id: tid,
|
|
522
|
+
state: "queued",
|
|
523
|
+
},
|
|
463
524
|
};
|
|
464
525
|
}
|
|
465
526
|
|
|
@@ -469,28 +530,52 @@ export function createRouter(store) {
|
|
|
469
530
|
});
|
|
470
531
|
return {
|
|
471
532
|
ok: true,
|
|
472
|
-
data: {
|
|
533
|
+
data: {
|
|
534
|
+
request_message_id: msg.id,
|
|
535
|
+
correlation_id: cid,
|
|
536
|
+
trace_id: tid,
|
|
537
|
+
state: "answered",
|
|
538
|
+
response,
|
|
539
|
+
},
|
|
473
540
|
};
|
|
474
541
|
} catch {
|
|
475
542
|
const resp = store.getResponseByCorrelation(cid);
|
|
476
543
|
if (resp) {
|
|
477
544
|
return {
|
|
478
545
|
ok: true,
|
|
479
|
-
data: {
|
|
546
|
+
data: {
|
|
547
|
+
request_message_id: msg.id,
|
|
548
|
+
correlation_id: cid,
|
|
549
|
+
trace_id: tid,
|
|
550
|
+
state: "answered",
|
|
551
|
+
response: resp.payload,
|
|
552
|
+
},
|
|
480
553
|
};
|
|
481
554
|
}
|
|
482
555
|
return {
|
|
483
556
|
ok: true,
|
|
484
|
-
data: {
|
|
557
|
+
data: {
|
|
558
|
+
request_message_id: msg.id,
|
|
559
|
+
correlation_id: cid,
|
|
560
|
+
trace_id: tid,
|
|
561
|
+
state: "delivered",
|
|
562
|
+
},
|
|
485
563
|
};
|
|
486
564
|
}
|
|
487
565
|
},
|
|
488
566
|
|
|
489
567
|
handlePublish({
|
|
490
|
-
from,
|
|
491
|
-
|
|
568
|
+
from,
|
|
569
|
+
to,
|
|
570
|
+
topic,
|
|
571
|
+
priority = 5,
|
|
572
|
+
ttl_ms = 300000,
|
|
573
|
+
payload = {},
|
|
574
|
+
trace_id,
|
|
575
|
+
correlation_id,
|
|
576
|
+
message_type,
|
|
492
577
|
}) {
|
|
493
|
-
const type = message_type || (correlation_id ?
|
|
578
|
+
const type = message_type || (correlation_id ? "response" : "event");
|
|
494
579
|
const { msg, recipients } = dispatchMessage({
|
|
495
580
|
type,
|
|
496
581
|
from,
|
|
@@ -513,11 +598,19 @@ export function createRouter(store) {
|
|
|
513
598
|
},
|
|
514
599
|
|
|
515
600
|
handleHandoff({
|
|
516
|
-
from,
|
|
517
|
-
|
|
601
|
+
from,
|
|
602
|
+
to,
|
|
603
|
+
topic,
|
|
604
|
+
task,
|
|
605
|
+
acceptance_criteria,
|
|
606
|
+
context_refs,
|
|
607
|
+
priority = 5,
|
|
608
|
+
ttl_ms = 600000,
|
|
609
|
+
trace_id,
|
|
610
|
+
correlation_id,
|
|
518
611
|
}) {
|
|
519
612
|
const { msg } = dispatchMessage({
|
|
520
|
-
type:
|
|
613
|
+
type: "handoff",
|
|
521
614
|
from,
|
|
522
615
|
to,
|
|
523
616
|
topic,
|
|
@@ -529,15 +622,15 @@ export function createRouter(store) {
|
|
|
529
622
|
});
|
|
530
623
|
return {
|
|
531
624
|
ok: true,
|
|
532
|
-
data: { handoff_message_id: msg.id, state:
|
|
625
|
+
data: { handoff_message_id: msg.id, state: "queued", assigned_to: to },
|
|
533
626
|
};
|
|
534
627
|
},
|
|
535
628
|
|
|
536
629
|
assignAsync({
|
|
537
630
|
supervisor_agent,
|
|
538
631
|
worker_agent,
|
|
539
|
-
topic =
|
|
540
|
-
task =
|
|
632
|
+
topic = "assign.job",
|
|
633
|
+
task = "",
|
|
541
634
|
payload = {},
|
|
542
635
|
priority = 5,
|
|
543
636
|
ttl_ms = 600000,
|
|
@@ -559,7 +652,7 @@ export function createRouter(store) {
|
|
|
559
652
|
trace_id,
|
|
560
653
|
correlation_id,
|
|
561
654
|
});
|
|
562
|
-
const dispatched = dispatchAssignJob(job,
|
|
655
|
+
const dispatched = dispatchAssignJob(job, "create");
|
|
563
656
|
return {
|
|
564
657
|
ok: true,
|
|
565
658
|
data: {
|
|
@@ -583,20 +676,26 @@ export function createRouter(store) {
|
|
|
583
676
|
if (!job) {
|
|
584
677
|
return {
|
|
585
678
|
ok: false,
|
|
586
|
-
error: {
|
|
679
|
+
error: {
|
|
680
|
+
code: "ASSIGN_NOT_FOUND",
|
|
681
|
+
message: `assign job not found: ${job_id}`,
|
|
682
|
+
},
|
|
587
683
|
};
|
|
588
684
|
}
|
|
589
685
|
if (worker_agent && worker_agent !== job.worker_agent) {
|
|
590
686
|
return {
|
|
591
687
|
ok: false,
|
|
592
|
-
error: {
|
|
688
|
+
error: {
|
|
689
|
+
code: "ASSIGN_WORKER_MISMATCH",
|
|
690
|
+
message: `worker mismatch: ${worker_agent}`,
|
|
691
|
+
},
|
|
593
692
|
};
|
|
594
693
|
}
|
|
595
694
|
if (Number.isFinite(Number(attempt)) && Number(attempt) !== job.attempt) {
|
|
596
695
|
return {
|
|
597
696
|
ok: false,
|
|
598
697
|
error: {
|
|
599
|
-
code:
|
|
698
|
+
code: "ASSIGN_ATTEMPT_MISMATCH",
|
|
600
699
|
message: `stale assign result for attempt ${attempt} (current ${job.attempt})`,
|
|
601
700
|
},
|
|
602
701
|
};
|
|
@@ -610,17 +709,20 @@ export function createRouter(store) {
|
|
|
610
709
|
status || payload?.status,
|
|
611
710
|
mergedMetadata,
|
|
612
711
|
);
|
|
613
|
-
const nextResult =
|
|
712
|
+
const nextResult =
|
|
713
|
+
result ??
|
|
714
|
+
(Object.hasOwn(payload || {}, "result") ? payload.result : payload);
|
|
614
715
|
const nextError = error ?? payload?.error ?? null;
|
|
615
716
|
|
|
616
|
-
if (normalizedStatus ===
|
|
617
|
-
const running = store.updateAssignStatus(job.job_id,
|
|
717
|
+
if (normalizedStatus === "running") {
|
|
718
|
+
const running = store.updateAssignStatus(job.job_id, "running", {
|
|
618
719
|
started_at_ms: job.started_at_ms || Date.now(),
|
|
619
|
-
deadline_ms:
|
|
720
|
+
deadline_ms:
|
|
721
|
+
Date.now() + clampAssignDuration(job.timeout_ms, job.timeout_ms),
|
|
620
722
|
result: nextResult,
|
|
621
723
|
error: nextError,
|
|
622
724
|
});
|
|
623
|
-
notifyAssignSupervisor(running,
|
|
725
|
+
notifyAssignSupervisor(running, "progress");
|
|
624
726
|
return { ok: true, data: buildAssignSnapshot(running) };
|
|
625
727
|
}
|
|
626
728
|
|
|
@@ -629,12 +731,19 @@ export function createRouter(store) {
|
|
|
629
731
|
error: nextError,
|
|
630
732
|
});
|
|
631
733
|
|
|
632
|
-
if (
|
|
633
|
-
|
|
634
|
-
|
|
734
|
+
if (
|
|
735
|
+
(normalizedStatus === "failed" || normalizedStatus === "timed_out") &&
|
|
736
|
+
finalized.retry_count < finalized.max_retries
|
|
737
|
+
) {
|
|
738
|
+
return scheduleAssignRetry(
|
|
739
|
+
finalized,
|
|
740
|
+
normalizedStatus,
|
|
741
|
+
nextError,
|
|
742
|
+
worker_agent || finalized.worker_agent,
|
|
743
|
+
);
|
|
635
744
|
}
|
|
636
745
|
|
|
637
|
-
notifyAssignSupervisor(finalized,
|
|
746
|
+
notifyAssignSupervisor(finalized, "completed");
|
|
638
747
|
return { ok: true, data: buildAssignSnapshot(finalized) };
|
|
639
748
|
},
|
|
640
749
|
|
|
@@ -643,22 +752,33 @@ export function createRouter(store) {
|
|
|
643
752
|
const job = store.getAssign(job_id);
|
|
644
753
|
return job
|
|
645
754
|
? { ok: true, data: buildAssignSnapshot(job) }
|
|
646
|
-
: {
|
|
755
|
+
: {
|
|
756
|
+
ok: false,
|
|
757
|
+
error: {
|
|
758
|
+
code: "ASSIGN_NOT_FOUND",
|
|
759
|
+
message: `assign job not found: ${job_id}`,
|
|
760
|
+
},
|
|
761
|
+
};
|
|
647
762
|
}
|
|
648
763
|
return {
|
|
649
764
|
ok: true,
|
|
650
765
|
data: {
|
|
651
|
-
assigns: store
|
|
766
|
+
assigns: store
|
|
767
|
+
.listAssigns(filters)
|
|
768
|
+
.map((job) => buildAssignSnapshot(job)),
|
|
652
769
|
},
|
|
653
770
|
};
|
|
654
771
|
},
|
|
655
772
|
|
|
656
|
-
retryAssign(job_id, { reason =
|
|
773
|
+
retryAssign(job_id, { reason = "manual", requested_by = "manual" } = {}) {
|
|
657
774
|
const job = store.getAssign(job_id);
|
|
658
775
|
if (!job) {
|
|
659
776
|
return {
|
|
660
777
|
ok: false,
|
|
661
|
-
error: {
|
|
778
|
+
error: {
|
|
779
|
+
code: "ASSIGN_NOT_FOUND",
|
|
780
|
+
message: `assign job not found: ${job_id}`,
|
|
781
|
+
},
|
|
662
782
|
};
|
|
663
783
|
}
|
|
664
784
|
return scheduleAssignRetry(job, reason, job.error, requested_by);
|
|
@@ -669,7 +789,7 @@ export function createRouter(store) {
|
|
|
669
789
|
let expired = 0;
|
|
670
790
|
for (const [messageId, record] of Array.from(liveMessages.entries())) {
|
|
671
791
|
if (record.message.expires_at_ms > now) continue;
|
|
672
|
-
store.moveToDeadLetter(messageId,
|
|
792
|
+
store.moveToDeadLetter(messageId, "ttl_expired", null);
|
|
673
793
|
removeMessage(messageId);
|
|
674
794
|
expired += 1;
|
|
675
795
|
}
|
|
@@ -703,15 +823,23 @@ export function createRouter(store) {
|
|
|
703
823
|
} catch {}
|
|
704
824
|
}, 10000);
|
|
705
825
|
staleTimer = setInterval(() => {
|
|
706
|
-
try {
|
|
826
|
+
try {
|
|
827
|
+
store.sweepStaleAgents();
|
|
828
|
+
} catch {}
|
|
707
829
|
}, 120000);
|
|
708
830
|
sweepTimer.unref();
|
|
709
831
|
staleTimer.unref();
|
|
710
832
|
},
|
|
711
833
|
|
|
712
834
|
stopSweeper() {
|
|
713
|
-
if (sweepTimer) {
|
|
714
|
-
|
|
835
|
+
if (sweepTimer) {
|
|
836
|
+
clearInterval(sweepTimer);
|
|
837
|
+
sweepTimer = null;
|
|
838
|
+
}
|
|
839
|
+
if (staleTimer) {
|
|
840
|
+
clearInterval(staleTimer);
|
|
841
|
+
staleTimer = null;
|
|
842
|
+
}
|
|
715
843
|
},
|
|
716
844
|
|
|
717
845
|
getQueueDepths() {
|
|
@@ -730,22 +858,27 @@ export function createRouter(store) {
|
|
|
730
858
|
return { total_deliveries: 0, avg_delivery_ms: 0 };
|
|
731
859
|
}
|
|
732
860
|
const filled = Math.min(latencyIdx, MAX_LATENCY_SAMPLES);
|
|
733
|
-
const total = deliveryLatencies
|
|
861
|
+
const total = deliveryLatencies
|
|
862
|
+
.slice(0, filled)
|
|
863
|
+
.reduce((sum, ms) => sum + ms, 0);
|
|
734
864
|
return {
|
|
735
865
|
total_deliveries: latencyIdx,
|
|
736
866
|
avg_delivery_ms: Math.round(total / filled),
|
|
737
867
|
};
|
|
738
868
|
},
|
|
739
869
|
|
|
740
|
-
getStatus(
|
|
870
|
+
getStatus(
|
|
871
|
+
scope = "hub",
|
|
872
|
+
{ agent_id, trace_id, include_metrics = true } = {},
|
|
873
|
+
) {
|
|
741
874
|
const data = {};
|
|
742
875
|
|
|
743
|
-
if (scope ===
|
|
876
|
+
if (scope === "hub" || scope === "queue") {
|
|
744
877
|
data.hub = {
|
|
745
|
-
state:
|
|
746
|
-
uptime_ms: process.uptime() * 1000 | 0,
|
|
747
|
-
realtime_transport:
|
|
748
|
-
audit_store: store.type ||
|
|
878
|
+
state: "healthy",
|
|
879
|
+
uptime_ms: (process.uptime() * 1000) | 0,
|
|
880
|
+
realtime_transport: "named-pipe",
|
|
881
|
+
audit_store: store.type || "sqlite",
|
|
749
882
|
};
|
|
750
883
|
if (include_metrics) {
|
|
751
884
|
const depths = router.getQueueDepths();
|
|
@@ -766,7 +899,7 @@ export function createRouter(store) {
|
|
|
766
899
|
}
|
|
767
900
|
}
|
|
768
901
|
|
|
769
|
-
if (scope ===
|
|
902
|
+
if (scope === "agent" && agent_id) {
|
|
770
903
|
const agent = store.getAgent(agent_id);
|
|
771
904
|
if (agent) {
|
|
772
905
|
data.agent = {
|
|
@@ -779,7 +912,7 @@ export function createRouter(store) {
|
|
|
779
912
|
}
|
|
780
913
|
}
|
|
781
914
|
|
|
782
|
-
if (scope ===
|
|
915
|
+
if (scope === "trace" && trace_id) {
|
|
783
916
|
data.trace = store.getMessagesByTrace(trace_id);
|
|
784
917
|
}
|
|
785
918
|
|