clawaid 1.0.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.
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.executeActions = executeActions;
37
+ exports.formatExecuteResults = formatExecuteResults;
38
+ const child_process_1 = require("child_process");
39
+ const util_1 = require("util");
40
+ const fs = __importStar(require("fs"));
41
+ const os = __importStar(require("os"));
42
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
43
+ async function runCommand(cmd, timeout = 30000) {
44
+ try {
45
+ const { stdout, stderr } = await execAsync(cmd, {
46
+ timeout,
47
+ env: {
48
+ ...process.env,
49
+ PATH: '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:' + (process.env.PATH || ''),
50
+ HOME: os.homedir(),
51
+ }
52
+ });
53
+ const output = (stdout + (stderr ? '\n' + stderr : '')).trim();
54
+ return { success: true, output: output || '[command completed with no output]' };
55
+ }
56
+ catch (err) {
57
+ if (err && typeof err === 'object' && 'stdout' in err && 'stderr' in err) {
58
+ const e = err;
59
+ const out = (e.stdout || '').trim();
60
+ const errOut = (e.stderr || '').trim();
61
+ const combined = [out, errOut].filter(Boolean).join('\n');
62
+ // Some commands return non-zero but still succeed (e.g., kill when process doesn't exist)
63
+ return { success: false, output: combined || e.message, error: e.message };
64
+ }
65
+ return { success: false, output: '', error: err.message };
66
+ }
67
+ }
68
+ async function backupFile(filePath) {
69
+ const expandedPath = filePath.replace('~', os.homedir());
70
+ const backupPath = expandedPath + '.bak.' + Date.now();
71
+ if (fs.existsSync(expandedPath)) {
72
+ fs.copyFileSync(expandedPath, backupPath);
73
+ return backupPath;
74
+ }
75
+ return '';
76
+ }
77
+ async function executeActions(actions, onProgress, dryRun = false) {
78
+ const results = [];
79
+ const progress = (msg, result) => {
80
+ if (onProgress)
81
+ onProgress(msg, result);
82
+ };
83
+ if (dryRun) {
84
+ progress('āš ļø DRY-RUN mode — showing what would be executed:');
85
+ for (let i = 0; i < actions.length; i++) {
86
+ const action = actions[i];
87
+ progress(` Step ${i + 1}: ${action.description}`);
88
+ progress(` $ ${action.command}`);
89
+ progress(` Risk: ${action.risk} | Type: ${action.type}`);
90
+ results.push({
91
+ action,
92
+ success: true,
93
+ output: '[dry-run: not executed]',
94
+ });
95
+ }
96
+ return { results, allSucceeded: true, summary: `Dry run: ${actions.length} actions shown (not executed)` };
97
+ }
98
+ for (let i = 0; i < actions.length; i++) {
99
+ const action = actions[i];
100
+ progress(`Step ${i + 1}/${actions.length}: ${action.description}`);
101
+ let backupPath;
102
+ // Backup file if needed
103
+ if (action.type === 'file_edit' && action.backup) {
104
+ try {
105
+ progress(` → Creating backup...`);
106
+ const backupCmd = action.backup.replace('~', os.homedir());
107
+ // Extract file path from backup command or action command
108
+ const fileMatch = action.command.match(/['"]?([~\/][^'"]+)['"]?/);
109
+ if (fileMatch) {
110
+ backupPath = await backupFile(fileMatch[1]);
111
+ if (backupPath) {
112
+ progress(` → Backed up to: ${backupPath}`);
113
+ }
114
+ }
115
+ }
116
+ catch (e) {
117
+ progress(` → Backup warning: ${e.message}`);
118
+ }
119
+ }
120
+ // Execute the command
121
+ progress(` → Running: ${action.command}`);
122
+ const { success, output, error } = await runCommand(action.command);
123
+ const result = {
124
+ action,
125
+ success,
126
+ output,
127
+ error,
128
+ backupPath,
129
+ };
130
+ results.push(result);
131
+ progress(` → ${success ? 'āœ“ Success' : 'āœ— Failed'}: ${output.slice(0, 200)}`, result);
132
+ // If a high-risk action fails, stop
133
+ if (!success && action.risk === 'high') {
134
+ progress(`High-risk action failed, stopping execution for safety.`);
135
+ break;
136
+ }
137
+ // Small delay between actions
138
+ await new Promise(resolve => setTimeout(resolve, 500));
139
+ }
140
+ const allSucceeded = results.length > 0 && results.every(r => r.success);
141
+ const successCount = results.filter(r => r.success).length;
142
+ const summary = `Executed ${results.length} actions: ${successCount} succeeded, ${results.length - successCount} failed`;
143
+ return { results, allSucceeded, summary };
144
+ }
145
+ function formatExecuteResults(results) {
146
+ return results.map((r, i) => {
147
+ const status = r.success ? 'āœ“' : 'āœ—';
148
+ return `${status} Step ${i + 1}: ${r.action.description}
149
+ Command: ${r.action.command}
150
+ Output: ${r.output.slice(0, 300)}${r.error ? `\n Error: ${r.error}` : ''}${r.backupPath ? `\n Backup: ${r.backupPath}` : ''}`;
151
+ }).join('\n\n');
152
+ }
153
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const http = __importStar(require("http"));
38
+ const server_1 = require("./server");
39
+ // Find a free port
40
+ async function findFreePort(start = 7357) {
41
+ return new Promise((resolve) => {
42
+ const server = http.createServer();
43
+ server.listen(start, '127.0.0.1', () => {
44
+ const port = server.address().port;
45
+ server.close(() => resolve(port));
46
+ });
47
+ server.on('error', () => {
48
+ resolve(findFreePort(start + 1));
49
+ });
50
+ });
51
+ }
52
+ async function openBrowser(url) {
53
+ const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
54
+ const { promisify } = await Promise.resolve().then(() => __importStar(require('util')));
55
+ const execAsync = promisify(exec);
56
+ const platform = process.platform;
57
+ let cmd;
58
+ if (platform === 'darwin') {
59
+ cmd = `open "${url}"`;
60
+ }
61
+ else if (platform === 'win32') {
62
+ cmd = `start "" "${url}"`;
63
+ }
64
+ else {
65
+ cmd = `xdg-open "${url}"`;
66
+ }
67
+ try {
68
+ await execAsync(cmd);
69
+ }
70
+ catch {
71
+ console.log(`Please open your browser to: ${url}`);
72
+ }
73
+ }
74
+ async function main() {
75
+ const dryRun = process.argv.includes('--dry-run');
76
+ const noOpen = process.argv.includes('--no-open');
77
+ const mockIdx = process.argv.indexOf('--mock');
78
+ const mockScenario = mockIdx !== -1 ? process.argv[mockIdx + 1] : undefined;
79
+ const portIdx = process.argv.indexOf('--port');
80
+ const requestedPort = portIdx !== -1 ? parseInt(process.argv[portIdx + 1], 10) : undefined;
81
+ if (mockScenario) {
82
+ console.log(`🧪 MOCK mode: using scenario "${mockScenario}"\n`);
83
+ global.__clawaid_mock = mockScenario;
84
+ }
85
+ console.log('\n🩺 ClawAid\n');
86
+ if (dryRun)
87
+ console.log('āš ļø DRY-RUN mode: fixes will NOT be executed\n');
88
+ console.log('Finding available port...');
89
+ // Export dry-run flag so server can access it
90
+ global.__clawaid_dry_run = dryRun;
91
+ const port = requestedPort || await findFreePort(7357);
92
+ const url = `http://127.0.0.1:${port}`;
93
+ console.log('Starting diagnostic server...');
94
+ await (0, server_1.createServer)(port);
95
+ console.log(`\nāœ“ Server running at ${url}`);
96
+ if (!noOpen) {
97
+ console.log('Opening browser...\n');
98
+ await new Promise(resolve => setTimeout(resolve, 300));
99
+ await openBrowser(url);
100
+ }
101
+ else {
102
+ console.log('Browser auto-open disabled (--no-open)\n');
103
+ }
104
+ console.log('ClawAid is running. Press Ctrl+C to stop.\n');
105
+ // Keep process alive
106
+ process.on('SIGINT', () => {
107
+ console.log('\nShutting down ClawAid...');
108
+ process.exit(0);
109
+ });
110
+ }
111
+ main().catch((err) => {
112
+ console.error('Failed to start ClawAid:', err);
113
+ process.exit(1);
114
+ });
115
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/loop.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { ObservationResult } from './observe';
2
+ import { DiagnosisResult } from './diagnose';
3
+ export type LoopState = 'idle' | 'observing' | 'diagnosing' | 'showing_options' | 'auto_executing' | 'executing' | 'verifying' | 'fixed' | 'not_fixed' | 'healthy' | 'needs_api_key' | 'error';
4
+ export interface LoopEvent {
5
+ type: 'state_change' | 'progress' | 'diagnosis' | 'action_result' | 'verify_result' | 'request_input' | 'complete' | 'error';
6
+ data: unknown;
7
+ }
8
+ export type EventCallback = (event: LoopEvent) => void;
9
+ export interface LoopContext {
10
+ apiKey: string;
11
+ originalObservation?: ObservationResult;
12
+ originalObservationText?: string;
13
+ currentDiagnosis?: DiagnosisResult;
14
+ attemptHistory: string[];
15
+ roundNumber: number;
16
+ }
17
+ export declare class DoctorLoop {
18
+ private callback;
19
+ private context;
20
+ private state;
21
+ private stopped;
22
+ constructor(callback: EventCallback, apiKey?: string);
23
+ setApiKey(key: string): void;
24
+ stop(): void;
25
+ private emit;
26
+ private setState;
27
+ private progress;
28
+ start(): Promise<void>;
29
+ provideInput(field: string, value: string): Promise<void>;
30
+ private runMainLoop;
31
+ /**
32
+ * Called when user clicks "Fix" on an option card.
33
+ * optionId: "A", "B", "C" — if omitted, use the recommended option.
34
+ */
35
+ startFix(optionId?: string): Promise<void>;
36
+ /**
37
+ * Continue with round 2 or 3 after a failed fix attempt.
38
+ */
39
+ private continueAfterFailure;
40
+ private executeOption;
41
+ private buildDiagnosticReport;
42
+ }
43
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmD,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAY,eAAe,EAA+B,MAAM,YAAY,CAAC;AAIpF,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,gBAAgB,GAChB,WAAW,GACX,WAAW,GACX,OAAO,GACP,WAAW,GACX,SAAS,GACT,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,WAAW,SAAS;IACxB,IAAI,EACA,cAAc,GACd,UAAU,GACV,WAAW,GACX,eAAe,GACf,eAAe,GACf,eAAe,GACf,UAAU,GACV,OAAO,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,iBAAiB,CAAC;IACxC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAS;gBAEZ,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAK;IAShD,SAAS,CAAC,GAAG,EAAE,MAAM;IAIrB,IAAI;IAIJ,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,QAAQ;IAIV,KAAK;IAwBL,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;YAQjC,WAAW;IAiEzB;;;OAGG;IACG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM;IAkChC;;OAEG;YACW,oBAAoB;YA4FpB,aAAa;IAwE3B,OAAO,CAAC,qBAAqB;CAqB9B"}
package/dist/loop.js ADDED
@@ -0,0 +1,316 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DoctorLoop = void 0;
4
+ const observe_1 = require("./observe");
5
+ const diagnose_1 = require("./diagnose");
6
+ const execute_1 = require("./execute");
7
+ const verify_1 = require("./verify");
8
+ class DoctorLoop {
9
+ constructor(callback, apiKey = '') {
10
+ this.state = 'idle';
11
+ this.stopped = false;
12
+ this.callback = callback;
13
+ this.context = {
14
+ apiKey,
15
+ attemptHistory: [],
16
+ roundNumber: 0,
17
+ };
18
+ }
19
+ setApiKey(key) {
20
+ this.context.apiKey = key;
21
+ }
22
+ stop() {
23
+ this.stopped = true;
24
+ }
25
+ emit(event) {
26
+ this.callback(event);
27
+ }
28
+ setState(state) {
29
+ this.state = state;
30
+ this.emit({ type: 'state_change', data: { state } });
31
+ }
32
+ progress(msg) {
33
+ this.emit({ type: 'progress', data: { message: msg } });
34
+ }
35
+ async start() {
36
+ // Check for API key first
37
+ const autoKey = (0, diagnose_1.extractApiKey)();
38
+ if (autoKey) {
39
+ this.context.apiKey = autoKey;
40
+ this.progress('Found OpenRouter API key in OpenClaw config āœ“');
41
+ }
42
+ else if (!this.context.apiKey) {
43
+ this.setState('needs_api_key');
44
+ this.emit({
45
+ type: 'request_input',
46
+ data: {
47
+ field: 'apiKey',
48
+ label: 'OpenRouter API Key',
49
+ placeholder: 'sk-or-...',
50
+ hint: 'šŸ”’ Local only. Not stored. Only sent to OpenRouter for AI diagnosis.',
51
+ instructions: 'ClawAid needs an OpenRouter API key to call Claude for diagnosis. Your existing OpenClaw config does not have an OpenRouter key.',
52
+ }
53
+ });
54
+ return; // Wait for user to provide key via provideInput()
55
+ }
56
+ await this.runMainLoop();
57
+ }
58
+ async provideInput(field, value) {
59
+ if (field === 'apiKey') {
60
+ this.context.apiKey = value;
61
+ this.progress('API key received, starting diagnosis...');
62
+ await this.runMainLoop();
63
+ }
64
+ }
65
+ async runMainLoop() {
66
+ // ── Round 1: Observe + Diagnose ──────────────────────────────────────────
67
+ this.setState('observing');
68
+ this.progress('šŸ” Gathering system information...');
69
+ const mockScenario = global.__clawaid_mock;
70
+ const observation = mockScenario
71
+ ? (0, observe_1.loadMockObservation)(mockScenario)
72
+ : await (0, observe_1.observe)((msg) => this.progress(msg));
73
+ this.context.originalObservation = observation;
74
+ this.context.originalObservationText = (0, observe_1.formatObservation)(observation);
75
+ this.progress('āœ“ System scan complete');
76
+ this.progress('šŸ“” Sending data to AI for analysis...');
77
+ this.setState('diagnosing');
78
+ this.progress('šŸ¤” AI is analyzing your system...');
79
+ try {
80
+ const diagnosis = await (0, diagnose_1.diagnose)({
81
+ apiKey: this.context.apiKey,
82
+ observationData: this.context.originalObservationText,
83
+ });
84
+ this.context.currentDiagnosis = diagnosis;
85
+ // Healthy?
86
+ if (diagnosis.healthy && diagnosis.options.length === 0) {
87
+ this.progress('āœ… ' + (diagnosis.diagnosis || 'OpenClaw is running normally. No issues detected.'));
88
+ this.setState('healthy');
89
+ this.emit({
90
+ type: 'complete',
91
+ data: { fixed: false, healthy: true, explanation: diagnosis.diagnosis, warnings: diagnosis.warnings || [], reasoning: diagnosis.reasoning || [] },
92
+ });
93
+ return;
94
+ }
95
+ this.emit({
96
+ type: 'diagnosis',
97
+ data: {
98
+ diagnosis: diagnosis.diagnosis,
99
+ confidence: diagnosis.confidence,
100
+ rootCause: diagnosis.rootCause,
101
+ reasoning: diagnosis.reasoning || [],
102
+ warnings: diagnosis.warnings || [],
103
+ options: diagnosis.options,
104
+ alternativeHypotheses: diagnosis.alternativeHypotheses,
105
+ round: 1,
106
+ }
107
+ });
108
+ // Always show options to user and wait for their choice
109
+ this.setState('showing_options');
110
+ return; // Resumes via startFix(optionId)
111
+ }
112
+ catch (err) {
113
+ this.progress(`āŒ AI analysis failed: ${err.message}`);
114
+ this.setState('error');
115
+ this.emit({ type: 'error', data: { message: err.message } });
116
+ return;
117
+ }
118
+ // Auto-fix failed → round 2 with updated observation
119
+ await this.continueAfterFailure(2);
120
+ }
121
+ /**
122
+ * Called when user clicks "Fix" on an option card.
123
+ * optionId: "A", "B", "C" — if omitted, use the recommended option.
124
+ */
125
+ async startFix(optionId) {
126
+ if (!this.context.currentDiagnosis) {
127
+ this.progress('No diagnosis available. Please restart.');
128
+ return;
129
+ }
130
+ const options = this.context.currentDiagnosis.options;
131
+ let chosen;
132
+ if (optionId) {
133
+ chosen = options.find(o => o.id === optionId);
134
+ }
135
+ if (!chosen) {
136
+ chosen = options.find(o => o.recommended) || options[0];
137
+ }
138
+ if (!chosen) {
139
+ this.progress('āš ļø No option found to execute.');
140
+ return;
141
+ }
142
+ this.context.roundNumber = 1;
143
+ const fixed = await this.executeOption(chosen);
144
+ if (fixed) {
145
+ this.setState('fixed');
146
+ this.emit({ type: 'complete', data: { fixed: true, explanation: 'OpenClaw has been successfully repaired!' } });
147
+ return;
148
+ }
149
+ // Not fixed after round 1 user choice → round 2
150
+ await this.continueAfterFailure(2);
151
+ }
152
+ /**
153
+ * Continue with round 2 or 3 after a failed fix attempt.
154
+ */
155
+ async continueAfterFailure(round) {
156
+ if (this.stopped)
157
+ return;
158
+ // Round 3: give up
159
+ if (round > 3) {
160
+ this.setState('not_fixed');
161
+ this.progress('\nšŸ˜” After 3 repair rounds, the issue persists.');
162
+ this.emit({
163
+ type: 'complete',
164
+ data: {
165
+ fixed: false,
166
+ explanation: 'The issue could not be automatically resolved after 3 attempts.',
167
+ diagnosticReport: this.buildDiagnosticReport(),
168
+ }
169
+ });
170
+ return;
171
+ }
172
+ // Re-observe
173
+ this.setState('observing');
174
+ this.progress(`\nšŸ”„ Round ${round}: Re-scanning system...`);
175
+ const mockScenario = global.__clawaid_mock;
176
+ let currentObsText;
177
+ try {
178
+ const currentObs = mockScenario
179
+ ? (0, observe_1.loadMockObservation)(mockScenario)
180
+ : await (0, observe_1.observe)((msg) => this.progress(msg));
181
+ currentObsText = (0, observe_1.formatObservation)(currentObs);
182
+ }
183
+ catch (err) {
184
+ this.progress(`Observation error: ${err.message}`);
185
+ currentObsText = this.context.originalObservationText || '';
186
+ }
187
+ // Re-diagnose
188
+ this.setState('diagnosing');
189
+ this.progress('šŸ¤” AI is re-analyzing with attempt history...');
190
+ try {
191
+ const newDiagnosis = await (0, diagnose_1.diagnose)({
192
+ apiKey: this.context.apiKey,
193
+ observationData: currentObsText,
194
+ previousAttempts: this.context.attemptHistory,
195
+ round,
196
+ });
197
+ this.context.currentDiagnosis = newDiagnosis;
198
+ if (newDiagnosis.healthy && newDiagnosis.options.length === 0) {
199
+ this.progress('āœ… ' + (newDiagnosis.diagnosis || 'OpenClaw is running normally. No issues detected.'));
200
+ this.setState('healthy');
201
+ this.emit({ type: 'complete', data: { fixed: false, healthy: true, explanation: newDiagnosis.diagnosis, warnings: newDiagnosis.warnings || [], reasoning: newDiagnosis.reasoning || [] } });
202
+ return;
203
+ }
204
+ this.emit({
205
+ type: 'diagnosis',
206
+ data: {
207
+ diagnosis: newDiagnosis.diagnosis,
208
+ confidence: newDiagnosis.confidence,
209
+ rootCause: newDiagnosis.rootCause,
210
+ reasoning: newDiagnosis.reasoning || [],
211
+ options: newDiagnosis.options,
212
+ alternativeHypotheses: newDiagnosis.alternativeHypotheses,
213
+ round,
214
+ }
215
+ });
216
+ // Round 3 = give up, just show report
217
+ if (round === 3) {
218
+ this.setState('not_fixed');
219
+ this.emit({
220
+ type: 'complete',
221
+ data: {
222
+ fixed: false,
223
+ explanation: 'The issue could not be automatically resolved after 3 attempts.',
224
+ diagnosticReport: this.buildDiagnosticReport(),
225
+ }
226
+ });
227
+ return;
228
+ }
229
+ // Always show options to user and wait for their choice
230
+ this.setState('showing_options');
231
+ this.context.roundNumber = round;
232
+ }
233
+ catch (err) {
234
+ this.progress(`āŒ AI analysis failed: ${err.message}`);
235
+ this.setState('error');
236
+ this.emit({ type: 'error', data: { message: err.message } });
237
+ }
238
+ }
239
+ async executeOption(option) {
240
+ if (option.steps.length === 0) {
241
+ this.progress('āš ļø No steps in this option.');
242
+ return false;
243
+ }
244
+ const dryRun = Boolean(global.__clawaid_dry_run);
245
+ this.setState('auto_executing');
246
+ this.progress(`\nšŸ”§ ${dryRun ? '[DRY-RUN] ' : ''}Executing: ${option.title} (${option.steps.length} step${option.steps.length > 1 ? 's' : ''})...`);
247
+ const executeResult = await (0, execute_1.executeActions)(option.steps, (msg, result) => {
248
+ this.progress(msg);
249
+ if (result) {
250
+ this.emit({ type: 'action_result', data: result });
251
+ }
252
+ }, dryRun);
253
+ // Record this attempt
254
+ const attemptSummary = `
255
+ ### Attempt ${this.context.roundNumber + 1} — Option ${option.id}: ${option.title}
256
+ Diagnosis: ${this.context.currentDiagnosis?.diagnosis || ''}
257
+ Root cause: ${this.context.currentDiagnosis?.rootCause || ''}
258
+ Steps taken:
259
+ ${(0, execute_1.formatExecuteResults)(executeResult.results)}
260
+ Result: ${executeResult.summary}
261
+ `.trim();
262
+ this.context.attemptHistory.push(attemptSummary);
263
+ this.context.roundNumber++;
264
+ // In dry-run mode, skip verification
265
+ if (dryRun) {
266
+ this.progress('\nāš ļø DRY-RUN: Skipping verification (nothing was executed).');
267
+ this.emit({ type: 'verify_result', data: { fixed: false, explanation: 'Dry-run mode — no changes made.' } });
268
+ return false;
269
+ }
270
+ // Verify
271
+ this.setState('verifying');
272
+ this.progress('\nšŸ” Verifying repair...');
273
+ try {
274
+ const verifyResult = await (0, verify_1.verify)(this.context.apiKey, this.context.originalObservationText || '', executeResult.results.map(r => `${r.action.command}: ${r.output}`), (msg) => this.progress(msg));
275
+ this.emit({
276
+ type: 'verify_result',
277
+ data: { fixed: verifyResult.fixed, explanation: verifyResult.explanation },
278
+ });
279
+ if (verifyResult.fixed) {
280
+ this.progress(`\nāœ… ${verifyResult.explanation}`);
281
+ return true;
282
+ }
283
+ else {
284
+ this.progress(`\nāš ļø Not yet fixed: ${verifyResult.explanation}`);
285
+ return false;
286
+ }
287
+ }
288
+ catch (err) {
289
+ this.progress(`Verification error: ${err.message}`);
290
+ return false;
291
+ }
292
+ }
293
+ buildDiagnosticReport() {
294
+ return `
295
+ # ClawAid - Diagnostic Report
296
+ Generated: ${new Date().toISOString()}
297
+
298
+ ## System State (Initial)
299
+ ${this.context.originalObservationText || 'Not captured'}
300
+
301
+ ## Repair Attempts (${this.context.attemptHistory.length} total)
302
+ ${this.context.attemptHistory.join('\n\n---\n\n')}
303
+
304
+ ## Summary
305
+ After ${this.context.roundNumber} repair round(s), the issue was not automatically resolved.
306
+ Please review the diagnostic data above and consult the OpenClaw community for assistance.
307
+
308
+ ## Resources
309
+ - OpenClaw Discord: https://discord.gg/openclaw
310
+ - Run manually: openclaw doctor
311
+ - View logs: openclaw logs --follow
312
+ `.trim();
313
+ }
314
+ }
315
+ exports.DoctorLoop = DoctorLoop;
316
+ //# sourceMappingURL=loop.js.map