@claude-flow/cli 3.54.1 → 3.56.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/.claude/helpers/helpers.manifest.json +2 -2
- package/.claude/settings.json +9 -9
- package/bin/cli.js +1 -1
- package/bin/mcp-server.js +1 -1
- package/catalog-manifest.json +2 -2
- package/dist/src/auth/client.js +40 -24
- package/dist/src/commands/agent.js +12 -0
- package/dist/src/commands/analyze.js +18 -14
- package/dist/src/commands/autopilot.js +2 -2
- package/dist/src/commands/daemon.js +15 -3
- package/dist/src/commands/doctor.js +65 -58
- package/dist/src/commands/hive-mind.js +7 -0
- package/dist/src/commands/mcp.js +35 -1
- package/dist/src/commands/memory-backup.d.ts +1 -1
- package/dist/src/commands/memory-backup.js +23 -9
- package/dist/src/commands/memory.d.ts +0 -4
- package/dist/src/commands/memory.js +10 -2
- package/dist/src/commands/plugins.js +13 -1
- package/dist/src/commands/policy.js +10 -2
- package/dist/src/commands/task.js +12 -0
- package/dist/src/init/settings-generator.js +3 -3
- package/dist/src/mcp-server.d.ts +33 -0
- package/dist/src/mcp-server.js +96 -4
- package/dist/src/mcp-tools/agent-execute-core.js +244 -188
- package/dist/src/mcp-tools/agent-tools.js +15 -16
- package/dist/src/mcp-tools/agentdb-tools.js +22 -3
- package/dist/src/mcp-tools/claims-tools.js +3 -11
- package/dist/src/mcp-tools/hive-mind-tools.d.ts +2 -4
- package/dist/src/mcp-tools/hive-mind-tools.js +214 -40
- package/dist/src/mcp-tools/hooks-tools.js +47 -2
- package/dist/src/mcp-tools/memory-tools.js +29 -10
- package/dist/src/mcp-tools/record-store.d.ts +3 -0
- package/dist/src/mcp-tools/record-store.js +21 -0
- package/dist/src/mcp-tools/session-tools.js +47 -13
- package/dist/src/mcp-tools/task-tools.js +5 -11
- package/dist/src/mcp-tools/workflow-tools.js +78 -29
- package/dist/src/memory/append-conditions.d.ts +28 -0
- package/dist/src/memory/append-conditions.js +56 -0
- package/dist/src/memory/graph-edge-writer.d.ts +9 -0
- package/dist/src/memory/graph-edge-writer.js +90 -0
- package/dist/src/memory/memory-bridge.d.ts +4 -0
- package/dist/src/memory/memory-bridge.js +50 -9
- package/dist/src/memory/memory-initializer.d.ts +4 -0
- package/dist/src/memory/memory-initializer.js +95 -61
- package/dist/src/memory/memory-root.d.ts +2 -0
- package/dist/src/memory/memory-root.js +28 -0
- package/dist/src/memory/sona-optimizer.d.ts +2 -0
- package/dist/src/memory/sona-optimizer.js +4 -0
- package/dist/src/missions/schemas.d.ts +125 -125
- package/dist/src/mods/command-registry/schema.d.ts +199 -199
- package/dist/src/parser.d.ts +3 -0
- package/dist/src/parser.js +71 -13
- package/dist/src/plugins/store/discovery.d.ts +6 -0
- package/dist/src/plugins/store/discovery.js +7 -3
- package/dist/src/production/retry.js +1 -1
- package/dist/src/ruvector/neural-router.js +7 -2
- package/dist/src/services/bounded-worker-pool.js +3 -0
- package/dist/src/services/claim-service.js +39 -18
- package/dist/src/services/claims-store.d.ts +3 -0
- package/dist/src/services/claims-store.js +40 -0
- package/dist/src/services/config-file-manager.d.ts +3 -0
- package/dist/src/services/config-file-manager.js +24 -7
- package/dist/src/services/distill-tuning.js +17 -10
- package/dist/src/services/memory-backup.d.ts +7 -0
- package/dist/src/services/memory-backup.js +29 -2
- package/dist/src/services/memory-distillation.js +2 -2
- package/dist/src/services/policy-ledger-anchor.d.ts +42 -0
- package/dist/src/services/policy-ledger-anchor.js +163 -0
- package/dist/src/services/policy-runtime.d.ts +11 -5
- package/dist/src/services/policy-runtime.js +70 -15
- package/dist/src/services/worker-daemon.d.ts +5 -2
- package/dist/src/services/worker-daemon.js +26 -6
- package/dist/src/services/worker-queue.js +11 -2
- package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
- package/node_modules/@claude-flow/mcp/dist/connection-pool.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/connection-pool.js +5 -2
- package/node_modules/@claude-flow/mcp/dist/connection-pool.js.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.d.ts +7 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/transport/http.js +60 -47
- package/node_modules/@claude-flow/mcp/dist/transport/http.js.map +1 -1
- package/node_modules/@claude-flow/mcp/package.json +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts +3 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js +4 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.d.ts.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js.map +1 -1
- package/node_modules/@claude-flow/plugin-agent-federation/package.json +1 -1
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.d.ts +2 -1
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.js +48 -16
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.js.map +1 -1
- package/node_modules/@claude-flow/security/dist/path-validator.d.ts +2 -2
- package/node_modules/@claude-flow/security/dist/path-validator.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/dist/path-validator.js +15 -4
- package/node_modules/@claude-flow/security/dist/path-validator.js.map +1 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts +11 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/dist/policy/engine.js +19 -3
- package/node_modules/@claude-flow/security/dist/policy/engine.js.map +1 -1
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts +4 -2
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts.map +1 -1
- package/node_modules/@claude-flow/security/package.json +1 -1
- package/package.json +7 -7
- package/plugins/ruflo-metaharness/.claude-plugin/plugin.json +1 -1
- package/plugins/ruflo-metaharness/CHANGELOG.md +48 -0
- package/plugins/ruflo-metaharness/scripts/_invoke.mjs +80 -7
- package/plugins/ruflo-metaharness/scripts/smoke.sh +4 -4
- package/plugins/ruflo-metaharness/scripts/test-cli-resolution-3558.mjs +141 -0
- package/plugins/ruflo-metaharness/scripts/test-no-tool-time-npx.mjs +5 -0
- package/.claude/agents/tmp.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.56.0",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "c8d218526a3c34034c2a69de23f507f0eb0f70d59c16426a8edc849e6ac22529",
|
|
6
6
|
"hook-handler.cjs": "34d2aacfb59a73ff94b1467bb57ab9d9c4af89c0e470aadf3bd0d74a503a658d",
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
"router.cjs": "16648b3c0d73b6681ac2d8d13def6a68286c57f5a11004de5b19a0fa088c833d"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"signature": "
|
|
12
|
+
"signature": "9T3S9rchP2NnIjrYOL9tV7QvDP3WlsrsR7WlBXpUpoGPCrhe2Mo9bQEU7JOCscuQ+UQsrP211p7vmc93+AlWDg==",
|
|
13
13
|
"algorithm": "ed25519"
|
|
14
14
|
}
|
package/.claude/settings.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"hooks": [
|
|
12
12
|
{
|
|
13
13
|
"type": "command",
|
|
14
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" pre-bash",
|
|
14
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" pre-bash",
|
|
15
15
|
"timeout": 5000
|
|
16
16
|
}
|
|
17
17
|
]
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"hooks": [
|
|
24
24
|
{
|
|
25
25
|
"type": "command",
|
|
26
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" post-edit",
|
|
26
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" post-edit",
|
|
27
27
|
"timeout": 10000
|
|
28
28
|
}
|
|
29
29
|
]
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"hooks": [
|
|
35
35
|
{
|
|
36
36
|
"type": "command",
|
|
37
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" route",
|
|
37
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" route",
|
|
38
38
|
"timeout": 10000
|
|
39
39
|
}
|
|
40
40
|
]
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"hooks": [
|
|
47
47
|
{
|
|
48
48
|
"type": "command",
|
|
49
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" session-restore",
|
|
49
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-restore",
|
|
50
50
|
"timeout": 15000,
|
|
51
51
|
"continueOnError": true
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"type": "command",
|
|
55
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs" import",
|
|
55
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs\" import",
|
|
56
56
|
"timeout": 8000,
|
|
57
57
|
"continueOnError": true
|
|
58
58
|
}
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"hooks": [
|
|
65
65
|
{
|
|
66
66
|
"type": "command",
|
|
67
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" session-end",
|
|
67
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" session-end",
|
|
68
68
|
"timeout": 10000,
|
|
69
69
|
"continueOnError": true
|
|
70
70
|
}
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"hooks": [
|
|
77
77
|
{
|
|
78
78
|
"type": "command",
|
|
79
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs" status",
|
|
79
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/hook-handler.cjs\" status",
|
|
80
80
|
"timeout": 3000,
|
|
81
81
|
"continueOnError": true
|
|
82
82
|
}
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"hooks": [
|
|
89
89
|
{
|
|
90
90
|
"type": "command",
|
|
91
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs" sync",
|
|
91
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/auto-memory-hook.mjs\" sync",
|
|
92
92
|
"timeout": 10000,
|
|
93
93
|
"continueOnError": true
|
|
94
94
|
}
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
"statusLine": {
|
|
100
100
|
"type": "command",
|
|
101
|
-
"command": "node "$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs"",
|
|
101
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/helpers/statusline.cjs\"",
|
|
102
102
|
"refreshMs": 5000,
|
|
103
103
|
"enabled": true
|
|
104
104
|
},
|
package/bin/cli.js
CHANGED
|
@@ -301,7 +301,7 @@ if (isMCPMode) {
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
try {
|
|
304
|
-
const result = await callMCPTool(toolName, toolParams, { sessionId });
|
|
304
|
+
const result = await callMCPTool(toolName, toolParams, { sessionId, transport: 'stdio' });
|
|
305
305
|
// Failed task outcomes are data; an explicit handler error is a tool failure.
|
|
306
306
|
const isError = result !== null && typeof result === 'object'
|
|
307
307
|
&& typeof result.error === 'string' && result.error.trim().length > 0;
|
package/bin/mcp-server.js
CHANGED
|
@@ -190,7 +190,7 @@ async function handleMessage(message) {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
try {
|
|
193
|
-
const result = await callMCPTool(toolName, toolParams, { sessionId });
|
|
193
|
+
const result = await callMCPTool(toolName, toolParams, { sessionId, transport: 'stdio' });
|
|
194
194
|
return {
|
|
195
195
|
jsonrpc: '2.0',
|
|
196
196
|
id: message.id,
|
package/catalog-manifest.json
CHANGED
package/dist/src/auth/client.js
CHANGED
|
@@ -19,6 +19,8 @@ import { hasConsent } from '../funnel/index.js';
|
|
|
19
19
|
import { domainForScope } from './scopes.js';
|
|
20
20
|
/** Refresh before there is less than one minute left on the access token. */
|
|
21
21
|
export const ACCESS_TOKEN_REFRESH_WINDOW_MS = 60_000;
|
|
22
|
+
// A rotating refresh credential may be spent only once per process attempt.
|
|
23
|
+
const pendingRefreshes = new Map();
|
|
22
24
|
/**
|
|
23
25
|
* Best-effort headlessness signal — a false negative just means the browser
|
|
24
26
|
* flow is attempted and a real browser opens fine anyway; a false positive
|
|
@@ -213,30 +215,44 @@ export async function getValidAccessToken(profileName = 'default') {
|
|
|
213
215
|
const cached = getSessionToken(profileName, ACCESS_TOKEN_REFRESH_WINDOW_MS);
|
|
214
216
|
if (cached)
|
|
215
217
|
return cached;
|
|
216
|
-
|
|
218
|
+
const keychainRef = profile.keychainRef;
|
|
219
|
+
if (!keychainRef)
|
|
217
220
|
throw new SessionOnlyExpiredError(profileName);
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
221
|
+
const refreshKey = JSON.stringify([profileName, keychainRef]);
|
|
222
|
+
const pending = pendingRefreshes.get(refreshKey);
|
|
223
|
+
if (pending)
|
|
224
|
+
return pending;
|
|
225
|
+
const refresh = (async () => {
|
|
226
|
+
const sec = await loadSecurityOAuth();
|
|
227
|
+
const keychain = await sec.createKeychainAdapter();
|
|
228
|
+
const refreshTokenValue = await keychain.getSecret(KEYCHAIN_SERVICE, keychainRef);
|
|
229
|
+
if (!refreshTokenValue)
|
|
230
|
+
throw new SessionOnlyExpiredError(profileName);
|
|
231
|
+
const refreshed = await refreshAccessToken(refreshTokenValue);
|
|
232
|
+
if (!refreshed.access_token)
|
|
233
|
+
throw new Error('Cognitum refresh response did not contain an access token');
|
|
234
|
+
// Cognitum rotates refresh tokens with reuse detection. Commit the rotated
|
|
235
|
+
// credential first; if this write fails, do not publish/cache the access
|
|
236
|
+
// token and do not retry the already-spent old refresh token here.
|
|
237
|
+
if (refreshed.refresh_token) {
|
|
238
|
+
await keychain.setSecret(KEYCHAIN_SERVICE, keychainRef, refreshed.refresh_token);
|
|
239
|
+
}
|
|
240
|
+
const expiresAtMs = Date.now() + Math.max(0, refreshed.expires_in ?? 0) * 1000;
|
|
241
|
+
setSessionToken(profileName, refreshed.access_token, expiresAtMs);
|
|
242
|
+
setProfile(profileName, {
|
|
243
|
+
...profile,
|
|
244
|
+
accountId: refreshed.account_email ?? profile.accountId,
|
|
245
|
+
accessTokenExpiresAt: new Date(expiresAtMs).toISOString(),
|
|
246
|
+
linkedAt: new Date().toISOString(),
|
|
247
|
+
});
|
|
248
|
+
return refreshed.access_token;
|
|
249
|
+
})();
|
|
250
|
+
pendingRefreshes.set(refreshKey, refresh);
|
|
251
|
+
try {
|
|
252
|
+
return await refresh;
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
pendingRefreshes.delete(refreshKey);
|
|
256
|
+
}
|
|
241
257
|
}
|
|
242
258
|
//# sourceMappingURL=client.js.map
|
|
@@ -294,6 +294,18 @@ const statusCommand = {
|
|
|
294
294
|
includeMetrics: true,
|
|
295
295
|
includeHistory: false,
|
|
296
296
|
});
|
|
297
|
+
// The MCP tool answers an unknown id with status "not_found" and no other fields.
|
|
298
|
+
// Rendering that as a record printed "Agent: undefined", "Invalid Date" and
|
|
299
|
+
// "undefined%" and exited 0, so scripts and agents took it as success.
|
|
300
|
+
if ((status.status) === 'not_found') {
|
|
301
|
+
if (ctx.flags.format === 'json') {
|
|
302
|
+
output.printJson(status);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
output.printError(`Agent not found: ${agentId}`);
|
|
306
|
+
}
|
|
307
|
+
return { success: false, exitCode: 1 };
|
|
308
|
+
}
|
|
297
309
|
if (ctx.flags.format === 'json') {
|
|
298
310
|
output.printJson(status);
|
|
299
311
|
return { success: true, data: status };
|
|
@@ -254,14 +254,16 @@ const codeCommand = {
|
|
|
254
254
|
const targetPath = resolve(ctx.flags.path || '.');
|
|
255
255
|
const analysisType = ctx.flags.type || 'quality';
|
|
256
256
|
const formatJson = ctx.flags.format === 'json';
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
if (!formatJson) {
|
|
258
|
+
output.writeln();
|
|
259
|
+
output.writeln(output.bold('Code Analysis'));
|
|
260
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
261
|
+
}
|
|
260
262
|
const spinner = output.createSpinner({ text: `Analyzing ${targetPath}...`, spinner: 'dots' });
|
|
261
263
|
spinner.start();
|
|
262
264
|
try {
|
|
263
265
|
const files = await scanSourceFiles(targetPath);
|
|
264
|
-
if (files.length === 0) {
|
|
266
|
+
if (files.length === 0 && !formatJson) {
|
|
265
267
|
spinner.stop();
|
|
266
268
|
output.printWarning('No source files found');
|
|
267
269
|
return { success: true };
|
|
@@ -310,16 +312,16 @@ const codeCommand = {
|
|
|
310
312
|
const totalTodos = fileStats.reduce((s, f) => s + f.todos, 0);
|
|
311
313
|
const totalFunctions = fileStats.reduce((s, f) => s + f.functions, 0);
|
|
312
314
|
const totalImports = fileStats.reduce((s, f) => s + f.imports, 0);
|
|
313
|
-
const avgFileSize = Math.round(totalLoc / files.length);
|
|
314
|
-
const longestFile = fileStats.reduce((a, b) => a.loc > b.loc ? a : b);
|
|
315
|
-
const avgFnPerFile = (totalFunctions / files.length).toFixed(1);
|
|
316
|
-
const deepestNesting = fileStats.reduce((a, b) => a.maxNesting > b.maxNesting ? a : b);
|
|
317
|
-
const allSecurityIssues = fileStats.filter(f => f.securityIssues.length > 0);
|
|
315
|
+
const avgFileSize = files.length > 0 ? Math.round(totalLoc / files.length) : 0;
|
|
318
316
|
if (formatJson) {
|
|
319
317
|
const jsonData = { type: analysisType, path: targetPath, files: files.length, totalLoc, totalTodos, totalFunctions, totalImports, avgFileSize, fileStats: fileStats.map(f => ({ relativePath: path.relative(targetPath, f.file), loc: f.loc, todos: f.todos, functions: f.functions, imports: f.imports, maxNesting: f.maxNesting, securityIssues: f.securityIssues })) };
|
|
320
318
|
output.printJson(jsonData);
|
|
321
319
|
return { success: true, data: jsonData };
|
|
322
320
|
}
|
|
321
|
+
const longestFile = fileStats.reduce((a, b) => a.loc > b.loc ? a : b);
|
|
322
|
+
const avgFnPerFile = (totalFunctions / files.length).toFixed(1);
|
|
323
|
+
const deepestNesting = fileStats.reduce((a, b) => a.maxNesting > b.maxNesting ? a : b);
|
|
324
|
+
const allSecurityIssues = fileStats.filter(f => f.securityIssues.length > 0);
|
|
323
325
|
if (analysisType === 'quality') {
|
|
324
326
|
output.printBox([`Files: ${files.length}`, `Lines of Code: ${totalLoc.toLocaleString()}`, `Avg File Size: ${avgFileSize} LOC`, `TODO/FIXME: ${totalTodos}`, `Functions: ${totalFunctions}`, `Imports: ${totalImports}`].join('\n'), 'Quality Summary');
|
|
325
327
|
output.writeln();
|
|
@@ -549,7 +551,7 @@ const astCommand = {
|
|
|
549
551
|
}
|
|
550
552
|
}
|
|
551
553
|
spinner.stop();
|
|
552
|
-
if (results.length === 0) {
|
|
554
|
+
if (results.length === 0 && formatType !== 'json') {
|
|
553
555
|
output.printWarning('No files analyzed');
|
|
554
556
|
return { success: true };
|
|
555
557
|
}
|
|
@@ -559,7 +561,7 @@ const astCommand = {
|
|
|
559
561
|
functions: results.reduce((sum, r) => sum + r.functions.length, 0),
|
|
560
562
|
classes: results.reduce((sum, r) => sum + r.classes.length, 0),
|
|
561
563
|
imports: results.reduce((sum, r) => sum + r.imports.length, 0),
|
|
562
|
-
avgComplexity: results.reduce((sum, r) => sum + r.complexity.cyclomatic, 0) / results.length,
|
|
564
|
+
avgComplexity: results.length > 0 ? results.reduce((sum, r) => sum + r.complexity.cyclomatic, 0) / results.length : 0,
|
|
563
565
|
totalLoc: results.reduce((sum, r) => sum + r.complexity.loc, 0),
|
|
564
566
|
};
|
|
565
567
|
// JSON output
|
|
@@ -1230,9 +1232,11 @@ const depsCommand = {
|
|
|
1230
1232
|
const showOutdated = ctx.flags.outdated;
|
|
1231
1233
|
const checkSecurity = ctx.flags.security;
|
|
1232
1234
|
const formatJson = ctx.flags.format === 'json';
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1235
|
+
if (!formatJson || showOutdated || checkSecurity) {
|
|
1236
|
+
output.writeln();
|
|
1237
|
+
output.writeln(output.bold('Dependency Analysis'));
|
|
1238
|
+
output.writeln(output.dim('-'.repeat(50)));
|
|
1239
|
+
}
|
|
1236
1240
|
try {
|
|
1237
1241
|
const pkgPath = resolve('package.json');
|
|
1238
1242
|
let pkgContent;
|
|
@@ -181,8 +181,8 @@ const configCommand = {
|
|
|
181
181
|
name: 'config',
|
|
182
182
|
description: 'Configure max iterations, timeout, and task sources',
|
|
183
183
|
options: [
|
|
184
|
-
{ name: 'max-iterations', type: '
|
|
185
|
-
{ name: 'timeout', type: '
|
|
184
|
+
{ name: 'max-iterations', type: 'number', description: 'Max re-engagement iterations (1-1000)' },
|
|
185
|
+
{ name: 'timeout', type: 'number', description: 'Timeout in minutes (1-1440)' },
|
|
186
186
|
{ name: 'task-sources', type: 'string', description: `Comma-separated task sources: ${[...VALID_TASK_SOURCES].join(', ')}` },
|
|
187
187
|
],
|
|
188
188
|
action: async (ctx) => {
|
|
@@ -3,19 +3,22 @@
|
|
|
3
3
|
* Manages background worker daemon (Node.js-based, similar to shell helpers)
|
|
4
4
|
*/
|
|
5
5
|
import { output } from '../output.js';
|
|
6
|
-
import { getDaemon, startDaemon, stopDaemon } from '../services/worker-daemon.js';
|
|
6
|
+
import { getDaemon, startDaemon, stopDaemon, parseEnabledWorkers } from '../services/worker-daemon.js';
|
|
7
7
|
import { resolveDaemonProjectRoot } from '../services/daemon-autostart.js';
|
|
8
8
|
import { fork } from 'child_process';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { dirname, join, resolve } from 'path';
|
|
11
11
|
import { homedir } from 'os';
|
|
12
12
|
import * as fs from 'fs';
|
|
13
|
+
// Syntax guard for worker-name flags forwarded to a background child.
|
|
14
|
+
// The start action validates the names against the daemon's supported workers.
|
|
15
|
+
const WORKERS_RE = /^[a-z][a-z0-9_-]*(,[a-z][a-z0-9_-]*)*$/;
|
|
13
16
|
// Start daemon subcommand
|
|
14
17
|
const startCommand = {
|
|
15
18
|
name: 'start',
|
|
16
19
|
description: 'Start the worker daemon with all enabled background workers',
|
|
17
20
|
options: [
|
|
18
|
-
{ name: 'workers', short: 'w', type: 'string', description: 'Comma-separated list of workers to enable (default: map,audit,optimize,consolidate,testgaps)' },
|
|
21
|
+
{ name: 'workers', short: 'w', type: 'string', description: 'Comma-separated list of workers to enable (default: saved selection or map,audit,optimize,consolidate,testgaps,backup,harness)' },
|
|
19
22
|
// ADR-174 M3: consolidate now runs a real memory-distillation pass
|
|
20
23
|
// (memory_entries -> episodes/reasoning_patterns/causal_edges) instead of
|
|
21
24
|
// a no-op stub. This opt-out skips just that pass for the life of this
|
|
@@ -119,6 +122,16 @@ const startCommand = {
|
|
|
119
122
|
output.printWarning(`Ignoring invalid --ttl value: ${sanitize(rawTtl)}`);
|
|
120
123
|
}
|
|
121
124
|
}
|
|
125
|
+
if (ctx.flags.workers !== undefined) {
|
|
126
|
+
try {
|
|
127
|
+
config.enabledWorkers = parseEnabledWorkers(ctx.flags.workers);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (!quiet)
|
|
131
|
+
output.printError(error.message);
|
|
132
|
+
return { success: false, exitCode: 1 };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
122
135
|
// Check if background daemon already running (skip if we ARE the daemon process)
|
|
123
136
|
//
|
|
124
137
|
// #2407 — without an atomic lockfile, N concurrent `daemon start` calls
|
|
@@ -518,7 +531,6 @@ async function startBackgroundDaemon(projectRoot, quiet, forwarded = {}) {
|
|
|
518
531
|
// through — argv goes straight to a forked process so reject anything
|
|
519
532
|
// that doesn't look like a comma-separated worker-name list or one of
|
|
520
533
|
// the allowed sandbox modes.
|
|
521
|
-
const WORKERS_RE = /^[a-z][a-z0-9_-]*(,[a-z][a-z0-9_-]*)*$/;
|
|
522
534
|
if (typeof workers === 'string' && workers.length > 0 && WORKERS_RE.test(workers)) {
|
|
523
535
|
forkArgs.push('--workers', workers);
|
|
524
536
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { output } from '../output.js';
|
|
8
8
|
import { existsSync, readFileSync, statSync, openSync, readSync, closeSync } from 'fs';
|
|
9
9
|
import { join, dirname } from 'path';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
11
11
|
import { createHash } from 'crypto';
|
|
12
12
|
import { execSync, exec, execFile } from 'child_process';
|
|
13
13
|
import { promisify } from 'util';
|
|
@@ -2117,7 +2117,7 @@ async function checkMetaharnessIntegration() {
|
|
|
2117
2117
|
// Runtime smoke: import the similarity module and exercise it
|
|
2118
2118
|
try {
|
|
2119
2119
|
const modPath = join(pluginDir, 'scripts', '_similarity.mjs');
|
|
2120
|
-
const mod = await import(modPath);
|
|
2120
|
+
const mod = await import(pathToFileURL(modPath).href);
|
|
2121
2121
|
if (typeof mod.similarity !== 'function') {
|
|
2122
2122
|
return {
|
|
2123
2123
|
name: 'MetaHarness integration (ADR-150)',
|
|
@@ -2144,7 +2144,7 @@ async function checkMetaharnessIntegration() {
|
|
|
2144
2144
|
// parallelization primitives oia-audit depends on; if they're
|
|
2145
2145
|
// missing, oia-audit's import fails and the whole pipeline breaks.
|
|
2146
2146
|
const harnessPath = join(pluginDir, 'scripts', '_harness.mjs');
|
|
2147
|
-
const harnessMod = await import(harnessPath);
|
|
2147
|
+
const harnessMod = await import(pathToFileURL(harnessPath).href);
|
|
2148
2148
|
if (typeof harnessMod.parseMcpScanText !== 'function') {
|
|
2149
2149
|
return {
|
|
2150
2150
|
name: 'MetaHarness integration (ADR-150)',
|
|
@@ -2580,6 +2580,67 @@ export const doctorCommand = {
|
|
|
2580
2580
|
const verbose = ctx.flags.verbose;
|
|
2581
2581
|
// Parser camelCases kebab-case flag names — read via `fixHandles`, not `['fix-handles']`.
|
|
2582
2582
|
const fixHandles = ctx.flags.fixHandles;
|
|
2583
|
+
// #2677: `--component memory` now runs the whole memory-health suite,
|
|
2584
|
+
// not just the existence check. Values can be a single check or an
|
|
2585
|
+
// array — expanded at execution time. Stuinfla's report showed the
|
|
2586
|
+
// existence-only check reporting PASS on a 99.97%-empty and even a
|
|
2587
|
+
// SQLite-malformed DB; the array here layers integrity → content →
|
|
2588
|
+
// embedding coverage over the existing existence probe; check 6 then
|
|
2589
|
+
// verifies that distilled episodes are actually Reflexion-retrievable and
|
|
2590
|
+
// execution feedback carries a lesson.
|
|
2591
|
+
const componentMap = {
|
|
2592
|
+
'version': checkVersionFreshness,
|
|
2593
|
+
'freshness': checkVersionFreshness,
|
|
2594
|
+
'node': checkNodeVersion,
|
|
2595
|
+
'npm': checkNpmVersion,
|
|
2596
|
+
'claude': checkClaudeCode,
|
|
2597
|
+
'browser': checkAgentBrowserVersion,
|
|
2598
|
+
'config': checkConfigFile,
|
|
2599
|
+
'stale-settings': checkStaleSettingsNpx, // #2448
|
|
2600
|
+
'helpers': () => checkHelperIntegrity(), // #3565
|
|
2601
|
+
'daemon': checkDaemonStatus,
|
|
2602
|
+
get memory() {
|
|
2603
|
+
return [
|
|
2604
|
+
checkMemoryDatabase, // existing: exists + statable (unchanged)
|
|
2605
|
+
checkMemoryIntegrity, // #2677 check 1: sql.js open + PRAGMA integrity_check
|
|
2606
|
+
...nativeAgentDbChecks, // #3195: present AgentDB authority, checked independently
|
|
2607
|
+
checkMemoryPersistenceDriver, // #2968/#3321: read-only native capability probe
|
|
2608
|
+
checkMemoryPackageVersion, // #3392: loaded memory package satisfies the declared range
|
|
2609
|
+
checkMemoryContent, // #2677 check 2: memory_entries content coverage
|
|
2610
|
+
checkMemoryEmbeddingCoverage, // #2677 check 3: vector coverage on populated rows
|
|
2611
|
+
checkMemoryReflexionCoverage, // #2677 check 6: episodes are retrievable
|
|
2612
|
+
checkMemoryCritiqueCoverage, // #2677 check 6: feedback carries lessons
|
|
2613
|
+
];
|
|
2614
|
+
},
|
|
2615
|
+
'memory-package': checkMemoryPackageVersion, // #3392
|
|
2616
|
+
'learning': checkLearningBridge, // #2545
|
|
2617
|
+
'learning-bridge': checkLearningBridge, // #2545
|
|
2618
|
+
'api': checkApiKeys,
|
|
2619
|
+
'git': checkGit,
|
|
2620
|
+
'mcp': checkMcpServers,
|
|
2621
|
+
'mcp-overhead': checkMcpSchemaOverhead,
|
|
2622
|
+
'aidefence': checkAIDefence, // #1807
|
|
2623
|
+
'disk': checkDiskSpace,
|
|
2624
|
+
'typescript': checkBuildTools,
|
|
2625
|
+
'agentic-flow': checkAgenticFlow,
|
|
2626
|
+
'encryption': checkEncryptionAtRest, // ADR-096 Phase 5
|
|
2627
|
+
'federation': checkFederationBreaker, // ADR-097 Phase 4
|
|
2628
|
+
'metaharness': [checkMetaharness, checkMetaharnessDeclaredPackages, checkMetaharnessIntegration], // ADR-150 — upstream + declared deps + ruflo-side
|
|
2629
|
+
'metaharness-integration': checkMetaharnessIntegration, // iter 45 — ruflo-side
|
|
2630
|
+
'funnel': checkFunnel, // ADR-305
|
|
2631
|
+
// ADR-307 — deep-dive array, same pattern as 'memory' above: the cheap
|
|
2632
|
+
// sponsored-consent check first, then binary/process/bind in the order
|
|
2633
|
+
// a user would actually debug them (is it installed? running? exposed?).
|
|
2634
|
+
'proxy': [checkProxySponsoredConsent, checkProxyBinary, checkProxyProcess, checkProxyBindAddress],
|
|
2635
|
+
'auth': checkAuth, // ADR-306
|
|
2636
|
+
'typesafe': checkTypesafeRouter, // opt-in @ruvector/typesafe task router
|
|
2637
|
+
'mods': checkMods, // ADR-404 — ruflo as a Claude Code mod
|
|
2638
|
+
};
|
|
2639
|
+
if (component !== undefined && !Object.hasOwn(componentMap, component)) {
|
|
2640
|
+
const message = `Unknown doctor component: ${JSON.stringify(component)}. Valid components: ${Object.keys(componentMap).join(', ')}`;
|
|
2641
|
+
output.printError(message);
|
|
2642
|
+
return { success: false, exitCode: 1, message };
|
|
2643
|
+
}
|
|
2583
2644
|
// Early-return short-circuit: `--fix-handles` is a targeted mitigation, not
|
|
2584
2645
|
// part of the health-check flow. Runs, reports, exits.
|
|
2585
2646
|
if (fixHandles) {
|
|
@@ -2684,62 +2745,8 @@ export const doctorCommand = {
|
|
|
2684
2745
|
checkAuth, // ADR-306 — Cognitum identity (warn-only; never fails bare `ruflo doctor`)
|
|
2685
2746
|
checkMods, // ADR-404 — Claude Code mod path (warn-only)
|
|
2686
2747
|
];
|
|
2687
|
-
// #2677: `--component memory` now runs the whole memory-health suite,
|
|
2688
|
-
// not just the existence check. Values can be a single check or an
|
|
2689
|
-
// array — expanded at execution time. Stuinfla's report showed the
|
|
2690
|
-
// existence-only check reporting PASS on a 99.97%-empty and even a
|
|
2691
|
-
// SQLite-malformed DB; the array here layers integrity → content →
|
|
2692
|
-
// embedding coverage over the existing existence probe; check 6 then
|
|
2693
|
-
// verifies that distilled episodes are actually Reflexion-retrievable and
|
|
2694
|
-
// execution feedback carries a lesson.
|
|
2695
|
-
const componentMap = {
|
|
2696
|
-
'version': checkVersionFreshness,
|
|
2697
|
-
'freshness': checkVersionFreshness,
|
|
2698
|
-
'node': checkNodeVersion,
|
|
2699
|
-
'npm': checkNpmVersion,
|
|
2700
|
-
'claude': checkClaudeCode,
|
|
2701
|
-
'browser': checkAgentBrowserVersion,
|
|
2702
|
-
'config': checkConfigFile,
|
|
2703
|
-
'stale-settings': checkStaleSettingsNpx, // #2448
|
|
2704
|
-
'helpers': () => checkHelperIntegrity(), // #3565
|
|
2705
|
-
'daemon': checkDaemonStatus,
|
|
2706
|
-
'memory': [
|
|
2707
|
-
checkMemoryDatabase, // existing: exists + statable (unchanged)
|
|
2708
|
-
checkMemoryIntegrity, // #2677 check 1: sql.js open + PRAGMA integrity_check
|
|
2709
|
-
...nativeAgentDbChecks, // #3195: present AgentDB authority, checked independently
|
|
2710
|
-
checkMemoryPersistenceDriver, // #2968/#3321: read-only native capability probe
|
|
2711
|
-
checkMemoryPackageVersion, // #3392: loaded memory package satisfies the declared range
|
|
2712
|
-
checkMemoryContent, // #2677 check 2: memory_entries content coverage
|
|
2713
|
-
checkMemoryEmbeddingCoverage, // #2677 check 3: vector coverage on populated rows
|
|
2714
|
-
checkMemoryReflexionCoverage, // #2677 check 6: episodes are retrievable
|
|
2715
|
-
checkMemoryCritiqueCoverage, // #2677 check 6: feedback carries lessons
|
|
2716
|
-
],
|
|
2717
|
-
'memory-package': checkMemoryPackageVersion, // #3392
|
|
2718
|
-
'learning': checkLearningBridge, // #2545
|
|
2719
|
-
'learning-bridge': checkLearningBridge, // #2545
|
|
2720
|
-
'api': checkApiKeys,
|
|
2721
|
-
'git': checkGit,
|
|
2722
|
-
'mcp': checkMcpServers,
|
|
2723
|
-
'mcp-overhead': checkMcpSchemaOverhead,
|
|
2724
|
-
'aidefence': checkAIDefence, // #1807
|
|
2725
|
-
'disk': checkDiskSpace,
|
|
2726
|
-
'typescript': checkBuildTools,
|
|
2727
|
-
'agentic-flow': checkAgenticFlow,
|
|
2728
|
-
'encryption': checkEncryptionAtRest, // ADR-096 Phase 5
|
|
2729
|
-
'federation': checkFederationBreaker, // ADR-097 Phase 4
|
|
2730
|
-
'metaharness': [checkMetaharness, checkMetaharnessDeclaredPackages, checkMetaharnessIntegration], // ADR-150 — upstream + declared deps + ruflo-side
|
|
2731
|
-
'metaharness-integration': checkMetaharnessIntegration, // iter 45 — ruflo-side
|
|
2732
|
-
'funnel': checkFunnel, // ADR-305
|
|
2733
|
-
// ADR-307 — deep-dive array, same pattern as 'memory' above: the cheap
|
|
2734
|
-
// sponsored-consent check first, then binary/process/bind in the order
|
|
2735
|
-
// a user would actually debug them (is it installed? running? exposed?).
|
|
2736
|
-
'proxy': [checkProxySponsoredConsent, checkProxyBinary, checkProxyProcess, checkProxyBindAddress],
|
|
2737
|
-
'auth': checkAuth, // ADR-306
|
|
2738
|
-
'typesafe': checkTypesafeRouter, // opt-in @ruvector/typesafe task router
|
|
2739
|
-
'mods': checkMods, // ADR-404 — ruflo as a Claude Code mod
|
|
2740
|
-
};
|
|
2741
2748
|
let checksToRun = allChecks;
|
|
2742
|
-
if (component
|
|
2749
|
+
if (component !== undefined) {
|
|
2743
2750
|
const entry = componentMap[component];
|
|
2744
2751
|
checksToRun = Array.isArray(entry) ? entry : [entry];
|
|
2745
2752
|
}
|
|
@@ -1016,6 +1016,13 @@ const consensusCommand = {
|
|
|
1016
1016
|
const action = ctx.flags.action || 'list';
|
|
1017
1017
|
try {
|
|
1018
1018
|
const result = await callMCPTool('hive-mind_consensus', { action, proposalId: ctx.flags.proposalId, type: ctx.flags.type, value: ctx.flags.value, vote: ctx.flags.vote === 'yes', voterId: ctx.flags.voterId, hiveToken: getHiveTokenForCli() });
|
|
1019
|
+
if (result.error) {
|
|
1020
|
+
if (ctx.flags.format === 'json')
|
|
1021
|
+
output.printJson(result);
|
|
1022
|
+
else
|
|
1023
|
+
output.printError(`Consensus error: ${String(result.error)}`);
|
|
1024
|
+
return { success: false, exitCode: 1, data: result };
|
|
1025
|
+
}
|
|
1019
1026
|
if (ctx.flags.format === 'json') {
|
|
1020
1027
|
output.printJson(result);
|
|
1021
1028
|
return { success: true, data: result };
|
package/dist/src/commands/mcp.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { output } from '../output.js';
|
|
9
9
|
import { confirm } from '../prompt.js';
|
|
10
10
|
import { installParentDeathWatchdog } from '../runtime/parent-death-watchdog.js';
|
|
11
|
-
import { getServerManager, getMCPServerStatus, filterAdvertisedMcpTools, parseMcpToolSelection, } from '../mcp-server.js';
|
|
11
|
+
import { getServerManager, getMCPServerStatus, resolveMcpHttpAuthToken, isLoopbackHost, filterAdvertisedMcpTools, parseMcpToolSelection, } from '../mcp-server.js';
|
|
12
12
|
import { listMCPTools, callMCPTool, hasTool } from '../mcp-client.js';
|
|
13
13
|
// MCP tools categories
|
|
14
14
|
const TOOL_CATEGORIES = [
|
|
@@ -71,6 +71,16 @@ const startCommand = {
|
|
|
71
71
|
description: 'HTTP request timeout in milliseconds (default 30000; env RUFLO_MCP_REQUEST_TIMEOUT_MS)',
|
|
72
72
|
type: 'number'
|
|
73
73
|
},
|
|
74
|
+
{
|
|
75
|
+
name: 'auth-token-file',
|
|
76
|
+
description: 'Read the HTTP bearer token from this file (http transport). Preferred over --auth-token; env RUFLO_MCP_HTTP_TOKEN also works',
|
|
77
|
+
type: 'string'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'auth-token',
|
|
81
|
+
description: 'HTTP bearer token (16+ printable ASCII chars). Visible in argv/ps - prefer RUFLO_MCP_HTTP_TOKEN or --auth-token-file',
|
|
82
|
+
type: 'string'
|
|
83
|
+
},
|
|
74
84
|
{
|
|
75
85
|
name: 'daemon',
|
|
76
86
|
short: 'd',
|
|
@@ -90,6 +100,8 @@ const startCommand = {
|
|
|
90
100
|
{ command: 'claude-flow mcp start', description: 'Start with defaults (stdio)' },
|
|
91
101
|
{ command: 'claude-flow mcp start -p 8080 -t http', description: 'Start HTTP server' },
|
|
92
102
|
{ command: 'claude-flow mcp start -t http --request-timeout-ms 120000', description: 'Allow slower cold-start HTTP tools' },
|
|
103
|
+
{ command: 'RUFLO_MCP_HTTP_TOKEN=<16+ chars> claude-flow mcp start -t http', description: 'HTTP server requiring "Authorization: Bearer <token>" on every request (except GET /health)' },
|
|
104
|
+
{ command: 'RUFLO_MCP_HTTP_TOKEN=<16+ chars> claude-flow mcp start -t http --host 0.0.0.0', description: 'Non-loopback bind: allowed only with a token (or RUFLO_MCP_ALLOW_UNAUTHENTICATED_HTTP=1)' },
|
|
93
105
|
{ command: 'claude-flow mcp start -d', description: 'Start as daemon' },
|
|
94
106
|
{ command: 'claude-flow mcp start -f', description: 'Force restart (kill existing)' }
|
|
95
107
|
],
|
|
@@ -109,6 +121,17 @@ const startCommand = {
|
|
|
109
121
|
output.printError('Request timeout must be an integer from 1 to 3600000 milliseconds');
|
|
110
122
|
return { success: false, exitCode: 1 };
|
|
111
123
|
}
|
|
124
|
+
let authToken;
|
|
125
|
+
try {
|
|
126
|
+
authToken = resolveMcpHttpAuthToken({
|
|
127
|
+
token: (ctx.flags.authToken ?? ctx.flags['auth-token']),
|
|
128
|
+
tokenFile: (ctx.flags.authTokenFile ?? ctx.flags['auth-token-file']),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
output.printError(error.message);
|
|
133
|
+
return { success: false, exitCode: 1 };
|
|
134
|
+
}
|
|
112
135
|
const daemon = ctx.flags.daemon ?? false;
|
|
113
136
|
const force = ctx.flags.force ?? false;
|
|
114
137
|
output.writeln();
|
|
@@ -166,6 +189,7 @@ const startCommand = {
|
|
|
166
189
|
port,
|
|
167
190
|
tools: !tools || tools === 'all' ? 'all' : tools.split(','),
|
|
168
191
|
...(requestTimeoutMs === undefined ? {} : { requestTimeoutMs }),
|
|
192
|
+
...(authToken ? { authToken } : {}),
|
|
169
193
|
daemonize: daemon,
|
|
170
194
|
};
|
|
171
195
|
try {
|
|
@@ -218,6 +242,15 @@ const startCommand = {
|
|
|
218
242
|
if (transport === 'http') {
|
|
219
243
|
output.writeln(output.dim(` Health: http://${host}:${port}/health`));
|
|
220
244
|
output.writeln(output.dim(` RPC: http://${host}:${port}/rpc`));
|
|
245
|
+
if (authToken) {
|
|
246
|
+
output.writeln(output.dim(' Auth: bearer token required (Authorization: Bearer <token>); /health is public'));
|
|
247
|
+
}
|
|
248
|
+
else if (isLoopbackHost(host)) {
|
|
249
|
+
output.printWarning('No auth token set: any local process (and DNS-rebinding web pages) can call tools. Set RUFLO_MCP_HTTP_TOKEN to require a bearer token.');
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
output.printWarning('Running UNAUTHENTICATED on a non-loopback host (RUFLO_MCP_ALLOW_UNAUTHENTICATED_HTTP is set).');
|
|
253
|
+
}
|
|
221
254
|
}
|
|
222
255
|
else if (transport === 'websocket') {
|
|
223
256
|
output.writeln(output.dim(` WebSocket: ws://${host}:${port}/ws`));
|
|
@@ -596,6 +629,7 @@ const execCommand = {
|
|
|
596
629
|
const startTime = performance.now();
|
|
597
630
|
const result = await callMCPTool(tool, params, {
|
|
598
631
|
sessionId: `cli-${Date.now().toString(36)}`,
|
|
632
|
+
transport: 'cli',
|
|
599
633
|
requestId: `exec-${Date.now()}`,
|
|
600
634
|
});
|
|
601
635
|
const duration = performance.now() - startTime;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* V3 CLI `memory backup` command.
|
|
3
3
|
*
|
|
4
|
-
* WAL-safe
|
|
4
|
+
* WAL-safe snapshots of the active CLI and AgentDB stores with rotation
|
|
5
5
|
* and optional GCS offsite. Thin surface over ../services/memory-backup.js; the
|
|
6
6
|
* daemon's nightly `backup` worker calls the same service.
|
|
7
7
|
*/
|