moflo 4.8.72 → 4.8.73
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.73",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"@types/js-yaml": "^4.0.9",
|
|
113
113
|
"@types/node": "^20.19.37",
|
|
114
114
|
"eslint": "^8.0.0",
|
|
115
|
-
"moflo": "^4.8.
|
|
115
|
+
"moflo": "^4.8.72",
|
|
116
116
|
"tsx": "^4.21.0",
|
|
117
117
|
"typescript": "^5.9.3",
|
|
118
118
|
"vitest": "^4.0.0"
|
|
@@ -15,6 +15,7 @@ import { execSync } from 'node:child_process';
|
|
|
15
15
|
import { existsSync, readFileSync } from 'node:fs';
|
|
16
16
|
import { platform } from 'node:os';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
|
+
import { escapeShellArg } from './shell.js';
|
|
18
19
|
export const DEFAULT_SANDBOX_CONFIG = {
|
|
19
20
|
enabled: false,
|
|
20
21
|
tier: 'auto',
|
|
@@ -40,6 +41,7 @@ export function detectSandboxCapability() {
|
|
|
40
41
|
/** Reset the cached result (for testing). */
|
|
41
42
|
export function resetSandboxCache() {
|
|
42
43
|
_cached = undefined;
|
|
44
|
+
_imageExistsCache.clear();
|
|
43
45
|
}
|
|
44
46
|
function detectUncached() {
|
|
45
47
|
const os = platform();
|
|
@@ -165,12 +167,13 @@ export async function loadSandboxConfigFromProject(projectRoot) {
|
|
|
165
167
|
* @throws Error if tier is 'full' but no OS sandbox is available.
|
|
166
168
|
*/
|
|
167
169
|
export function resolveEffectiveSandbox(config, capability = detectSandboxCapability()) {
|
|
170
|
+
let resolved = config;
|
|
168
171
|
// Config disabled or tier is denylist-only => no OS sandbox
|
|
169
|
-
if (!
|
|
172
|
+
if (!resolved.enabled || resolved.tier === 'denylist-only') {
|
|
170
173
|
return {
|
|
171
174
|
useOsSandbox: false,
|
|
172
175
|
capability,
|
|
173
|
-
config,
|
|
176
|
+
config: resolved,
|
|
174
177
|
displayStatus: `OS sandbox: disabled (denylist active)`,
|
|
175
178
|
};
|
|
176
179
|
}
|
|
@@ -181,17 +184,16 @@ export function resolveEffectiveSandbox(config, capability = detectSandboxCapabi
|
|
|
181
184
|
if (!capability.available) {
|
|
182
185
|
throw new Error(formatWindowsDockerNotReadyMessage());
|
|
183
186
|
}
|
|
184
|
-
const image =
|
|
185
|
-
if (!
|
|
186
|
-
|
|
187
|
-
config = { ...config, dockerImage: image };
|
|
187
|
+
const image = resolved.dockerImage || RECOMMENDED_DOCKER_IMAGE;
|
|
188
|
+
if (!resolved.dockerImage) {
|
|
189
|
+
resolved = { ...resolved, dockerImage: image };
|
|
188
190
|
}
|
|
189
191
|
if (!dockerImageExists(image)) {
|
|
190
192
|
dockerPullImage(image);
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
// tier: full — require OS sandbox on non-Windows platforms
|
|
194
|
-
if (
|
|
196
|
+
if (resolved.tier === 'full' && !capability.available) {
|
|
195
197
|
throw new Error(`Sandbox tier "full" requires an OS sandbox but none was detected on ${capability.platform}. ` +
|
|
196
198
|
`Install bubblewrap (Linux) or set sandbox.tier to "auto".`);
|
|
197
199
|
}
|
|
@@ -199,24 +201,29 @@ export function resolveEffectiveSandbox(config, capability = detectSandboxCapabi
|
|
|
199
201
|
return {
|
|
200
202
|
useOsSandbox: false,
|
|
201
203
|
capability,
|
|
202
|
-
config,
|
|
204
|
+
config: resolved,
|
|
203
205
|
displayStatus: `OS sandbox: not available (${capability.platform})`,
|
|
204
206
|
};
|
|
205
207
|
}
|
|
206
208
|
return {
|
|
207
209
|
useOsSandbox: true,
|
|
208
210
|
capability,
|
|
209
|
-
config,
|
|
211
|
+
config: resolved,
|
|
210
212
|
displayStatus: `OS sandbox: ${capability.tool} (${capability.platform})`,
|
|
211
213
|
};
|
|
212
214
|
}
|
|
215
|
+
const _imageExistsCache = new Map();
|
|
213
216
|
/**
|
|
214
217
|
* Check whether a Docker image is available locally (already pulled).
|
|
215
|
-
*
|
|
218
|
+
* Result is cached per image name for the process lifetime.
|
|
216
219
|
*/
|
|
217
220
|
function dockerImageExists(image) {
|
|
221
|
+
const cached = _imageExistsCache.get(image);
|
|
222
|
+
if (cached !== undefined)
|
|
223
|
+
return cached;
|
|
218
224
|
try {
|
|
219
|
-
execSync(`docker image inspect ${
|
|
225
|
+
execSync(`docker image inspect ${escapeShellArg(image)}`, { stdio: 'ignore', timeout: 5000 });
|
|
226
|
+
_imageExistsCache.set(image, true);
|
|
220
227
|
return true;
|
|
221
228
|
}
|
|
222
229
|
catch {
|
|
@@ -231,7 +238,8 @@ function dockerPullImage(image) {
|
|
|
231
238
|
console.log(`[spell] One-time setup: pulling Docker image ${image} for sandboxing...\n` +
|
|
232
239
|
` This only happens once — Docker caches the image afterwards.`);
|
|
233
240
|
try {
|
|
234
|
-
execSync(`docker pull ${
|
|
241
|
+
execSync(`docker pull ${escapeShellArg(image)}`, { stdio: 'inherit', timeout: 300_000 });
|
|
242
|
+
_imageExistsCache.set(image, true);
|
|
235
243
|
console.log(`[spell] Docker image ${image} is ready.`);
|
|
236
244
|
}
|
|
237
245
|
catch {
|
|
@@ -239,10 +247,6 @@ function dockerPullImage(image) {
|
|
|
239
247
|
'Make sure Docker Desktop is running and you have internet access, then try again.');
|
|
240
248
|
}
|
|
241
249
|
}
|
|
242
|
-
/** Minimal shell quoting for image names — keeps the execSync call safe. */
|
|
243
|
-
function shellQuote(value) {
|
|
244
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
245
|
-
}
|
|
246
250
|
// ── Beginner-friendly setup messages (Windows) ──────────────────────────
|
|
247
251
|
function formatWindowsDockerNotReadyMessage() {
|
|
248
252
|
return [
|