myshell-tools 1.0.0 → 2.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.
- package/CHANGELOG.md +44 -69
- package/LICENSE +21 -21
- package/README.md +178 -318
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +130 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cost.d.ts +36 -0
- package/dist/commands/cost.js +103 -0
- package/dist/commands/cost.js.map +1 -0
- package/dist/commands/doctor.d.ts +36 -0
- package/dist/commands/doctor.js +115 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/login.d.ts +20 -0
- package/dist/commands/login.js +60 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/core/assess.d.ts +25 -0
- package/dist/core/assess.js +142 -0
- package/dist/core/assess.js.map +1 -0
- package/dist/core/classify.d.ts +19 -0
- package/dist/core/classify.js +80 -0
- package/dist/core/classify.js.map +1 -0
- package/dist/core/escalate.d.ts +32 -0
- package/dist/core/escalate.js +57 -0
- package/dist/core/escalate.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/orchestrate.d.ts +42 -0
- package/dist/core/orchestrate.js +439 -0
- package/dist/core/orchestrate.js.map +1 -0
- package/dist/core/policy.d.ts +9 -0
- package/dist/core/policy.js +27 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/prompt.d.ts +26 -0
- package/dist/core/prompt.js +125 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/review.d.ts +46 -0
- package/dist/core/review.js +148 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/route.d.ts +28 -0
- package/dist/core/route.js +52 -0
- package/dist/core/route.js.map +1 -0
- package/dist/core/types.d.ts +141 -0
- package/dist/core/types.js +14 -0
- package/dist/core/types.js.map +1 -0
- package/dist/infra/atomic.d.ts +53 -0
- package/dist/infra/atomic.js +171 -0
- package/dist/infra/atomic.js.map +1 -0
- package/dist/infra/clock.d.ts +9 -0
- package/dist/infra/clock.js +15 -0
- package/dist/infra/clock.js.map +1 -0
- package/dist/infra/index.d.ts +9 -0
- package/dist/infra/index.js +7 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/ledger.d.ts +49 -0
- package/dist/infra/ledger.js +90 -0
- package/dist/infra/ledger.js.map +1 -0
- package/dist/infra/paths.d.ts +28 -0
- package/dist/infra/paths.js +38 -0
- package/dist/infra/paths.js.map +1 -0
- package/dist/infra/pricing.d.ts +47 -0
- package/dist/infra/pricing.js +151 -0
- package/dist/infra/pricing.js.map +1 -0
- package/dist/infra/session.d.ts +28 -0
- package/dist/infra/session.js +61 -0
- package/dist/infra/session.js.map +1 -0
- package/dist/interface/render.d.ts +27 -0
- package/dist/interface/render.js +134 -0
- package/dist/interface/render.js.map +1 -0
- package/dist/interface/repl.d.ts +23 -0
- package/dist/interface/repl.js +90 -0
- package/dist/interface/repl.js.map +1 -0
- package/dist/interface/run.d.ts +20 -0
- package/dist/interface/run.js +31 -0
- package/dist/interface/run.js.map +1 -0
- package/dist/providers/claude-parse.d.ts +24 -0
- package/dist/providers/claude-parse.js +113 -0
- package/dist/providers/claude-parse.js.map +1 -0
- package/dist/providers/claude.d.ts +45 -0
- package/dist/providers/claude.js +122 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex-parse.d.ts +32 -0
- package/dist/providers/codex-parse.js +145 -0
- package/dist/providers/codex-parse.js.map +1 -0
- package/dist/providers/codex.d.ts +44 -0
- package/dist/providers/codex.js +124 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/detect.d.ts +49 -0
- package/dist/providers/detect.js +125 -0
- package/dist/providers/detect.js.map +1 -0
- package/dist/providers/errors.d.ts +49 -0
- package/dist/providers/errors.js +189 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/port.d.ts +74 -0
- package/dist/providers/port.js +16 -0
- package/dist/providers/port.js.map +1 -0
- package/dist/providers/registry.d.ts +21 -0
- package/dist/providers/registry.js +34 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/ui/banner.d.ts +19 -0
- package/dist/ui/banner.js +32 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/spinner.d.ts +27 -0
- package/dist/ui/spinner.js +67 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/theme.d.ts +32 -0
- package/dist/ui/theme.js +56 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +55 -49
- package/data/orchestrator.json +0 -113
- package/src/auth/recovery.mjs +0 -328
- package/src/auth/refresh.mjs +0 -373
- package/src/chef.mjs +0 -348
- package/src/cli/doctor.mjs +0 -568
- package/src/cli/reset.mjs +0 -447
- package/src/cli/status.mjs +0 -379
- package/src/cli.mjs +0 -429
- package/src/commands/doctor.mjs +0 -375
- package/src/commands/help.mjs +0 -324
- package/src/commands/status.mjs +0 -331
- package/src/monitor/health.mjs +0 -486
- package/src/monitor/performance.mjs +0 -442
- package/src/monitor/report.mjs +0 -535
- package/src/orchestrator/classify.mjs +0 -391
- package/src/orchestrator/confidence.mjs +0 -151
- package/src/orchestrator/handoffs.mjs +0 -231
- package/src/orchestrator/review.mjs +0 -222
- package/src/providers/balance.mjs +0 -201
- package/src/providers/claude.mjs +0 -236
- package/src/providers/codex.mjs +0 -255
- package/src/providers/detect.mjs +0 -185
- package/src/providers/errors.mjs +0 -373
- package/src/providers/select.mjs +0 -162
- package/src/repl-enhanced.mjs +0 -417
- package/src/repl.mjs +0 -321
- package/src/state/archive.mjs +0 -366
- package/src/state/atomic.mjs +0 -116
- package/src/state/cleanup.mjs +0 -440
- package/src/state/recovery.mjs +0 -461
- package/src/state/session.mjs +0 -147
- package/src/ui/errors.mjs +0 -456
- package/src/ui/formatter.mjs +0 -327
- package/src/ui/icons.mjs +0 -318
- package/src/ui/progress.mjs +0 -468
- package/templates/prompts/confidence-format.txt +0 -14
- package/templates/prompts/ic-with-feedback.txt +0 -41
- package/templates/prompts/ic.txt +0 -13
- package/templates/prompts/manager-review.txt +0 -40
- package/templates/prompts/manager.txt +0 -14
- package/templates/prompts/worker.txt +0 -12
package/src/auth/refresh.mjs
DELETED
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* refresh.mjs — OAuth token refresh system for Claude and Codex
|
|
3
|
-
* Adapted from archive/dual-brain/install.mjs
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import https from 'https';
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
-
import { join, resolve, dirname } from 'path';
|
|
9
|
-
import { atomicWriteJSON } from '../state/atomic.mjs';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* HTTP POST form helper
|
|
13
|
-
*/
|
|
14
|
-
function postForm(url, body) {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
const payload = Buffer.from(new URLSearchParams(body).toString(), 'utf8');
|
|
17
|
-
const req = https.request(url, {
|
|
18
|
-
method: 'POST',
|
|
19
|
-
headers: {
|
|
20
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
21
|
-
'Content-Length': payload.length,
|
|
22
|
-
},
|
|
23
|
-
timeout: 8000,
|
|
24
|
-
}, (res) => {
|
|
25
|
-
const chunks = [];
|
|
26
|
-
res.on('data', (chunk) => chunks.push(chunk));
|
|
27
|
-
res.on('end', () => {
|
|
28
|
-
const raw = Buffer.concat(chunks).toString('utf8');
|
|
29
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
30
|
-
try {
|
|
31
|
-
resolve(JSON.parse(raw));
|
|
32
|
-
} catch (err) {
|
|
33
|
-
reject(err);
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
reject(new Error(`HTTP ${res.statusCode || 0}: ${raw}`));
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
req.on('timeout', () => req.destroy(new Error('Request timeout')));
|
|
41
|
-
req.on('error', reject);
|
|
42
|
-
req.write(payload);
|
|
43
|
-
req.end();
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Safe JSON parsing with fallback
|
|
49
|
-
*/
|
|
50
|
-
function safeParseJson(path) {
|
|
51
|
-
try {
|
|
52
|
-
return JSON.parse(readFileSync(path, 'utf8'));
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Decode JWT payload without verification
|
|
60
|
-
*/
|
|
61
|
-
function decodeJwtPayload(token) {
|
|
62
|
-
if (!token || typeof token !== 'string') return null;
|
|
63
|
-
const parts = token.split('.');
|
|
64
|
-
if (parts.length < 2) return null;
|
|
65
|
-
try {
|
|
66
|
-
return JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
67
|
-
} catch {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Compute expiration time in hours
|
|
74
|
-
*/
|
|
75
|
-
function computeExpiresInHours(expiresAtMs) {
|
|
76
|
-
if (!Number.isFinite(expiresAtMs)) return null;
|
|
77
|
-
return Math.round(((expiresAtMs - Date.now()) / 3_600_000) * 10) / 10;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Get potential Claude credential file paths
|
|
82
|
-
*/
|
|
83
|
-
function getClaudeCredentialPaths(workspace = process.cwd()) {
|
|
84
|
-
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
85
|
-
const home = process.env.HOME || '';
|
|
86
|
-
return [
|
|
87
|
-
configDir ? join(configDir, '.credentials.json') : null,
|
|
88
|
-
join(home, '.claude', '.credentials.json'),
|
|
89
|
-
join(home, '.claude', 'credentials.json'),
|
|
90
|
-
resolve(workspace, '.replit-tools', '.claude-persistent', '.credentials.json'),
|
|
91
|
-
].filter(Boolean);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get Codex auth file path
|
|
96
|
-
*/
|
|
97
|
-
function getCodexAuthPath() {
|
|
98
|
-
const home = process.env.HOME || '';
|
|
99
|
-
return join(home, '.codex', 'auth.json');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Refresh Claude OAuth token
|
|
104
|
-
*/
|
|
105
|
-
async function refreshClaudeToken() {
|
|
106
|
-
const credPaths = getClaudeCredentialPaths();
|
|
107
|
-
|
|
108
|
-
for (const credPath of credPaths) {
|
|
109
|
-
if (!existsSync(credPath)) continue;
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
const cred = safeParseJson(credPath);
|
|
113
|
-
const oauth = cred?.claudeAiOauth;
|
|
114
|
-
if (!oauth?.refreshToken) continue;
|
|
115
|
-
|
|
116
|
-
const refreshed = await postForm('https://console.anthropic.com/v1/oauth/token', {
|
|
117
|
-
grant_type: 'refresh_token',
|
|
118
|
-
refresh_token: oauth.refreshToken,
|
|
119
|
-
client_id: '9d1c250a-e61b-44d9-88ed-5944d1962f5e',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const nextOauth = {
|
|
123
|
-
...oauth,
|
|
124
|
-
accessToken: refreshed.access_token || oauth.accessToken,
|
|
125
|
-
refreshToken: refreshed.refresh_token || oauth.refreshToken,
|
|
126
|
-
tokenType: refreshed.token_type || oauth.tokenType,
|
|
127
|
-
scopes: refreshed.scope || oauth.scopes,
|
|
128
|
-
expiresAt: Date.now() + ((refreshed.expires_in || 0) * 1000),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const updated = { ...cred, claudeAiOauth: nextOauth };
|
|
132
|
-
atomicWriteJSON(credPath, updated);
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
success: true,
|
|
136
|
-
provider: 'claude',
|
|
137
|
-
expiresInHours: computeExpiresInHours(nextOauth.expiresAt),
|
|
138
|
-
refreshed: true
|
|
139
|
-
};
|
|
140
|
-
} catch (error) {
|
|
141
|
-
return {
|
|
142
|
-
success: false,
|
|
143
|
-
provider: 'claude',
|
|
144
|
-
action: 'reauth_required',
|
|
145
|
-
error: error.message
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
success: false,
|
|
152
|
-
provider: 'claude',
|
|
153
|
-
action: 'no_credentials',
|
|
154
|
-
error: 'No Claude credentials found'
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Refresh OpenAI/Codex token
|
|
160
|
-
*/
|
|
161
|
-
async function refreshOpenAIToken() {
|
|
162
|
-
const authPath = getCodexAuthPath();
|
|
163
|
-
|
|
164
|
-
if (!existsSync(authPath)) {
|
|
165
|
-
return {
|
|
166
|
-
success: false,
|
|
167
|
-
provider: 'openai',
|
|
168
|
-
action: 'no_credentials',
|
|
169
|
-
error: 'No Codex auth file found'
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
const auth = safeParseJson(authPath);
|
|
175
|
-
const tokens = auth?.tokens || auth;
|
|
176
|
-
const refreshToken = tokens?.refresh_token;
|
|
177
|
-
|
|
178
|
-
if (!refreshToken) {
|
|
179
|
-
return {
|
|
180
|
-
success: false,
|
|
181
|
-
provider: 'openai',
|
|
182
|
-
action: 'no_refresh_token',
|
|
183
|
-
error: 'No refresh token available'
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const refreshed = await postForm('https://auth.openai.com/oauth/token', {
|
|
188
|
-
grant_type: 'refresh_token',
|
|
189
|
-
refresh_token: refreshToken,
|
|
190
|
-
client_id: 'app_EMoamEEZ73f0CkXaXp7hrann',
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const updatedTokens = {
|
|
194
|
-
...tokens,
|
|
195
|
-
access_token: refreshed.access_token || tokens.access_token,
|
|
196
|
-
refresh_token: refreshed.refresh_token || tokens.refresh_token,
|
|
197
|
-
id_token: refreshed.id_token || tokens.id_token,
|
|
198
|
-
token_type: refreshed.token_type || tokens.token_type,
|
|
199
|
-
scope: refreshed.scope || tokens.scope,
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const updated = auth?.tokens ? { ...auth, tokens: updatedTokens } : updatedTokens;
|
|
203
|
-
atomicWriteJSON(authPath, updated);
|
|
204
|
-
|
|
205
|
-
const payload = decodeJwtPayload(updatedTokens.access_token);
|
|
206
|
-
return {
|
|
207
|
-
success: true,
|
|
208
|
-
provider: 'openai',
|
|
209
|
-
expiresInHours: payload?.exp ? computeExpiresInHours(payload.exp * 1000) : null,
|
|
210
|
-
refreshed: true
|
|
211
|
-
};
|
|
212
|
-
} catch (error) {
|
|
213
|
-
return {
|
|
214
|
-
success: false,
|
|
215
|
-
provider: 'openai',
|
|
216
|
-
action: 'reauth_required',
|
|
217
|
-
error: error.message
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Refresh all available tokens
|
|
224
|
-
*/
|
|
225
|
-
export async function refreshTokens() {
|
|
226
|
-
const results = [];
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
const claudeResult = await refreshClaudeToken();
|
|
230
|
-
results.push(claudeResult);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
results.push({
|
|
233
|
-
success: false,
|
|
234
|
-
provider: 'claude',
|
|
235
|
-
error: error.message,
|
|
236
|
-
action: 'reauth_required'
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
const openaiResult = await refreshOpenAIToken();
|
|
242
|
-
results.push(openaiResult);
|
|
243
|
-
} catch (error) {
|
|
244
|
-
results.push({
|
|
245
|
-
success: false,
|
|
246
|
-
provider: 'openai',
|
|
247
|
-
error: error.message,
|
|
248
|
-
action: 'reauth_required'
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const successful = results.filter(r => r.success);
|
|
253
|
-
const needReauth = results.filter(r => r.action === 'reauth_required');
|
|
254
|
-
|
|
255
|
-
return {
|
|
256
|
-
success: successful.length > 0,
|
|
257
|
-
results,
|
|
258
|
-
refreshed: successful.filter(r => r.refreshed),
|
|
259
|
-
needReauth: needReauth,
|
|
260
|
-
hasValidAuth: successful.length > 0
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Get refresh state file path
|
|
266
|
-
*/
|
|
267
|
-
function getRefreshStatePath() {
|
|
268
|
-
const home = process.env.HOME || '';
|
|
269
|
-
const dir = join(home, '.cortex', 'auth');
|
|
270
|
-
if (!existsSync(dir)) {
|
|
271
|
-
mkdirSync(dir, { recursive: true });
|
|
272
|
-
}
|
|
273
|
-
return join(dir, 'refresh-state.json');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Save refresh state for background processing
|
|
278
|
-
*/
|
|
279
|
-
export function saveRefreshState(results) {
|
|
280
|
-
const statePath = getRefreshStatePath();
|
|
281
|
-
const state = {
|
|
282
|
-
lastRefresh: new Date().toISOString(),
|
|
283
|
-
results,
|
|
284
|
-
nextRefreshDue: new Date(Date.now() + (23 * 60 * 60 * 1000)).toISOString() // 23 hours
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
atomicWriteJSON(statePath, state);
|
|
289
|
-
} catch (error) {
|
|
290
|
-
console.warn('Failed to save refresh state:', error.message);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Load refresh state
|
|
296
|
-
*/
|
|
297
|
-
export function loadRefreshState() {
|
|
298
|
-
const statePath = getRefreshStatePath();
|
|
299
|
-
|
|
300
|
-
if (!existsSync(statePath)) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
return safeParseJson(statePath);
|
|
306
|
-
} catch {
|
|
307
|
-
return null;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Check if refresh is due (run every 24 hours)
|
|
313
|
-
*/
|
|
314
|
-
export function isRefreshDue() {
|
|
315
|
-
const state = loadRefreshState();
|
|
316
|
-
if (!state?.nextRefreshDue) return true;
|
|
317
|
-
|
|
318
|
-
return new Date() >= new Date(state.nextRefreshDue);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Background token refresh with error handling
|
|
323
|
-
*/
|
|
324
|
-
export async function backgroundRefresh() {
|
|
325
|
-
if (!isRefreshDue()) {
|
|
326
|
-
return { skipped: true, reason: 'Not due for refresh' };
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
try {
|
|
330
|
-
const results = await refreshTokens();
|
|
331
|
-
saveRefreshState(results.results);
|
|
332
|
-
|
|
333
|
-
return {
|
|
334
|
-
success: true,
|
|
335
|
-
hasValidAuth: results.hasValidAuth,
|
|
336
|
-
refreshed: results.refreshed.map(r => r.provider),
|
|
337
|
-
needReauth: results.needReauth.map(r => r.provider)
|
|
338
|
-
};
|
|
339
|
-
} catch (error) {
|
|
340
|
-
return {
|
|
341
|
-
success: false,
|
|
342
|
-
error: error.message
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Display refresh status to user
|
|
349
|
-
*/
|
|
350
|
-
export function displayRefreshStatus(refreshResult) {
|
|
351
|
-
if (refreshResult.skipped) {
|
|
352
|
-
return; // Silent when not due
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (refreshResult.success) {
|
|
356
|
-
if (refreshResult.refreshed.length > 0) {
|
|
357
|
-
console.log(`🔄 Refreshed tokens: ${refreshResult.refreshed.join(', ')}`);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (refreshResult.needReauth.length > 0) {
|
|
361
|
-
console.log(`\n⚠️ Re-authentication required for: ${refreshResult.needReauth.join(', ')}`);
|
|
362
|
-
for (const provider of refreshResult.needReauth) {
|
|
363
|
-
if (provider === 'claude') {
|
|
364
|
-
console.log(' Run: claude auth login');
|
|
365
|
-
} else if (provider === 'openai') {
|
|
366
|
-
console.log(' Run: codex login');
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
} else if (refreshResult.error) {
|
|
371
|
-
console.log(`⚠️ Token refresh failed: ${refreshResult.error}`);
|
|
372
|
-
}
|
|
373
|
-
}
|
package/src/chef.mjs
DELETED
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chef.mjs — The three-tier hierarchical orchestration engine
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { executeClaude, buildClaudePrompt } from './providers/claude.mjs';
|
|
6
|
-
import { executeCodex, buildCodexPrompt } from './providers/codex.mjs';
|
|
7
|
-
import { classifyTask, shouldEscalate, selectModel } from './orchestrator/classify.mjs';
|
|
8
|
-
import { addMessage, addHandoff } from './state/session.mjs';
|
|
9
|
-
import { parseConfidence, shouldEscalateOnConfidence } from './orchestrator/confidence.mjs';
|
|
10
|
-
import { logHandoff, logEscalation, logBounce, checkFailureLoop } from './orchestrator/handoffs.mjs';
|
|
11
|
-
import { runManagerReview, shouldTriggerManagerReview } from './orchestrator/review.mjs';
|
|
12
|
-
import { selectProvider, checkProviderHealth } from './providers/select.mjs';
|
|
13
|
-
import { balanceProviderLoad } from './providers/balance.mjs';
|
|
14
|
-
import { trackHandoff } from './monitor/performance.mjs';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Execute a task at a specific tier with intelligent provider selection
|
|
18
|
-
*/
|
|
19
|
-
async function runTier(tier, task, context = {}) {
|
|
20
|
-
const { availableModels, sessionId } = context;
|
|
21
|
-
|
|
22
|
-
// Use intelligent provider selection with load balancing
|
|
23
|
-
const model = selectProvider ?
|
|
24
|
-
selectProvider(tier, { availableModels, sessionId }) :
|
|
25
|
-
selectModel(tier, availableModels);
|
|
26
|
-
|
|
27
|
-
if (!model) {
|
|
28
|
-
return {
|
|
29
|
-
success: false,
|
|
30
|
-
error: `No available model for tier: ${tier}`,
|
|
31
|
-
tier,
|
|
32
|
-
model: null
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Check provider health before executing
|
|
37
|
-
if (checkProviderHealth) {
|
|
38
|
-
const health = checkProviderHealth(model.provider);
|
|
39
|
-
if (!health.available) {
|
|
40
|
-
console.log(` ⚠️ ${model.provider} is degraded (${health.failures} recent failures)`);
|
|
41
|
-
// Try to find alternative provider
|
|
42
|
-
const tierModels = availableModels[tier] || [];
|
|
43
|
-
const alternative = tierModels.find(m => m.provider !== model.provider);
|
|
44
|
-
if (alternative) {
|
|
45
|
-
console.log(` 🔄 Switching to ${alternative.provider}/${alternative.model}`);
|
|
46
|
-
return runTier(tier, task, { ...context, availableModels: { [tier]: [alternative] } });
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log(` ${tier.toUpperCase()} (${model.provider}/${model.model}): Working...`);
|
|
52
|
-
|
|
53
|
-
const startTime = Date.now();
|
|
54
|
-
let result;
|
|
55
|
-
let prompt;
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
// Build appropriate prompt for the provider and tier
|
|
59
|
-
if (model.provider === 'claude') {
|
|
60
|
-
prompt = buildClaudePrompt(tier, task, context);
|
|
61
|
-
result = await executeClaude(model.bin, model.model, prompt, context.options);
|
|
62
|
-
} else if (model.provider === 'codex') {
|
|
63
|
-
prompt = buildCodexPrompt(tier, task, context);
|
|
64
|
-
result = await executeCodex(model.bin, model.model, prompt, context.options);
|
|
65
|
-
} else {
|
|
66
|
-
return {
|
|
67
|
-
success: false,
|
|
68
|
-
error: `Unknown provider: ${model.provider}`,
|
|
69
|
-
tier,
|
|
70
|
-
model
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Enhanced confidence parsing
|
|
75
|
-
if (result.success && result.output) {
|
|
76
|
-
const confidenceData = parseConfidence(result.output);
|
|
77
|
-
result.confidence = confidenceData.confidence;
|
|
78
|
-
result.escalate = confidenceData.escalate;
|
|
79
|
-
result.reasoning = confidenceData.reason;
|
|
80
|
-
result.needsReview = confidenceData.needsReview;
|
|
81
|
-
result.structured = confidenceData.structured;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Add metadata
|
|
85
|
-
result.tier = tier;
|
|
86
|
-
result.selectedModel = model;
|
|
87
|
-
result.durationMs = Date.now() - startTime;
|
|
88
|
-
|
|
89
|
-
// Log the handoff for audit trail
|
|
90
|
-
if (logHandoff) {
|
|
91
|
-
logHandoff('execute', 'user', tier, {
|
|
92
|
-
providerfrom: 'user',
|
|
93
|
-
providerTo: model.provider,
|
|
94
|
-
confidenceOut: result.confidence,
|
|
95
|
-
durationMs: result.durationMs,
|
|
96
|
-
sessionId: context.sessionId,
|
|
97
|
-
success: result.success
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Track performance metrics
|
|
102
|
-
trackHandoff({
|
|
103
|
-
operation: 'execute',
|
|
104
|
-
fromTier: 'user',
|
|
105
|
-
toTier: tier,
|
|
106
|
-
provider: model.provider,
|
|
107
|
-
model: model.model,
|
|
108
|
-
confidence: result.confidence,
|
|
109
|
-
success: result.success,
|
|
110
|
-
durationMs: result.durationMs,
|
|
111
|
-
tokensUsed: result.usage?.total_tokens || null,
|
|
112
|
-
prompt: task,
|
|
113
|
-
output: result.output
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
return result;
|
|
117
|
-
|
|
118
|
-
} catch (error) {
|
|
119
|
-
const errorResult = {
|
|
120
|
-
success: false,
|
|
121
|
-
error: error.message,
|
|
122
|
-
tier,
|
|
123
|
-
model,
|
|
124
|
-
output: '',
|
|
125
|
-
durationMs: Date.now() - startTime
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Log failure for future routing decisions
|
|
129
|
-
if (logHandoff) {
|
|
130
|
-
logHandoff('execute_failed', 'user', tier, {
|
|
131
|
-
providerFrom: 'user',
|
|
132
|
-
providerTo: model.provider,
|
|
133
|
-
durationMs: errorResult.durationMs,
|
|
134
|
-
sessionId: context.sessionId,
|
|
135
|
-
reason: error.message,
|
|
136
|
-
success: false
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return errorResult;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* The main orchestration function with Phase 2 smart routing enhancements
|
|
146
|
-
*/
|
|
147
|
-
export async function chef(userMessage, context = {}) {
|
|
148
|
-
console.log(`\nCortex AI Org Chart Processing: "${userMessage}"`);
|
|
149
|
-
|
|
150
|
-
// Generate session ID for tracking
|
|
151
|
-
const sessionId = context.sessionId || `session_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
|
|
152
|
-
context.sessionId = sessionId;
|
|
153
|
-
|
|
154
|
-
// Step 1: Enhanced task classification
|
|
155
|
-
const classification = classifyTask(userMessage, context.fileContext);
|
|
156
|
-
console.log(`Task Classification: ${classification.tier} tier, ${classification.risk} risk`);
|
|
157
|
-
console.log(`Reason: ${classification.reason}`);
|
|
158
|
-
console.log(`Confidence Estimate: ${(classification.confidence * 100).toFixed(0)}%`);
|
|
159
|
-
|
|
160
|
-
// Check for failure loops before starting
|
|
161
|
-
const taskHash = createTaskHash(userMessage);
|
|
162
|
-
const failureCheck = checkFailureLoop ? checkFailureLoop(taskHash) : { isLoop: false };
|
|
163
|
-
|
|
164
|
-
if (failureCheck.isLoop) {
|
|
165
|
-
console.log(` ⚠️ Failure loop detected (${failureCheck.bounceCount} bounces, score: ${failureCheck.weightedScore.toFixed(1)})`);
|
|
166
|
-
if (failureCheck.suggestion === 'escalate_to_manager') {
|
|
167
|
-
classification.tier = 'manager';
|
|
168
|
-
console.log(` ↗️ Auto-escalating to MANAGER due to failure loop`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Step 2: Start with the classified tier (or IC as default)
|
|
173
|
-
let currentTier = classification.tier === 'manager' ? 'manager' : 'ic';
|
|
174
|
-
let attempts = 0;
|
|
175
|
-
const maxAttempts = 3;
|
|
176
|
-
let lastResult = null;
|
|
177
|
-
|
|
178
|
-
while (attempts < maxAttempts) {
|
|
179
|
-
attempts++;
|
|
180
|
-
console.log(`\nAttempt ${attempts}: Starting at ${currentTier.toUpperCase()} tier`);
|
|
181
|
-
|
|
182
|
-
// Execute at current tier
|
|
183
|
-
const result = await runTier(currentTier, userMessage, {
|
|
184
|
-
...context,
|
|
185
|
-
attempt: attempts,
|
|
186
|
-
taskHash,
|
|
187
|
-
managerNotes: context.managerNotes
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (!result.success) {
|
|
191
|
-
console.log(` ❌ ${currentTier.toUpperCase()} failed: ${result.error}`);
|
|
192
|
-
|
|
193
|
-
// Log escalation due to failure
|
|
194
|
-
if (logEscalation && currentTier !== 'manager') {
|
|
195
|
-
logEscalation(currentTier, 'manager', 'execution failure', {
|
|
196
|
-
sessionId,
|
|
197
|
-
attempt: attempts,
|
|
198
|
-
taskHash,
|
|
199
|
-
error: result.error
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (currentTier !== 'manager') {
|
|
204
|
-
console.log(` ↗️ ESCALATE → MANAGER (execution failure)`);
|
|
205
|
-
addHandoff('escalate', currentTier, 'manager', 'execution failure');
|
|
206
|
-
currentTier = 'manager';
|
|
207
|
-
context.previous = result;
|
|
208
|
-
continue;
|
|
209
|
-
} else {
|
|
210
|
-
return {
|
|
211
|
-
success: false,
|
|
212
|
-
output: result.error,
|
|
213
|
-
tier: 'manager',
|
|
214
|
-
totalAttempts: attempts,
|
|
215
|
-
finalResult: result,
|
|
216
|
-
sessionId
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
lastResult = result;
|
|
222
|
-
|
|
223
|
-
// Log successful completion
|
|
224
|
-
console.log(` ✓ ${currentTier.toUpperCase()} completed`);
|
|
225
|
-
if (result.confidence !== null) {
|
|
226
|
-
console.log(` Confidence: ${(result.confidence * 100).toFixed(0)}%`);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Phase 2 Enhancement: Manager Review Pattern for high-stakes work
|
|
230
|
-
if (currentTier === 'ic' && shouldTriggerManagerReview) {
|
|
231
|
-
const reviewCheck = shouldTriggerManagerReview(userMessage, classification, result);
|
|
232
|
-
|
|
233
|
-
if (reviewCheck.required) {
|
|
234
|
-
console.log(` 🔍 Triggering manager review: ${reviewCheck.reason}`);
|
|
235
|
-
|
|
236
|
-
const review = await runManagerReview(userMessage, result, context, runTier);
|
|
237
|
-
|
|
238
|
-
if (review.verdict === 'bounce' && attempts < maxAttempts) {
|
|
239
|
-
console.log(` ↩️ BOUNCE DOWN: Manager wants fixes (attempt ${attempts + 1})`);
|
|
240
|
-
|
|
241
|
-
// Log bounce for audit trail
|
|
242
|
-
if (logBounce) {
|
|
243
|
-
logBounce('manager', 'ic', review.notes, attempts + 1, {
|
|
244
|
-
sessionId,
|
|
245
|
-
taskHash,
|
|
246
|
-
originalConfidence: result.confidence,
|
|
247
|
-
reviewConfidence: review.managerResult.confidence
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Set up context for retry with manager feedback
|
|
252
|
-
context.managerNotes = review.notes;
|
|
253
|
-
context.attempt = attempts + 1;
|
|
254
|
-
|
|
255
|
-
// Stay at IC tier but incorporate manager feedback
|
|
256
|
-
continue; // This will increment attempts and retry
|
|
257
|
-
} else if (review.verdict === 'escalate') {
|
|
258
|
-
console.log(` ↗️ ESCALATE: Manager taking over directly`);
|
|
259
|
-
currentTier = 'manager';
|
|
260
|
-
context.previous = result;
|
|
261
|
-
continue;
|
|
262
|
-
} else if (review.verdict === 'approve') {
|
|
263
|
-
console.log(` ✅ Manager approved IC work`);
|
|
264
|
-
// Continue with approval
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Check if we should escalate based on confidence/risk
|
|
270
|
-
const needsEscalation = shouldEscalate(result, classification) ||
|
|
271
|
-
shouldEscalateOnConfidence(result.confidence, classification.risk, currentTier);
|
|
272
|
-
|
|
273
|
-
if (needsEscalation && currentTier !== 'manager') {
|
|
274
|
-
console.log(` ↗️ ESCALATE → MANAGER (${result.reasoning || 'low confidence'})`);
|
|
275
|
-
|
|
276
|
-
if (logEscalation) {
|
|
277
|
-
logEscalation(currentTier, 'manager', result.reasoning || 'low confidence', {
|
|
278
|
-
sessionId,
|
|
279
|
-
attempt: attempts,
|
|
280
|
-
taskHash,
|
|
281
|
-
confidence: result.confidence,
|
|
282
|
-
riskLevel: classification.risk
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
addHandoff('escalate', currentTier, 'manager', result.reasoning || 'low confidence', {
|
|
287
|
-
confidence: result.confidence
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
currentTier = 'manager';
|
|
291
|
-
context.previous = result;
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Task completed successfully
|
|
296
|
-
console.log(` 🎯 Task completed at ${currentTier.toUpperCase()} tier`);
|
|
297
|
-
|
|
298
|
-
return {
|
|
299
|
-
success: true,
|
|
300
|
-
output: result.output,
|
|
301
|
-
tier: currentTier,
|
|
302
|
-
confidence: result.confidence,
|
|
303
|
-
model: result.selectedModel,
|
|
304
|
-
classification,
|
|
305
|
-
totalAttempts: attempts,
|
|
306
|
-
finalResult: result,
|
|
307
|
-
sessionId,
|
|
308
|
-
review: currentTier === 'ic' ? 'manager_approved' : 'direct_completion'
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return {
|
|
313
|
-
success: false,
|
|
314
|
-
output: 'Maximum escalation attempts reached',
|
|
315
|
-
tier: currentTier,
|
|
316
|
-
totalAttempts: attempts,
|
|
317
|
-
error: 'Max attempts exceeded',
|
|
318
|
-
sessionId,
|
|
319
|
-
lastResult
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Create a hash for task tracking across attempts
|
|
325
|
-
*/
|
|
326
|
-
function createTaskHash(task) {
|
|
327
|
-
// Simple hash for tracking related attempts
|
|
328
|
-
return `task_${Buffer.from(task.slice(0, 100)).toString('base64').slice(0, 8)}`;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Handle delegation to worker tier for simple tasks
|
|
333
|
-
*/
|
|
334
|
-
export async function delegateToWorker(task, context = {}) {
|
|
335
|
-
console.log(` ↘️ DELEGATE → WORKER`);
|
|
336
|
-
addHandoff('delegate', 'ic', 'worker', 'simple task delegation');
|
|
337
|
-
|
|
338
|
-
const result = await runTier('worker', task, context);
|
|
339
|
-
|
|
340
|
-
if (!result.success || shouldEscalate(result, classifyTask(task))) {
|
|
341
|
-
console.log(` ↗️ WORKER → IC (delegation failed or escalation needed)`);
|
|
342
|
-
addHandoff('escalate', 'worker', 'ic', result.reasoning || 'worker task failed');
|
|
343
|
-
return null; // Signal to retry at IC level
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
console.log(` ✓ WORKER completed delegation`);
|
|
347
|
-
return result;
|
|
348
|
-
}
|