moflo 4.10.7 → 4.10.8
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/guidance/shipped/moflo-cli-reference.md +1 -1
- package/.claude/guidance/shipped/moflo-memory-strategy.md +1 -1
- package/.claude/guidance/shipped/moflo-yaml-reference.md +4 -4
- package/.claude/skills/memory-optimization/SKILL.md +1 -1
- package/.claude/skills/memory-patterns/SKILL.md +3 -3
- package/.claude/skills/vector-search/SKILL.md +2 -2
- package/README.md +5 -5
- package/bin/lib/daemon-port.mjs +66 -0
- package/dist/src/cli/commands/daemon.js +31 -10
- package/dist/src/cli/commands/doctor-checks-config.js +139 -1
- package/dist/src/cli/commands/doctor-fixes.js +75 -2
- package/dist/src/cli/commands/doctor-registry.js +10 -1
- package/dist/src/cli/commands/memory.js +8 -8
- package/dist/src/cli/commands/neural.js +8 -6
- package/dist/src/cli/config/moflo-config.js +68 -3
- package/dist/src/cli/index.js +18 -19
- package/dist/src/cli/init/moflo-yaml-template.js +1 -1
- package/dist/src/cli/mcp-server.js +59 -10
- package/dist/src/cli/mcp-tools/memory-tools.js +46 -27
- package/dist/src/cli/memory/auto-memory-bridge.js +1 -1
- package/dist/src/cli/memory/controllers/attestation-log.js +1 -1
- package/dist/src/cli/memory/controllers/causal-graph.js +1 -1
- package/dist/src/cli/memory/daemon-write-client.js +178 -49
- package/dist/src/cli/memory/database-provider.js +58 -3
- package/dist/src/cli/memory/intelligence.js +54 -26
- package/dist/src/cli/memory/memory-initializer.js +21 -11
- package/dist/src/cli/services/daemon-dashboard.js +94 -25
- package/dist/src/cli/services/daemon-lock.js +390 -3
- package/dist/src/cli/services/daemon-port.js +217 -0
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -2
- package/dist/src/cli/config-adapter.js +0 -182
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon port resolution — single source of truth for the moflo daemon's
|
|
3
|
+
* HTTP port.
|
|
4
|
+
*
|
|
5
|
+
* Before #1145, `DEFAULT_DASHBOARD_PORT` in `daemon-dashboard.ts` and
|
|
6
|
+
* `DEFAULT_DAEMON_PORT` in `daemon-write-client.ts` were two separate `3117`
|
|
7
|
+
* literals. The server tried 3117 → 3126 on `EADDRINUSE`; the client always
|
|
8
|
+
* POSTed to 3117. When a second moflo project's daemon bound 3118+, that
|
|
9
|
+
* project's clients still hit 3117 → silent cross-project read/write
|
|
10
|
+
* routing. See `docs/internal/1145-daemon-port-collision-analysis.md`.
|
|
11
|
+
*
|
|
12
|
+
* This module collapses both literals into one resolver. Every entry point
|
|
13
|
+
* MUST go through `resolveProjectPort()` (or read the `port` field a
|
|
14
|
+
* already-bound daemon recorded in `.moflo/daemon.lock`).
|
|
15
|
+
*
|
|
16
|
+
* Resolution precedence — server and client agree:
|
|
17
|
+
* 1. `MOFLO_DAEMON_PORT` env override (consumer pin / smoke harness — wins)
|
|
18
|
+
* 2. Lock-file `port` field (client-only — server WRITES this after bind)
|
|
19
|
+
* 3. `resolveProjectPort(projectRoot)` — sha256(path) → 33000+(hash%1000)
|
|
20
|
+
* 4. `LEGACY_DEFAULT_PORT` (3117) — read-only fallback for ancient locks
|
|
21
|
+
* with no port field and no env override; warns once via stderr
|
|
22
|
+
*
|
|
23
|
+
* @module cli/services/daemon-port
|
|
24
|
+
*/
|
|
25
|
+
import { createHash } from 'node:crypto';
|
|
26
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import * as http from 'node:http';
|
|
29
|
+
/**
|
|
30
|
+
* Deterministic port range. 33000-33999 — clear of every common dev-server
|
|
31
|
+
* port (3000, 3001, 4000, 5000, 5173, 8000, 8080), every well-known service
|
|
32
|
+
* (≤ 1024), and the moflo legacy default (3117). Collision probability across
|
|
33
|
+
* N active projects is ~N/1000; the identity check (`isDaemonIdentityMatch`)
|
|
34
|
+
* is the safety net when collisions do hit.
|
|
35
|
+
*/
|
|
36
|
+
export const PORT_RANGE_BASE = 33000;
|
|
37
|
+
export const PORT_RANGE_SIZE = 1000;
|
|
38
|
+
/**
|
|
39
|
+
* Legacy default port — used by daemons that haven't been upgraded past
|
|
40
|
+
* 4.10.7 and locks that never recorded a port field. Kept as a read-only
|
|
41
|
+
* fallback so a fresh client probing an old daemon still finds it; clients
|
|
42
|
+
* that fall through to this path emit a one-time deprecation warn.
|
|
43
|
+
*
|
|
44
|
+
* NEW code must NEVER reference this constant outside `daemon-port.ts`. The
|
|
45
|
+
* regression guard at `tests/system/no-fixed-3117.test.ts` enforces.
|
|
46
|
+
*/
|
|
47
|
+
export const LEGACY_DEFAULT_PORT = 3117;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the canonical port for a given project root.
|
|
50
|
+
*
|
|
51
|
+
* Pure function — no I/O. Same project path → same port across daemon
|
|
52
|
+
* restarts, across processes, across machines (the hash is deterministic).
|
|
53
|
+
*
|
|
54
|
+
* @param projectRoot absolute path to the project root (use `findProjectRoot()`)
|
|
55
|
+
* @returns port in `[PORT_RANGE_BASE, PORT_RANGE_BASE + PORT_RANGE_SIZE)`
|
|
56
|
+
*/
|
|
57
|
+
export function resolveProjectPort(projectRoot) {
|
|
58
|
+
const envPort = readEnvPortOverride();
|
|
59
|
+
if (envPort != null)
|
|
60
|
+
return envPort;
|
|
61
|
+
const hash = createHash('sha256').update(projectRoot).digest();
|
|
62
|
+
return PORT_RANGE_BASE + (hash.readUInt16BE(0) % PORT_RANGE_SIZE);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read `MOFLO_DAEMON_PORT` from the environment. Returns the parsed port
|
|
66
|
+
* (1-65535) or `null` if unset/invalid.
|
|
67
|
+
*
|
|
68
|
+
* Exported so callers can short-circuit lock-file reads when the env is
|
|
69
|
+
* pinned — useful in the smoke harness and CI where the env is the
|
|
70
|
+
* authoritative pin.
|
|
71
|
+
*/
|
|
72
|
+
export function readEnvPortOverride() {
|
|
73
|
+
const raw = process.env.MOFLO_DAEMON_PORT;
|
|
74
|
+
if (!raw)
|
|
75
|
+
return null;
|
|
76
|
+
const n = parseInt(raw, 10);
|
|
77
|
+
if (!Number.isFinite(n) || n < 1 || n > 65535)
|
|
78
|
+
return null;
|
|
79
|
+
return n;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the daemon port a CLIENT should connect to for a given project.
|
|
83
|
+
*
|
|
84
|
+
* Reads `.moflo/daemon.lock` to discover the actual bound port — if the
|
|
85
|
+
* daemon collided with another project in its deterministic-range bucket
|
|
86
|
+
* and the dashboard retry loop bumped it forward, the lock reflects reality
|
|
87
|
+
* and the client follows. Falls back to `resolveProjectPort` when the lock
|
|
88
|
+
* is absent (daemon not yet started), the lock has no `port` field (old
|
|
89
|
+
* daemon predating #1145), or the port reads as invalid.
|
|
90
|
+
*
|
|
91
|
+
* Never throws — every I/O failure degrades to the deterministic fallback.
|
|
92
|
+
*/
|
|
93
|
+
export function resolveClientPort(projectRoot) {
|
|
94
|
+
const envPort = readEnvPortOverride();
|
|
95
|
+
if (envPort != null)
|
|
96
|
+
return envPort;
|
|
97
|
+
try {
|
|
98
|
+
const lockFile = join(projectRoot, '.moflo', 'daemon.lock');
|
|
99
|
+
if (existsSync(lockFile)) {
|
|
100
|
+
const raw = readFileSync(lockFile, 'utf-8');
|
|
101
|
+
const lock = JSON.parse(raw);
|
|
102
|
+
const lockPort = typeof lock?.port === 'number' ? lock.port : null;
|
|
103
|
+
if (lockPort && Number.isFinite(lockPort) && lockPort > 0 && lockPort < 65536) {
|
|
104
|
+
return lockPort;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Corrupt or unreadable lock — fall through to deterministic port.
|
|
110
|
+
}
|
|
111
|
+
return resolveProjectPort(projectRoot);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build the list of ports the SERVER should try, in order, when starting
|
|
115
|
+
* the daemon. First entry is the deterministic port; the rest are the
|
|
116
|
+
* collision-fallback range. Capped at `PORT_RANGE_SIZE` so the loop can
|
|
117
|
+
* never wrap past the bucket.
|
|
118
|
+
*
|
|
119
|
+
* If the env override is set, the list collapses to that single port —
|
|
120
|
+
* the consumer pinned it on purpose; respect their choice and hard-fail
|
|
121
|
+
* if it's already in use.
|
|
122
|
+
*/
|
|
123
|
+
export function serverPortCandidates(projectRoot, maxAttempts = 10) {
|
|
124
|
+
const envPort = readEnvPortOverride();
|
|
125
|
+
if (envPort != null)
|
|
126
|
+
return [envPort];
|
|
127
|
+
const base = resolveProjectPort(projectRoot);
|
|
128
|
+
const attempts = Math.min(Math.max(1, maxAttempts), PORT_RANGE_SIZE);
|
|
129
|
+
const ports = [];
|
|
130
|
+
for (let i = 0; i < attempts; i++) {
|
|
131
|
+
ports.push(PORT_RANGE_BASE + ((base - PORT_RANGE_BASE + i) % PORT_RANGE_SIZE));
|
|
132
|
+
}
|
|
133
|
+
return ports;
|
|
134
|
+
}
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Identity probe — shared by client + healer (#1145)
|
|
137
|
+
// ============================================================================
|
|
138
|
+
/**
|
|
139
|
+
* Normalize project root paths for identity comparison.
|
|
140
|
+
*
|
|
141
|
+
* - Resolve symlinks via `realpathSync`. macOS aliases `/var/folders`
|
|
142
|
+
* → `/private/var/folders`; one side of the daemon/client pair may
|
|
143
|
+
* resolve the symlink and the other may not, producing false-positive
|
|
144
|
+
* identity mismatches on otherwise-matching project roots (caught by
|
|
145
|
+
* the consumer-smoke harness on macOS + Ubuntu after the original
|
|
146
|
+
* #1145 fix). Ubuntu hits the same shape via `/tmp` symlinks under
|
|
147
|
+
* certain mount configurations.
|
|
148
|
+
* - Lowercase on Windows so `C:\Users\...` and `c:\users\...` compare
|
|
149
|
+
* equal. POSIX is case-sensitive — pass through.
|
|
150
|
+
*
|
|
151
|
+
* Never throws — a path that doesn't exist (or that we lack permission
|
|
152
|
+
* to stat) falls back to the input string. The fallback case is safe
|
|
153
|
+
* because the symlink-mismatch class only fires on paths that DO exist
|
|
154
|
+
* (both daemon and client just resolved them).
|
|
155
|
+
*/
|
|
156
|
+
export function normalizeProjectRoot(p) {
|
|
157
|
+
let resolved = p;
|
|
158
|
+
try {
|
|
159
|
+
resolved = realpathSync(p);
|
|
160
|
+
}
|
|
161
|
+
catch { /* path doesn't exist / EACCES — use input */ }
|
|
162
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Send `GET /api/health` to `127.0.0.1:<port>` and parse the daemon's
|
|
166
|
+
* identity payload. Never throws — every failure mode maps to a
|
|
167
|
+
* `DaemonIdentityProbe` variant.
|
|
168
|
+
*
|
|
169
|
+
* Shared by `daemon-write-client.ts` (per-request safety net) and
|
|
170
|
+
* `doctor-checks-config.ts` (`checkDaemonIdentity` subcheck).
|
|
171
|
+
*/
|
|
172
|
+
export function probeDaemonHealth(port, timeoutMs) {
|
|
173
|
+
return new Promise((resolve) => {
|
|
174
|
+
let done = false;
|
|
175
|
+
const finish = (r) => {
|
|
176
|
+
if (done)
|
|
177
|
+
return;
|
|
178
|
+
done = true;
|
|
179
|
+
resolve(r);
|
|
180
|
+
};
|
|
181
|
+
const req = http.get({ host: '127.0.0.1', port, path: '/api/health', timeout: timeoutMs }, (res) => {
|
|
182
|
+
const status = res.statusCode ?? 0;
|
|
183
|
+
if (status === 404) {
|
|
184
|
+
res.resume();
|
|
185
|
+
finish({ kind: 'legacy' });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (status !== 200) {
|
|
189
|
+
res.resume();
|
|
190
|
+
finish({ kind: 'unreachable' });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
let buf = '';
|
|
194
|
+
res.setEncoding('utf8');
|
|
195
|
+
res.on('data', (chunk) => { buf += chunk; });
|
|
196
|
+
res.on('end', () => {
|
|
197
|
+
try {
|
|
198
|
+
const data = JSON.parse(buf);
|
|
199
|
+
if (typeof data?.projectRoot === 'string' && data.projectRoot.length > 0) {
|
|
200
|
+
finish({ kind: 'identity', projectRoot: data.projectRoot });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// 200 but no identity field — pre-#1145 daemon that 200s on
|
|
204
|
+
// every URL. Same handling as a 404.
|
|
205
|
+
finish({ kind: 'legacy' });
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
finish({ kind: 'legacy' });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
res.on('error', () => finish({ kind: 'unreachable' }));
|
|
212
|
+
});
|
|
213
|
+
req.on('error', () => finish({ kind: 'unreachable' }));
|
|
214
|
+
req.on('timeout', () => { req.destroy(); finish({ kind: 'unreachable' }); });
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=daemon-port.js.map
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.8",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
|
|
5
5
|
"main": "dist/src/cli/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
96
96
|
"@typescript-eslint/parser": "^7.18.0",
|
|
97
97
|
"eslint": "^8.0.0",
|
|
98
|
-
"moflo": "^4.10.
|
|
98
|
+
"moflo": "^4.10.7",
|
|
99
99
|
"tsx": "^4.21.0",
|
|
100
100
|
"typescript": "^5.9.3",
|
|
101
101
|
"vitest": "^4.0.0"
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration Adapter
|
|
3
|
-
* Converts between SystemConfig and V3Config types
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Convert SystemConfig to V3Config (CLI-specific format)
|
|
7
|
-
*/
|
|
8
|
-
export function systemConfigToV3Config(systemConfig) {
|
|
9
|
-
return {
|
|
10
|
-
version: '3.0.0',
|
|
11
|
-
projectRoot: systemConfig.orchestrator?.session?.dataDir || process.cwd(),
|
|
12
|
-
// Agent configuration
|
|
13
|
-
agents: {
|
|
14
|
-
defaultType: 'coder',
|
|
15
|
-
autoSpawn: false, // Not in SystemConfig
|
|
16
|
-
maxConcurrent: systemConfig.orchestrator?.lifecycle?.maxConcurrentAgents ?? 15,
|
|
17
|
-
timeout: systemConfig.orchestrator?.lifecycle?.spawnTimeout ?? 300000,
|
|
18
|
-
providers: [],
|
|
19
|
-
},
|
|
20
|
-
// Swarm configuration
|
|
21
|
-
swarm: {
|
|
22
|
-
topology: normalizeTopology(systemConfig.swarm?.topology),
|
|
23
|
-
maxAgents: systemConfig.swarm?.maxAgents ?? 15,
|
|
24
|
-
autoScale: systemConfig.swarm?.autoScale?.enabled ?? false,
|
|
25
|
-
coordinationStrategy: systemConfig.swarm?.coordination?.consensusRequired ? 'consensus' : 'leader',
|
|
26
|
-
healthCheckInterval: systemConfig.swarm?.coordination?.timeoutMs ?? 10000,
|
|
27
|
-
},
|
|
28
|
-
// Memory configuration
|
|
29
|
-
memory: {
|
|
30
|
-
backend: normalizeMemoryBackend(systemConfig.memory?.type),
|
|
31
|
-
persistPath: systemConfig.memory?.path || './data/memory',
|
|
32
|
-
cacheSize: systemConfig.memory?.maxSize ?? 1000000,
|
|
33
|
-
enableHNSW: systemConfig.memory?.agentdb?.indexType === 'hnsw',
|
|
34
|
-
vectorDimension: systemConfig.memory?.agentdb?.dimensions ?? 1536,
|
|
35
|
-
},
|
|
36
|
-
// MCP configuration (only stdio transport is supported)
|
|
37
|
-
mcp: {
|
|
38
|
-
autoStart: false, // Not in SystemConfig
|
|
39
|
-
transportType: 'stdio',
|
|
40
|
-
tools: [], // Not in SystemConfig
|
|
41
|
-
},
|
|
42
|
-
// CLI preferences
|
|
43
|
-
cli: {
|
|
44
|
-
colorOutput: true,
|
|
45
|
-
interactive: true,
|
|
46
|
-
verbosity: 'normal',
|
|
47
|
-
outputFormat: 'text',
|
|
48
|
-
progressStyle: 'spinner',
|
|
49
|
-
},
|
|
50
|
-
// Hooks configuration
|
|
51
|
-
hooks: {
|
|
52
|
-
enabled: false,
|
|
53
|
-
autoExecute: false,
|
|
54
|
-
hooks: [],
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Convert V3Config to SystemConfig
|
|
60
|
-
*/
|
|
61
|
-
export function v3ConfigToSystemConfig(v3Config) {
|
|
62
|
-
return {
|
|
63
|
-
orchestrator: {
|
|
64
|
-
lifecycle: {
|
|
65
|
-
maxConcurrentAgents: v3Config.agents.maxConcurrent,
|
|
66
|
-
spawnTimeout: v3Config.agents.timeout,
|
|
67
|
-
terminateTimeout: 10000,
|
|
68
|
-
maxSpawnRetries: 3,
|
|
69
|
-
},
|
|
70
|
-
session: {
|
|
71
|
-
dataDir: v3Config.projectRoot,
|
|
72
|
-
persistSessions: true,
|
|
73
|
-
sessionRetentionMs: 3600000,
|
|
74
|
-
},
|
|
75
|
-
health: {
|
|
76
|
-
checkInterval: v3Config.swarm.healthCheckInterval,
|
|
77
|
-
historyLimit: 100,
|
|
78
|
-
degradedThreshold: 1,
|
|
79
|
-
unhealthyThreshold: 2,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
swarm: {
|
|
83
|
-
topology: denormalizeTopology(v3Config.swarm.topology),
|
|
84
|
-
maxAgents: v3Config.swarm.maxAgents,
|
|
85
|
-
autoScale: {
|
|
86
|
-
enabled: v3Config.swarm.autoScale,
|
|
87
|
-
minAgents: 1,
|
|
88
|
-
maxAgents: v3Config.swarm.maxAgents,
|
|
89
|
-
scaleUpThreshold: 0.8,
|
|
90
|
-
scaleDownThreshold: 0.3,
|
|
91
|
-
},
|
|
92
|
-
coordination: {
|
|
93
|
-
consensusRequired: v3Config.swarm.coordinationStrategy === 'consensus',
|
|
94
|
-
timeoutMs: v3Config.swarm.healthCheckInterval,
|
|
95
|
-
retryPolicy: {
|
|
96
|
-
maxRetries: 3,
|
|
97
|
-
backoffMs: 500,
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
communication: {
|
|
101
|
-
protocol: 'events',
|
|
102
|
-
batchSize: 10,
|
|
103
|
-
flushIntervalMs: 100,
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
memory: {
|
|
107
|
-
type: denormalizeMemoryBackend(v3Config.memory.backend),
|
|
108
|
-
path: v3Config.memory.persistPath,
|
|
109
|
-
maxSize: v3Config.memory.cacheSize,
|
|
110
|
-
agentdb: {
|
|
111
|
-
dimensions: v3Config.memory.vectorDimension,
|
|
112
|
-
indexType: v3Config.memory.enableHNSW ? 'hnsw' : 'flat',
|
|
113
|
-
efConstruction: 200,
|
|
114
|
-
m: 16,
|
|
115
|
-
quantization: 'none',
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
mcp: {
|
|
119
|
-
name: 'moflo',
|
|
120
|
-
version: '3.0.0',
|
|
121
|
-
transport: {
|
|
122
|
-
type: 'stdio',
|
|
123
|
-
},
|
|
124
|
-
capabilities: {
|
|
125
|
-
tools: true,
|
|
126
|
-
resources: true,
|
|
127
|
-
prompts: true,
|
|
128
|
-
logging: true,
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Normalize topology from SystemConfig to V3Config
|
|
135
|
-
*/
|
|
136
|
-
function normalizeTopology(topology) {
|
|
137
|
-
switch (topology) {
|
|
138
|
-
case 'hierarchical':
|
|
139
|
-
case 'mesh':
|
|
140
|
-
case 'ring':
|
|
141
|
-
case 'star':
|
|
142
|
-
case 'hybrid':
|
|
143
|
-
case 'hierarchical-mesh':
|
|
144
|
-
return topology;
|
|
145
|
-
case 'adaptive':
|
|
146
|
-
return 'hybrid';
|
|
147
|
-
default:
|
|
148
|
-
return 'hierarchical';
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Denormalize topology from V3Config to SystemConfig
|
|
153
|
-
*/
|
|
154
|
-
function denormalizeTopology(topology) {
|
|
155
|
-
if (topology === 'hybrid') {
|
|
156
|
-
return 'hierarchical-mesh';
|
|
157
|
-
}
|
|
158
|
-
return topology;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Normalize memory backend from SystemConfig to V3Config
|
|
162
|
-
*/
|
|
163
|
-
function normalizeMemoryBackend(backend) {
|
|
164
|
-
switch (backend) {
|
|
165
|
-
case 'memory':
|
|
166
|
-
case 'sqlite':
|
|
167
|
-
case 'agentdb':
|
|
168
|
-
case 'hybrid':
|
|
169
|
-
return backend;
|
|
170
|
-
case 'redis':
|
|
171
|
-
return 'memory'; // Redis maps to memory for CLI purposes
|
|
172
|
-
default:
|
|
173
|
-
return 'hybrid';
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Denormalize memory backend from V3Config to SystemConfig
|
|
178
|
-
*/
|
|
179
|
-
function denormalizeMemoryBackend(backend) {
|
|
180
|
-
return backend;
|
|
181
|
-
}
|
|
182
|
-
//# sourceMappingURL=config-adapter.js.map
|