claude-flow 3.5.44 → 3.5.46

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": "claude-flow",
3
- "version": "3.5.44",
3
+ "version": "3.5.46",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Autopilot Shared State Module
3
+ *
4
+ * Centralizes state management, validation, and task discovery
5
+ * for both CLI command and MCP tools. Eliminates code duplication.
6
+ *
7
+ * ADR-072: Autopilot Integration
8
+ * Security: Addresses prototype pollution, NaN bypass, input validation
9
+ */
10
+ export declare const STATE_DIR = ".claude-flow/data";
11
+ export declare const STATE_FILE = ".claude-flow/data/autopilot-state.json";
12
+ export declare const LOG_FILE = ".claude-flow/data/autopilot-log.json";
13
+ /** Allowlist for valid task sources */
14
+ export declare const VALID_TASK_SOURCES: Set<string>;
15
+ /** Terminal task statuses */
16
+ export declare const TERMINAL_STATUSES: Set<string>;
17
+ export interface AutopilotState {
18
+ sessionId: string;
19
+ enabled: boolean;
20
+ startTime: number;
21
+ iterations: number;
22
+ maxIterations: number;
23
+ timeoutMinutes: number;
24
+ taskSources: string[];
25
+ lastCheck: number | null;
26
+ history: Array<{
27
+ ts: number;
28
+ iteration: number;
29
+ completed: number;
30
+ total: number;
31
+ }>;
32
+ }
33
+ export interface AutopilotLogEntry {
34
+ ts: number;
35
+ event: string;
36
+ [key: string]: unknown;
37
+ }
38
+ export interface TaskInfo {
39
+ id: string;
40
+ subject: string;
41
+ status: string;
42
+ source: string;
43
+ }
44
+ export interface TaskProgress {
45
+ completed: number;
46
+ total: number;
47
+ percent: number;
48
+ incomplete: TaskInfo[];
49
+ }
50
+ /**
51
+ * Safe JSON.parse that prevents prototype pollution.
52
+ */
53
+ export declare function safeJsonParse<T>(raw: string): T;
54
+ /**
55
+ * Validate and coerce a numeric parameter. Returns the default if
56
+ * the input is NaN, undefined, or outside the allowed range.
57
+ */
58
+ export declare function validateNumber(value: unknown, min: number, max: number, defaultValue: number): number;
59
+ /**
60
+ * Validate task sources against the allowlist.
61
+ * Returns only valid sources; falls back to defaults if none are valid.
62
+ */
63
+ export declare function validateTaskSources(sources: unknown): string[];
64
+ export declare function getDefaultState(): AutopilotState;
65
+ export declare function loadState(): AutopilotState;
66
+ export declare function saveState(state: AutopilotState): void;
67
+ export declare function appendLog(entry: AutopilotLogEntry): void;
68
+ export declare function loadLog(): AutopilotLogEntry[];
69
+ export declare function discoverTasks(sources: string[]): TaskInfo[];
70
+ export declare function isTerminal(status: string): boolean;
71
+ export declare function getProgress(tasks: TaskInfo[]): TaskProgress;
72
+ export declare function calculateReward(iterations: number, durationMs: number): number;
73
+ export declare function tryLoadLearning(): Promise<{
74
+ initialize: () => Promise<boolean>;
75
+ [key: string]: unknown;
76
+ } | null>;
77
+ //# sourceMappingURL=autopilot-state.d.ts.map
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Autopilot Shared State Module
3
+ *
4
+ * Centralizes state management, validation, and task discovery
5
+ * for both CLI command and MCP tools. Eliminates code duplication.
6
+ *
7
+ * ADR-072: Autopilot Integration
8
+ * Security: Addresses prototype pollution, NaN bypass, input validation
9
+ */
10
+ // ── Constants ─────────────────────────────────────────────────
11
+ export const STATE_DIR = '.claude-flow/data';
12
+ export const STATE_FILE = `${STATE_DIR}/autopilot-state.json`;
13
+ export const LOG_FILE = `${STATE_DIR}/autopilot-log.json`;
14
+ /** Maximum entries kept in state.history (prevents unbounded growth) */
15
+ const MAX_HISTORY_ENTRIES = 50;
16
+ /** Maximum entries kept in the event log */
17
+ const MAX_LOG_ENTRIES = 1000;
18
+ /** Allowlist for valid task sources */
19
+ export const VALID_TASK_SOURCES = new Set(['team-tasks', 'swarm-tasks', 'file-checklist']);
20
+ /** Terminal task statuses */
21
+ export const TERMINAL_STATUSES = new Set(['completed', 'done', 'cancelled', 'skipped', 'failed']);
22
+ // ── Validation Helpers ────────────────────────────────────────
23
+ /**
24
+ * Sanitize a parsed JSON object to prevent prototype pollution.
25
+ * Removes __proto__, constructor, and prototype keys recursively.
26
+ */
27
+ function sanitizeObject(obj) {
28
+ if (obj === null || typeof obj !== 'object')
29
+ return obj;
30
+ if (Array.isArray(obj))
31
+ return obj.map(sanitizeObject);
32
+ const clean = {};
33
+ for (const key of Object.keys(obj)) {
34
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype')
35
+ continue;
36
+ clean[key] = sanitizeObject(obj[key]);
37
+ }
38
+ return clean;
39
+ }
40
+ /**
41
+ * Safe JSON.parse that prevents prototype pollution.
42
+ */
43
+ export function safeJsonParse(raw) {
44
+ return sanitizeObject(JSON.parse(raw));
45
+ }
46
+ /**
47
+ * Validate and coerce a numeric parameter. Returns the default if
48
+ * the input is NaN, undefined, or outside the allowed range.
49
+ */
50
+ export function validateNumber(value, min, max, defaultValue) {
51
+ if (value === undefined || value === null)
52
+ return defaultValue;
53
+ const num = Number(value);
54
+ if (!Number.isFinite(num))
55
+ return defaultValue;
56
+ return Math.min(Math.max(min, Math.round(num)), max);
57
+ }
58
+ /**
59
+ * Validate task sources against the allowlist.
60
+ * Returns only valid sources; falls back to defaults if none are valid.
61
+ */
62
+ export function validateTaskSources(sources) {
63
+ const defaults = ['team-tasks', 'swarm-tasks', 'file-checklist'];
64
+ if (!Array.isArray(sources))
65
+ return defaults;
66
+ const valid = sources
67
+ .filter((s) => typeof s === 'string')
68
+ .map(s => s.trim())
69
+ .filter(s => VALID_TASK_SOURCES.has(s));
70
+ return valid.length > 0 ? valid : defaults;
71
+ }
72
+ // ── State Management ──────────────────────────────────────────
73
+ export function getDefaultState() {
74
+ const crypto = require('crypto');
75
+ return {
76
+ sessionId: crypto.randomUUID(),
77
+ enabled: false,
78
+ startTime: Date.now(),
79
+ iterations: 0,
80
+ maxIterations: 50,
81
+ timeoutMinutes: 240,
82
+ taskSources: ['team-tasks', 'swarm-tasks', 'file-checklist'],
83
+ lastCheck: null,
84
+ history: [],
85
+ };
86
+ }
87
+ export function loadState() {
88
+ const fs = require('fs');
89
+ const path = require('path');
90
+ const filePath = path.resolve(STATE_FILE);
91
+ const defaults = getDefaultState();
92
+ try {
93
+ if (fs.existsSync(filePath)) {
94
+ const raw = safeJsonParse(fs.readFileSync(filePath, 'utf-8'));
95
+ const merged = { ...defaults, ...raw };
96
+ // Re-validate fields that could be tampered with
97
+ merged.maxIterations = validateNumber(merged.maxIterations, 1, 1000, 50);
98
+ merged.timeoutMinutes = validateNumber(merged.timeoutMinutes, 1, 1440, 240);
99
+ merged.iterations = validateNumber(merged.iterations, 0, 1000, 0);
100
+ merged.taskSources = validateTaskSources(merged.taskSources);
101
+ // Cap history to prevent unbounded growth
102
+ if (Array.isArray(merged.history) && merged.history.length > MAX_HISTORY_ENTRIES) {
103
+ merged.history = merged.history.slice(-MAX_HISTORY_ENTRIES);
104
+ }
105
+ return merged;
106
+ }
107
+ }
108
+ catch {
109
+ // Corrupted state file — return defaults
110
+ }
111
+ return defaults;
112
+ }
113
+ export function saveState(state) {
114
+ const fs = require('fs');
115
+ const path = require('path');
116
+ const dir = path.resolve(STATE_DIR);
117
+ if (!fs.existsSync(dir))
118
+ fs.mkdirSync(dir, { recursive: true });
119
+ // Cap history before saving
120
+ if (state.history.length > MAX_HISTORY_ENTRIES) {
121
+ state.history = state.history.slice(-MAX_HISTORY_ENTRIES);
122
+ }
123
+ const tmpFile = path.resolve(STATE_FILE) + '.tmp';
124
+ fs.writeFileSync(tmpFile, JSON.stringify(state, null, 2));
125
+ fs.renameSync(tmpFile, path.resolve(STATE_FILE));
126
+ }
127
+ export function appendLog(entry) {
128
+ const fs = require('fs');
129
+ const path = require('path');
130
+ const filePath = path.resolve(LOG_FILE);
131
+ const dir = path.resolve(STATE_DIR);
132
+ if (!fs.existsSync(dir))
133
+ fs.mkdirSync(dir, { recursive: true });
134
+ let log = [];
135
+ try {
136
+ if (fs.existsSync(filePath)) {
137
+ log = safeJsonParse(fs.readFileSync(filePath, 'utf-8'));
138
+ if (!Array.isArray(log))
139
+ log = [];
140
+ }
141
+ }
142
+ catch {
143
+ log = [];
144
+ }
145
+ log.push(entry);
146
+ if (log.length > MAX_LOG_ENTRIES)
147
+ log = log.slice(-MAX_LOG_ENTRIES);
148
+ const tmpFile = filePath + '.tmp';
149
+ fs.writeFileSync(tmpFile, JSON.stringify(log, null, 2));
150
+ fs.renameSync(tmpFile, filePath);
151
+ }
152
+ export function loadLog() {
153
+ const fs = require('fs');
154
+ const path = require('path');
155
+ const filePath = path.resolve(LOG_FILE);
156
+ try {
157
+ if (fs.existsSync(filePath)) {
158
+ const result = safeJsonParse(fs.readFileSync(filePath, 'utf-8'));
159
+ return Array.isArray(result) ? result : [];
160
+ }
161
+ }
162
+ catch {
163
+ // Corrupted log — return empty
164
+ }
165
+ return [];
166
+ }
167
+ // ── Task Discovery ────────────────────────────────────────────
168
+ export function discoverTasks(sources) {
169
+ const fs = require('fs');
170
+ const path = require('path');
171
+ const os = require('os');
172
+ const tasks = [];
173
+ // Only process valid sources
174
+ const validSources = sources.filter(s => VALID_TASK_SOURCES.has(s));
175
+ for (const source of validSources) {
176
+ if (source === 'team-tasks') {
177
+ const tasksDir = path.join(os.homedir(), '.claude', 'tasks');
178
+ try {
179
+ if (fs.existsSync(tasksDir)) {
180
+ const teams = fs.readdirSync(tasksDir, { withFileTypes: true });
181
+ for (const team of teams) {
182
+ if (!team.isDirectory())
183
+ continue;
184
+ const teamDir = path.join(tasksDir, team.name);
185
+ const files = fs.readdirSync(teamDir).filter((f) => f.endsWith('.json'));
186
+ for (const file of files) {
187
+ try {
188
+ const data = safeJsonParse(fs.readFileSync(path.join(teamDir, file), 'utf-8'));
189
+ tasks.push({
190
+ id: String(data.id || file.replace('.json', '')),
191
+ subject: String(data.subject || data.title || file),
192
+ status: String(data.status || 'unknown'),
193
+ source: 'team-tasks',
194
+ });
195
+ }
196
+ catch { /* skip individual file */ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ catch { /* skip source */ }
202
+ }
203
+ if (source === 'swarm-tasks') {
204
+ const swarmFile = path.resolve('.claude-flow/swarm-tasks.json');
205
+ try {
206
+ if (fs.existsSync(swarmFile)) {
207
+ const data = safeJsonParse(fs.readFileSync(swarmFile, 'utf-8'));
208
+ const swarmTasks = Array.isArray(data) ? data : (data.tasks || []);
209
+ for (const t of swarmTasks) {
210
+ if (t && typeof t === 'object') {
211
+ const task = t;
212
+ tasks.push({
213
+ id: String(task.id || task.taskId || `swarm-${tasks.length}`),
214
+ subject: String(task.subject || task.description || task.name || 'Unnamed task'),
215
+ status: String(task.status || 'unknown'),
216
+ source: 'swarm-tasks',
217
+ });
218
+ }
219
+ }
220
+ }
221
+ }
222
+ catch { /* skip source */ }
223
+ }
224
+ if (source === 'file-checklist') {
225
+ const checklistFile = path.resolve('.claude-flow/data/checklist.json');
226
+ try {
227
+ if (fs.existsSync(checklistFile)) {
228
+ const data = safeJsonParse(fs.readFileSync(checklistFile, 'utf-8'));
229
+ const items = Array.isArray(data) ? data : (data.items || []);
230
+ for (const item of items) {
231
+ if (item && typeof item === 'object') {
232
+ const i = item;
233
+ tasks.push({
234
+ id: String(i.id || `check-${tasks.length}`),
235
+ subject: String(i.subject || i.text || i.description || 'Unnamed item'),
236
+ status: String(i.status || (i.done ? 'completed' : 'pending')),
237
+ source: 'file-checklist',
238
+ });
239
+ }
240
+ }
241
+ }
242
+ }
243
+ catch { /* skip source */ }
244
+ }
245
+ }
246
+ return tasks;
247
+ }
248
+ // ── Progress Helpers ──────────────────────────────────────────
249
+ export function isTerminal(status) {
250
+ return TERMINAL_STATUSES.has(status.toLowerCase());
251
+ }
252
+ export function getProgress(tasks) {
253
+ const completed = tasks.filter(t => isTerminal(t.status)).length;
254
+ const total = tasks.length;
255
+ const percent = total === 0 ? 100 : Math.round((completed / total) * 100);
256
+ const incomplete = tasks.filter(t => !isTerminal(t.status));
257
+ return { completed, total, percent, incomplete };
258
+ }
259
+ // ── Reward Calculation ────────────────────────────────────────
260
+ export function calculateReward(iterations, durationMs) {
261
+ const iterFactor = (1 - iterations / (iterations + 10)) * 0.6;
262
+ const timeFactor = (1 - Math.min(durationMs / 3600000, 1)) * 0.4;
263
+ return Math.round((iterFactor + timeFactor) * 100) / 100;
264
+ }
265
+ // ── Learning Integration ──────────────────────────────────────
266
+ export async function tryLoadLearning() {
267
+ try {
268
+ const modPath = 'agentic-flow/dist/coordination/autopilot-learning.js';
269
+ const mod = await import(/* webpackIgnore: true */ modPath).catch(() => null);
270
+ if (mod?.AutopilotLearning) {
271
+ const instance = new mod.AutopilotLearning();
272
+ if (await instance.initialize())
273
+ return instance;
274
+ }
275
+ }
276
+ catch { /* not available */ }
277
+ return null;
278
+ }
279
+ //# sourceMappingURL=autopilot-state.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * V3 CLI Autopilot Command
3
+ * Persistent swarm completion — keeps agents working until ALL tasks are done.
4
+ *
5
+ * ADR-072: Autopilot Integration
6
+ */
7
+ import type { Command } from '../types.js';
8
+ export declare function autopilotCheck(): Promise<{
9
+ allowStop: boolean;
10
+ reason: string;
11
+ continueWith?: string;
12
+ }>;
13
+ export declare const autopilotCommand: Command;
14
+ export default autopilotCommand;
15
+ //# sourceMappingURL=autopilot.d.ts.map
@@ -0,0 +1,362 @@
1
+ /**
2
+ * V3 CLI Autopilot Command
3
+ * Persistent swarm completion — keeps agents working until ALL tasks are done.
4
+ *
5
+ * ADR-072: Autopilot Integration
6
+ */
7
+ import { output } from '../output.js';
8
+ import { loadState, saveState, appendLog, loadLog, discoverTasks, getProgress, calculateReward, tryLoadLearning, validateNumber, validateTaskSources, LOG_FILE, } from '../autopilot-state.js';
9
+ // ── Check Handler (for Stop hook) ─────────────────────────────
10
+ export async function autopilotCheck() {
11
+ const state = loadState();
12
+ if (!state.enabled) {
13
+ return { allowStop: true, reason: 'Autopilot disabled' };
14
+ }
15
+ // Safety: max iterations
16
+ if (state.iterations >= state.maxIterations) {
17
+ state.enabled = false;
18
+ saveState(state);
19
+ appendLog({ ts: Date.now(), event: 'max-iterations-reached', iterations: state.iterations });
20
+ return { allowStop: true, reason: `Max iterations (${state.maxIterations}) reached` };
21
+ }
22
+ // Safety: timeout
23
+ const elapsed = Date.now() - state.startTime;
24
+ if (elapsed > state.timeoutMinutes * 60000) {
25
+ state.enabled = false;
26
+ saveState(state);
27
+ appendLog({ ts: Date.now(), event: 'timeout-reached', elapsed: Math.round(elapsed / 60000) });
28
+ return { allowStop: true, reason: `Timeout (${state.timeoutMinutes} min) reached` };
29
+ }
30
+ // Discover tasks
31
+ const tasks = discoverTasks(state.taskSources);
32
+ if (tasks.length === 0) {
33
+ return { allowStop: true, reason: 'No tasks discovered from any source' };
34
+ }
35
+ const progress = getProgress(tasks);
36
+ if (progress.incomplete.length === 0) {
37
+ const reward = calculateReward(state.iterations, elapsed);
38
+ state.enabled = false;
39
+ saveState(state);
40
+ appendLog({ ts: Date.now(), event: 'all-tasks-complete', total: progress.total, iterations: state.iterations, durationMs: elapsed, reward });
41
+ return { allowStop: true, reason: `All ${progress.total} tasks complete (${state.iterations} iterations, reward: ${reward})` };
42
+ }
43
+ // Stall detection
44
+ const recentHistory = state.history.slice(-5);
45
+ const isStalled = recentHistory.length >= 5 && recentHistory.every(h => h.completed === progress.completed);
46
+ if (isStalled && state.history.length >= 10) {
47
+ state.enabled = false;
48
+ saveState(state);
49
+ appendLog({ ts: Date.now(), event: 'stall-auto-disable', iterations: state.iterations, completed: progress.completed });
50
+ return { allowStop: true, reason: `Stalled: no progress in 10 iterations (${progress.completed}/${progress.total} complete)` };
51
+ }
52
+ // Re-engage
53
+ state.iterations++;
54
+ state.lastCheck = Date.now();
55
+ state.history.push({ ts: Date.now(), iteration: state.iterations, completed: progress.completed, total: progress.total });
56
+ saveState(state);
57
+ const stallWarning = isStalled
58
+ ? '\nWARNING: No progress in 5 iterations. Consider breaking tasks into smaller subtasks or trying a different approach.'
59
+ : '';
60
+ const taskList = progress.incomplete.slice(0, 5).map(t => `- ${t.subject} (${t.status})`).join('\n');
61
+ const moreCount = progress.incomplete.length > 5 ? `\n... and ${progress.incomplete.length - 5} more` : '';
62
+ const continuePrompt = [
63
+ `AUTOPILOT: ${progress.completed}/${progress.total} tasks complete (${progress.percent}%).`,
64
+ `Iteration ${state.iterations}/${state.maxIterations}.`,
65
+ `Remaining tasks:\n${taskList}${moreCount}`,
66
+ stallWarning,
67
+ `Continue working on the remaining tasks. Do not stop until all are complete.`,
68
+ ].join('\n');
69
+ appendLog({ ts: Date.now(), event: 're-engaging', iteration: state.iterations, completed: progress.completed, remaining: progress.incomplete.length });
70
+ return { allowStop: false, reason: `${progress.incomplete.length}/${progress.total} tasks remaining (iteration ${state.iterations}/${state.maxIterations})`, continueWith: continuePrompt };
71
+ }
72
+ // ── Subcommands ───────────────────────────────────────────────
73
+ const statusCommand = {
74
+ name: 'status',
75
+ description: 'Show autopilot state, iterations, and task progress',
76
+ options: [{ name: 'json', type: 'boolean', description: 'Output as JSON' }],
77
+ action: async (ctx) => {
78
+ const state = loadState();
79
+ const tasks = discoverTasks(state.taskSources);
80
+ const progress = getProgress(tasks);
81
+ const elapsed = state.enabled ? Date.now() - state.startTime : 0;
82
+ if (ctx.flags?.json) {
83
+ output.printJson({
84
+ enabled: state.enabled, sessionId: state.sessionId, iterations: state.iterations,
85
+ maxIterations: state.maxIterations, timeoutMinutes: state.timeoutMinutes, elapsedMs: elapsed,
86
+ tasks: { completed: progress.completed, total: progress.total, percent: progress.percent },
87
+ taskSources: state.taskSources,
88
+ });
89
+ return { success: true };
90
+ }
91
+ output.writeln(`Autopilot: ${state.enabled ? '✓ ENABLED' : '✗ DISABLED'}`);
92
+ output.writeln(`Session: ${state.sessionId.slice(0, 8)}...`);
93
+ output.writeln(`Iterations: ${state.iterations}/${state.maxIterations}`);
94
+ output.writeln(`Timeout: ${state.timeoutMinutes} min`);
95
+ output.writeln(`Elapsed: ${Math.round(elapsed / 60000)} min`);
96
+ output.writeln(`Tasks: ${progress.completed}/${progress.total} (${progress.percent}%)`);
97
+ output.writeln(`Sources: ${state.taskSources.join(', ')}`);
98
+ if (progress.incomplete.length > 0 && progress.incomplete.length <= 10) {
99
+ output.writeln('\nRemaining tasks:');
100
+ for (const t of progress.incomplete) {
101
+ output.writeln(` - [${t.source}] ${t.subject} (${t.status})`);
102
+ }
103
+ }
104
+ return { success: true };
105
+ },
106
+ };
107
+ const enableCommand = {
108
+ name: 'enable',
109
+ description: 'Enable persistent completion',
110
+ action: async () => {
111
+ const state = loadState();
112
+ state.enabled = true;
113
+ state.startTime = Date.now();
114
+ state.iterations = 0;
115
+ saveState(state);
116
+ appendLog({ ts: Date.now(), event: 'enabled', sessionId: state.sessionId, maxIterations: state.maxIterations });
117
+ output.writeln(output.success(`Autopilot enabled (max ${state.maxIterations} iterations, ${state.timeoutMinutes} min timeout)`));
118
+ return { success: true };
119
+ },
120
+ };
121
+ const disableCommand = {
122
+ name: 'disable',
123
+ description: 'Disable re-engagement loop',
124
+ action: async () => {
125
+ const state = loadState();
126
+ const wasEnabled = state.enabled;
127
+ state.enabled = false;
128
+ saveState(state);
129
+ if (wasEnabled)
130
+ appendLog({ ts: Date.now(), event: 'disabled', iterations: state.iterations });
131
+ output.writeln('Autopilot disabled');
132
+ return { success: true };
133
+ },
134
+ };
135
+ const configCommand = {
136
+ name: 'config',
137
+ description: 'Configure max iterations, timeout, and task sources',
138
+ options: [
139
+ { name: 'max-iterations', type: 'string', description: 'Max re-engagement iterations (1-1000)' },
140
+ { name: 'timeout', type: 'string', description: 'Timeout in minutes (1-1440)' },
141
+ { name: 'task-sources', type: 'string', description: 'Comma-separated task sources' },
142
+ ],
143
+ action: async (ctx) => {
144
+ const state = loadState();
145
+ const maxIter = ctx.flags?.['max-iterations'];
146
+ const timeout = ctx.flags?.timeout;
147
+ const sources = ctx.flags?.['task-sources'];
148
+ if (maxIter)
149
+ state.maxIterations = validateNumber(maxIter, 1, 1000, state.maxIterations);
150
+ if (timeout)
151
+ state.timeoutMinutes = validateNumber(timeout, 1, 1440, state.timeoutMinutes);
152
+ if (sources)
153
+ state.taskSources = validateTaskSources(sources.split(',').map(s => s.trim()).filter(Boolean));
154
+ saveState(state);
155
+ appendLog({ ts: Date.now(), event: 'config-updated', maxIterations: state.maxIterations, timeoutMinutes: state.timeoutMinutes, taskSources: state.taskSources });
156
+ output.writeln(`Config updated: maxIterations=${state.maxIterations}, timeout=${state.timeoutMinutes}min, sources=${state.taskSources.join(',')}`);
157
+ return { success: true };
158
+ },
159
+ };
160
+ const resetCommand = {
161
+ name: 'reset',
162
+ description: 'Reset iteration counter and timer',
163
+ action: async () => {
164
+ const state = loadState();
165
+ state.iterations = 0;
166
+ state.startTime = Date.now();
167
+ state.history = [];
168
+ state.lastCheck = null;
169
+ saveState(state);
170
+ appendLog({ ts: Date.now(), event: 'reset' });
171
+ output.writeln('Autopilot state reset (iterations=0, timer restarted)');
172
+ return { success: true };
173
+ },
174
+ };
175
+ const logCommand = {
176
+ name: 'log',
177
+ description: 'View autopilot event log',
178
+ options: [
179
+ { name: 'last', type: 'string', description: 'Show last N entries' },
180
+ { name: 'json', type: 'boolean', description: 'Output as JSON' },
181
+ { name: 'clear', type: 'boolean', description: 'Clear the log' },
182
+ ],
183
+ action: async (ctx) => {
184
+ if (ctx.flags?.clear) {
185
+ const fs = require('fs');
186
+ const path = require('path');
187
+ try {
188
+ fs.writeFileSync(path.resolve(LOG_FILE), '[]');
189
+ }
190
+ catch { /* ignore */ }
191
+ output.writeln('Autopilot log cleared');
192
+ return { success: true };
193
+ }
194
+ const log = loadLog();
195
+ const lastRaw = ctx.flags?.last;
196
+ const last = lastRaw ? validateNumber(lastRaw, 1, 10000, 50) : undefined;
197
+ const entries = last ? log.slice(-last) : log;
198
+ if (ctx.flags?.json) {
199
+ output.printJson(entries);
200
+ return { success: true };
201
+ }
202
+ if (entries.length === 0) {
203
+ output.writeln('No autopilot events logged');
204
+ return { success: true };
205
+ }
206
+ for (const e of entries) {
207
+ const time = new Date(e.ts).toISOString().slice(11, 19);
208
+ const details = Object.entries(e).filter(([k]) => k !== 'ts' && k !== 'event').map(([k, v]) => `${k}=${v}`).join(' ');
209
+ output.writeln(`[${time}] ${e.event} ${details}`);
210
+ }
211
+ return { success: true };
212
+ },
213
+ };
214
+ const learnCommand = {
215
+ name: 'learn',
216
+ description: 'Discover success patterns from past completions',
217
+ options: [{ name: 'json', type: 'boolean', description: 'Output as JSON' }],
218
+ action: async (ctx) => {
219
+ const learning = await tryLoadLearning();
220
+ if (!learning) {
221
+ output.writeln('Learning not available (AgentDB not initialized). Autopilot still works for task completion tracking.');
222
+ return { success: true };
223
+ }
224
+ const metrics = await learning.getMetrics();
225
+ const patterns = await learning.discoverSuccessPatterns();
226
+ if (ctx.flags?.json) {
227
+ output.printJson({ metrics, patterns });
228
+ return { success: true };
229
+ }
230
+ output.writeln(`Episodes: ${metrics.episodes}`);
231
+ output.writeln(`Patterns: ${metrics.patterns}`);
232
+ output.writeln(`Trajectories: ${metrics.trajectories}`);
233
+ if (patterns.length > 0) {
234
+ output.writeln('\nDiscovered patterns:');
235
+ for (const p of patterns) {
236
+ output.writeln(` - ${p.pattern} (freq: ${p.frequency}, reward: ${p.avgReward.toFixed(2)})`);
237
+ }
238
+ }
239
+ return { success: true };
240
+ },
241
+ };
242
+ const historyCommand = {
243
+ name: 'history',
244
+ description: 'Search past completion episodes',
245
+ options: [
246
+ { name: 'query', type: 'string', description: 'Search query', required: true },
247
+ { name: 'limit', type: 'string', description: 'Max results (default 10)' },
248
+ { name: 'json', type: 'boolean', description: 'Output as JSON' },
249
+ ],
250
+ action: async (ctx) => {
251
+ const query = (ctx.flags?.query || '');
252
+ const limit = validateNumber(ctx.flags?.limit, 1, 100, 10);
253
+ if (!query) {
254
+ output.writeln('Usage: autopilot history --query "search terms" [--limit N]');
255
+ return { success: false, message: 'Missing --query' };
256
+ }
257
+ const learning = await tryLoadLearning();
258
+ if (!learning) {
259
+ output.writeln('Learning not available. No history to search.');
260
+ return { success: true };
261
+ }
262
+ const results = await learning.recallSimilarTasks(query, limit);
263
+ if (ctx.flags?.json) {
264
+ output.printJson(results);
265
+ }
266
+ else if (results.length === 0) {
267
+ output.writeln(`No matching episodes for: "${query}"`);
268
+ }
269
+ else {
270
+ output.printJson(results);
271
+ }
272
+ return { success: true };
273
+ },
274
+ };
275
+ const predictCommand = {
276
+ name: 'predict',
277
+ description: 'Predict optimal next action',
278
+ options: [{ name: 'json', type: 'boolean', description: 'Output as JSON' }],
279
+ action: async (ctx) => {
280
+ const state = loadState();
281
+ const learning = await tryLoadLearning();
282
+ if (learning) {
283
+ const prediction = await learning.predictNextAction(state);
284
+ if (ctx.flags?.json) {
285
+ output.printJson(prediction);
286
+ }
287
+ else {
288
+ output.writeln(`Action: ${prediction?.action || 'unknown'}`);
289
+ output.writeln(`Confidence: ${prediction?.confidence || 0}`);
290
+ if (prediction?.alternatives?.length > 0)
291
+ output.writeln(`Alternatives: ${prediction.alternatives.join(', ')}`);
292
+ }
293
+ return { success: true };
294
+ }
295
+ // Heuristic fallback
296
+ const tasks = discoverTasks(state.taskSources);
297
+ const progress = getProgress(tasks);
298
+ if (progress.incomplete.length === 0) {
299
+ output.writeln('All tasks complete. No action needed.');
300
+ return { success: true };
301
+ }
302
+ const next = progress.incomplete[0];
303
+ const result = { action: `Work on: ${next.subject}`, confidence: 0.5, remaining: progress.incomplete.length };
304
+ if (ctx.flags?.json) {
305
+ output.printJson(result);
306
+ }
307
+ else {
308
+ output.writeln(`Action: ${result.action}`);
309
+ output.writeln(`Confidence: ${result.confidence} (heuristic — learning not available)`);
310
+ output.writeln(`Remaining: ${result.remaining} tasks`);
311
+ }
312
+ return { success: true };
313
+ },
314
+ };
315
+ const checkCommand = {
316
+ name: 'check',
317
+ description: 'Run completion check (used by stop hook)',
318
+ options: [{ name: 'json', type: 'boolean', description: 'Output as JSON' }],
319
+ action: async (ctx) => {
320
+ const result = await autopilotCheck();
321
+ if (ctx.flags?.json) {
322
+ output.printJson(result);
323
+ }
324
+ else {
325
+ output.writeln(`${result.allowStop ? 'ALLOW STOP' : 'CONTINUE'}: ${result.reason}`);
326
+ }
327
+ return { success: true };
328
+ },
329
+ };
330
+ // ── Main Command ──────────────────────────────────────────────
331
+ export const autopilotCommand = {
332
+ name: 'autopilot',
333
+ description: 'Persistent swarm completion — keeps agents working until ALL tasks are done',
334
+ aliases: ['ap'],
335
+ subcommands: [statusCommand, enableCommand, disableCommand, configCommand, resetCommand, logCommand, learnCommand, historyCommand, predictCommand, checkCommand],
336
+ examples: [
337
+ { command: 'claude-flow autopilot status', description: 'Show current state and progress' },
338
+ { command: 'claude-flow autopilot enable', description: 'Enable persistent completion' },
339
+ { command: 'claude-flow autopilot config --max-iterations 100 --timeout 180', description: 'Configure limits' },
340
+ { command: 'claude-flow autopilot predict', description: 'Get recommended next action' },
341
+ ],
342
+ action: async () => {
343
+ output.writeln(output.bold('Autopilot — Persistent Swarm Completion'));
344
+ output.writeln(output.dim('Keeps agents working until ALL tasks are done'));
345
+ output.writeln();
346
+ output.printList([
347
+ 'status — Show state, iterations, and task progress',
348
+ 'enable — Enable persistent completion',
349
+ 'disable — Disable re-engagement loop',
350
+ 'config — Configure max iterations, timeout, sources',
351
+ 'reset — Reset iteration counter and timer',
352
+ 'log — View autopilot event log',
353
+ 'learn — Discover success patterns',
354
+ 'history — Search past completion episodes',
355
+ 'predict — Predict optimal next action',
356
+ 'check — Run completion check (stop hook)',
357
+ ]);
358
+ return { success: true };
359
+ },
360
+ };
361
+ export default autopilotCommand;
362
+ //# sourceMappingURL=autopilot.js.map
@@ -30,6 +30,7 @@ export { hiveMindCommand } from './hive-mind.js';
30
30
  export { guidanceCommand } from './guidance.js';
31
31
  export { applianceCommand } from './appliance.js';
32
32
  export { cleanupCommand } from './cleanup.js';
33
+ export { autopilotCommand } from './autopilot.js';
33
34
  export declare function getConfigCommand(): Promise<Command | undefined>;
34
35
  export declare function getMigrateCommand(): Promise<Command | undefined>;
35
36
  export declare function getWorkflowCommand(): Promise<Command | undefined>;
@@ -54,6 +55,7 @@ export declare function getRuvectorCommand(): Promise<Command | undefined>;
54
55
  export declare function getGuidanceCommand(): Promise<Command | undefined>;
55
56
  export declare function getApplianceCommand(): Promise<Command | undefined>;
56
57
  export declare function getCleanupCommand(): Promise<Command | undefined>;
58
+ export declare function getAutopilotCommand(): Promise<Command | undefined>;
57
59
  /**
58
60
  * Core commands loaded synchronously (available immediately)
59
61
  * Advanced commands loaded on-demand for faster startup
@@ -64,6 +64,7 @@ const commandLoaders = {
64
64
  'appliance-advanced': () => import('./appliance-advanced.js'),
65
65
  'transfer-store': () => import('./transfer-store.js'),
66
66
  cleanup: () => import('./cleanup.js'),
67
+ autopilot: () => import('./autopilot.js'),
67
68
  };
68
69
  // Cache for loaded commands
69
70
  const loadedCommands = new Map();
@@ -134,6 +135,7 @@ import { processCommand } from './process.js';
134
135
  import { guidanceCommand } from './guidance.js';
135
136
  import { applianceCommand } from './appliance.js';
136
137
  import { cleanupCommand } from './cleanup.js';
138
+ import { autopilotCommand } from './autopilot.js';
137
139
  // Pre-populate cache with core commands
138
140
  loadedCommands.set('init', initCommand);
139
141
  loadedCommands.set('start', startCommand);
@@ -155,6 +157,7 @@ loadedCommands.set('ruvector', ruvectorCommand);
155
157
  loadedCommands.set('hive-mind', hiveMindCommand);
156
158
  loadedCommands.set('guidance', guidanceCommand);
157
159
  loadedCommands.set('cleanup', cleanupCommand);
160
+ loadedCommands.set('autopilot', autopilotCommand);
158
161
  // =============================================================================
159
162
  // Exports (maintain backwards compatibility)
160
163
  // =============================================================================
@@ -180,6 +183,7 @@ export { hiveMindCommand } from './hive-mind.js';
180
183
  export { guidanceCommand } from './guidance.js';
181
184
  export { applianceCommand } from './appliance.js';
182
185
  export { cleanupCommand } from './cleanup.js';
186
+ export { autopilotCommand } from './autopilot.js';
183
187
  // Lazy-loaded command re-exports (for backwards compatibility, but async-only)
184
188
  export async function getConfigCommand() { return loadCommand('config'); }
185
189
  export async function getMigrateCommand() { return loadCommand('migrate'); }
@@ -205,6 +209,7 @@ export async function getRuvectorCommand() { return loadCommand('ruvector'); }
205
209
  export async function getGuidanceCommand() { return loadCommand('guidance'); }
206
210
  export async function getApplianceCommand() { return loadCommand('appliance'); }
207
211
  export async function getCleanupCommand() { return loadCommand('cleanup'); }
212
+ export async function getAutopilotCommand() { return loadCommand('autopilot'); }
208
213
  /**
209
214
  * Core commands loaded synchronously (available immediately)
210
215
  * Advanced commands loaded on-demand for faster startup
@@ -231,6 +236,7 @@ export const commands = [
231
236
  hiveMindCommand,
232
237
  guidanceCommand,
233
238
  cleanupCommand,
239
+ autopilotCommand,
234
240
  ];
235
241
  /**
236
242
  * Commands organized by category for help display
@@ -256,6 +262,7 @@ export const commandsByCategory = {
256
262
  hiveMindCommand,
257
263
  ruvectorCommand,
258
264
  guidanceCommand,
265
+ autopilotCommand,
259
266
  ],
260
267
  utility: [
261
268
  configCommand,
@@ -99,26 +99,15 @@ export function generateSettings(options) {
99
99
  enabled: options.runtime.enableNeural,
100
100
  },
101
101
  daemon: {
102
- autoStart: true,
102
+ autoStart: false, // Opt-in only — prevents unintended token consumption (#1427, #1330)
103
103
  workers: [
104
104
  'map', // Codebase mapping
105
105
  'audit', // Security auditing (critical priority)
106
106
  'optimize', // Performance optimization (high priority)
107
- 'consolidate', // Memory consolidation
108
- 'testgaps', // Test coverage gaps
109
- 'ultralearn', // Deep knowledge acquisition
110
- 'deepdive', // Deep code analysis
111
- 'document', // Auto-documentation for ADRs
112
- 'refactor', // Refactoring suggestions (DDD alignment)
113
- 'benchmark', // Performance benchmarking
114
107
  ],
115
108
  schedules: {
116
- audit: { interval: '1h', priority: 'critical' },
117
- optimize: { interval: '30m', priority: 'high' },
118
- consolidate: { interval: '2h', priority: 'low' },
119
- document: { interval: '1h', priority: 'normal', triggers: ['adr-update', 'api-change'] },
120
- deepdive: { interval: '4h', priority: 'normal', triggers: ['complex-change'] },
121
- ultralearn: { interval: '1h', priority: 'normal' },
109
+ audit: { interval: '4h', priority: 'critical' },
110
+ optimize: { interval: '2h', priority: 'high' },
122
111
  },
123
112
  },
124
113
  learning: {
@@ -38,6 +38,7 @@ import { agentdbTools } from './mcp-tools/agentdb-tools.js';
38
38
  import { ruvllmWasmTools } from './mcp-tools/ruvllm-tools.js';
39
39
  import { wasmAgentTools } from './mcp-tools/wasm-agent-tools.js';
40
40
  import { guidanceTools } from './mcp-tools/guidance-tools.js';
41
+ import { autopilotTools } from './mcp-tools/autopilot-tools.js';
41
42
  /**
42
43
  * MCP Tool Registry
43
44
  * Maps tool names to their handler functions
@@ -82,6 +83,8 @@ registerTools([
82
83
  ...wasmAgentTools,
83
84
  // Guidance & discovery tools
84
85
  ...guidanceTools,
86
+ // Autopilot persistent completion tools
87
+ ...autopilotTools,
85
88
  ]);
86
89
  /**
87
90
  * MCP Client Error
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Autopilot MCP Tools
3
+ *
4
+ * 10 MCP tools for persistent swarm completion management.
5
+ * Allows programmatic control of the autopilot loop via MCP.
6
+ *
7
+ * ADR-072: Autopilot Integration
8
+ * @module @claude-flow/cli/mcp-tools/autopilot
9
+ */
10
+ import type { MCPTool } from './types.js';
11
+ export declare const autopilotTools: MCPTool[];
12
+ //# sourceMappingURL=autopilot-tools.d.ts.map
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Autopilot MCP Tools
3
+ *
4
+ * 10 MCP tools for persistent swarm completion management.
5
+ * Allows programmatic control of the autopilot loop via MCP.
6
+ *
7
+ * ADR-072: Autopilot Integration
8
+ * @module @claude-flow/cli/mcp-tools/autopilot
9
+ */
10
+ import { loadState, saveState, appendLog, loadLog, discoverTasks, isTerminal, tryLoadLearning, validateNumber, validateTaskSources, VALID_TASK_SOURCES, } from '../autopilot-state.js';
11
+ function ok(data) {
12
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
13
+ }
14
+ // ── MCP Tool Definitions ──────────────────────────────────────
15
+ const autopilotStatus = {
16
+ name: 'autopilot_status',
17
+ description: 'Get autopilot state including enabled status, iteration count, task progress, and learning metrics.',
18
+ category: 'autopilot',
19
+ inputSchema: { type: 'object', properties: {} },
20
+ handler: async () => {
21
+ const state = loadState();
22
+ const tasks = discoverTasks(state.taskSources);
23
+ const completed = tasks.filter(t => isTerminal(t.status)).length;
24
+ return ok({
25
+ enabled: state.enabled,
26
+ sessionId: state.sessionId,
27
+ iterations: state.iterations,
28
+ maxIterations: state.maxIterations,
29
+ timeoutMinutes: state.timeoutMinutes,
30
+ elapsedMs: state.enabled ? Date.now() - state.startTime : 0,
31
+ tasks: { completed, total: tasks.length, percent: tasks.length === 0 ? 100 : Math.round((completed / tasks.length) * 100) },
32
+ taskSources: state.taskSources,
33
+ });
34
+ },
35
+ };
36
+ const autopilotEnable = {
37
+ name: 'autopilot_enable',
38
+ description: 'Enable autopilot persistent completion. Agents will be re-engaged when tasks remain incomplete.',
39
+ category: 'autopilot',
40
+ inputSchema: { type: 'object', properties: {} },
41
+ handler: async () => {
42
+ const state = loadState();
43
+ state.enabled = true;
44
+ state.startTime = Date.now();
45
+ state.iterations = 0;
46
+ saveState(state);
47
+ appendLog({ ts: Date.now(), event: 'enabled', sessionId: state.sessionId });
48
+ return ok({ enabled: true, maxIterations: state.maxIterations, timeoutMinutes: state.timeoutMinutes });
49
+ },
50
+ };
51
+ const autopilotDisable = {
52
+ name: 'autopilot_disable',
53
+ description: 'Disable autopilot. Agents will be allowed to stop even if tasks remain.',
54
+ category: 'autopilot',
55
+ inputSchema: { type: 'object', properties: {} },
56
+ handler: async () => {
57
+ const state = loadState();
58
+ state.enabled = false;
59
+ saveState(state);
60
+ appendLog({ ts: Date.now(), event: 'disabled', iterations: state.iterations });
61
+ return ok({ enabled: false });
62
+ },
63
+ };
64
+ const autopilotConfig = {
65
+ name: 'autopilot_config',
66
+ description: 'Configure autopilot limits: max iterations (1-1000), timeout in minutes (1-1440), and task sources.',
67
+ category: 'autopilot',
68
+ inputSchema: {
69
+ type: 'object',
70
+ properties: {
71
+ maxIterations: { type: 'number', description: 'Max re-engagement iterations (1-1000)' },
72
+ timeoutMinutes: { type: 'number', description: 'Timeout in minutes (1-1440)' },
73
+ taskSources: { type: 'array', items: { type: 'string' }, description: `Task sources: ${[...VALID_TASK_SOURCES].join(', ')}` },
74
+ },
75
+ },
76
+ handler: async (params) => {
77
+ const state = loadState();
78
+ if (params.maxIterations !== undefined) {
79
+ state.maxIterations = validateNumber(params.maxIterations, 1, 1000, state.maxIterations);
80
+ }
81
+ if (params.timeoutMinutes !== undefined) {
82
+ state.timeoutMinutes = validateNumber(params.timeoutMinutes, 1, 1440, state.timeoutMinutes);
83
+ }
84
+ if (params.taskSources !== undefined) {
85
+ state.taskSources = validateTaskSources(params.taskSources);
86
+ }
87
+ saveState(state);
88
+ return ok({ maxIterations: state.maxIterations, timeoutMinutes: state.timeoutMinutes, taskSources: state.taskSources });
89
+ },
90
+ };
91
+ const autopilotReset = {
92
+ name: 'autopilot_reset',
93
+ description: 'Reset autopilot iteration counter and restart the timer.',
94
+ category: 'autopilot',
95
+ inputSchema: { type: 'object', properties: {} },
96
+ handler: async () => {
97
+ const state = loadState();
98
+ state.iterations = 0;
99
+ state.startTime = Date.now();
100
+ state.history = [];
101
+ state.lastCheck = null;
102
+ saveState(state);
103
+ appendLog({ ts: Date.now(), event: 'reset' });
104
+ return ok({ reset: true, iterations: 0 });
105
+ },
106
+ };
107
+ const autopilotLog = {
108
+ name: 'autopilot_log',
109
+ description: 'Retrieve the autopilot event log. Shows enable/disable events, re-engagements, completions.',
110
+ category: 'autopilot',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {
114
+ last: { type: 'number', description: 'Return only the last N entries' },
115
+ },
116
+ },
117
+ handler: async (params) => {
118
+ const log = loadLog();
119
+ const last = validateNumber(params.last, 1, 10000, 0);
120
+ return ok(last > 0 ? log.slice(-last) : log);
121
+ },
122
+ };
123
+ const autopilotProgress = {
124
+ name: 'autopilot_progress',
125
+ description: 'Detailed task progress broken down by source (team-tasks, swarm-tasks, file-checklist).',
126
+ category: 'autopilot',
127
+ inputSchema: { type: 'object', properties: {} },
128
+ handler: async () => {
129
+ const state = loadState();
130
+ const tasks = discoverTasks(state.taskSources);
131
+ const bySource = {};
132
+ for (const t of tasks) {
133
+ if (!bySource[t.source])
134
+ bySource[t.source] = { completed: 0, total: 0, tasks: [] };
135
+ bySource[t.source].total++;
136
+ if (isTerminal(t.status)) {
137
+ bySource[t.source].completed++;
138
+ }
139
+ bySource[t.source].tasks.push(t);
140
+ }
141
+ const completed = tasks.filter(t => isTerminal(t.status)).length;
142
+ return ok({
143
+ overall: { completed, total: tasks.length, percent: tasks.length === 0 ? 100 : Math.round((completed / tasks.length) * 100) },
144
+ bySource,
145
+ });
146
+ },
147
+ };
148
+ const autopilotLearn = {
149
+ name: 'autopilot_learn',
150
+ description: 'Discover success patterns from past task completions. Requires AgentDB for full functionality.',
151
+ category: 'autopilot',
152
+ inputSchema: { type: 'object', properties: {} },
153
+ handler: async () => {
154
+ const learning = await tryLoadLearning();
155
+ if (learning) {
156
+ const [metrics, patterns] = await Promise.all([
157
+ learning.getMetrics(),
158
+ learning.discoverSuccessPatterns(),
159
+ ]);
160
+ return ok({ metrics, patterns });
161
+ }
162
+ return ok({ available: false, reason: 'AgentDB/AutopilotLearning not initialized', patterns: [] });
163
+ },
164
+ };
165
+ const autopilotHistory = {
166
+ name: 'autopilot_history',
167
+ description: 'Search past completion episodes by keyword. Requires AgentDB.',
168
+ category: 'autopilot',
169
+ inputSchema: {
170
+ type: 'object',
171
+ properties: {
172
+ query: { type: 'string', description: 'Search query' },
173
+ limit: { type: 'number', description: 'Max results (default 10)' },
174
+ },
175
+ required: ['query'],
176
+ },
177
+ handler: async (params) => {
178
+ const query = String(params.query || '');
179
+ const limit = validateNumber(params.limit, 1, 100, 10);
180
+ const learning = await tryLoadLearning();
181
+ if (learning) {
182
+ const results = await learning.recallSimilarTasks(query, limit);
183
+ return ok({ query, results });
184
+ }
185
+ return ok({ query, results: [], available: false });
186
+ },
187
+ };
188
+ const autopilotPredict = {
189
+ name: 'autopilot_predict',
190
+ description: 'Predict the optimal next action based on current state and learned patterns.',
191
+ category: 'autopilot',
192
+ inputSchema: { type: 'object', properties: {} },
193
+ handler: async () => {
194
+ const state = loadState();
195
+ const learning = await tryLoadLearning();
196
+ if (learning) {
197
+ const prediction = await learning.predictNextAction(state);
198
+ return ok(prediction);
199
+ }
200
+ // Heuristic fallback
201
+ const tasks = discoverTasks(state.taskSources);
202
+ const incomplete = tasks.filter(t => !isTerminal(t.status));
203
+ if (incomplete.length === 0) {
204
+ return ok({ action: 'none', confidence: 1.0, reason: 'All tasks complete' });
205
+ }
206
+ return ok({
207
+ action: `Work on: ${incomplete[0].subject}`,
208
+ confidence: 0.5,
209
+ reason: 'Heuristic (learning not available)',
210
+ remaining: incomplete.length,
211
+ });
212
+ },
213
+ };
214
+ // ── Export ─────────────────────────────────────────────────────
215
+ export const autopilotTools = [
216
+ autopilotStatus,
217
+ autopilotEnable,
218
+ autopilotDisable,
219
+ autopilotConfig,
220
+ autopilotReset,
221
+ autopilotLog,
222
+ autopilotProgress,
223
+ autopilotLearn,
224
+ autopilotHistory,
225
+ autopilotPredict,
226
+ ];
227
+ //# sourceMappingURL=autopilot-tools.js.map
@@ -1376,13 +1376,13 @@ export const hooksSessionStart = {
1376
1376
  properties: {
1377
1377
  sessionId: { type: 'string', description: 'Optional session ID' },
1378
1378
  restoreLatest: { type: 'boolean', description: 'Restore latest session state' },
1379
- startDaemon: { type: 'boolean', description: 'Auto-start worker daemon (default: true)' },
1379
+ startDaemon: { type: 'boolean', description: 'Start worker daemon (default: false — opt-in to prevent unintended token usage)' },
1380
1380
  },
1381
1381
  },
1382
1382
  handler: async (params) => {
1383
1383
  const sessionId = params.sessionId || `session-${Date.now()}`;
1384
1384
  const restoreLatest = params.restoreLatest;
1385
- const shouldStartDaemon = params.startDaemon !== false;
1385
+ const shouldStartDaemon = params.startDaemon === true;
1386
1386
  // Auto-start daemon if enabled
1387
1387
  let daemonStatus = { started: false };
1388
1388
  if (shouldStartDaemon) {
@@ -23,4 +23,5 @@ export { claimsTools } from './claims-tools.js';
23
23
  export { wasmAgentTools } from './wasm-agent-tools.js';
24
24
  export { ruvllmWasmTools } from './ruvllm-tools.js';
25
25
  export { guidanceTools } from './guidance-tools.js';
26
+ export { autopilotTools } from './autopilot-tools.js';
26
27
  //# sourceMappingURL=index.d.ts.map
@@ -22,4 +22,5 @@ export { claimsTools } from './claims-tools.js';
22
22
  export { wasmAgentTools } from './wasm-agent-tools.js';
23
23
  export { ruvllmWasmTools } from './ruvllm-tools.js';
24
24
  export { guidanceTools } from './guidance-tools.js';
25
+ export { autopilotTools } from './autopilot-tools.js';
25
26
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.5.44",
3
+ "version": "3.5.46",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -94,7 +94,7 @@
94
94
  "@claude-flow/codex": "^3.0.0-alpha.8",
95
95
  "@claude-flow/embeddings": "^3.0.0-alpha.12",
96
96
  "@claude-flow/guidance": "^3.0.0-alpha.1",
97
- "@claude-flow/memory": "^3.0.0-alpha.11",
97
+ "@claude-flow/memory": "^3.0.0-alpha.12",
98
98
  "@claude-flow/plugin-gastown-bridge": "^0.1.3",
99
99
  "agentic-flow": "^3.0.0-alpha.1",
100
100
  "@ruvector/attention": "^0.1.4",