@siftd/connect-agent 0.2.38 → 0.2.40
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/README.md +3 -7
- package/dist/agent.js +69 -127
- package/dist/api.d.ts +0 -1
- package/dist/cli.js +1 -1
- package/dist/core/task-queue.d.ts +124 -0
- package/dist/core/task-queue.js +248 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/orchestrator.d.ts +81 -3
- package/dist/orchestrator.js +349 -10
- package/dist/websocket.d.ts +5 -2
- package/dist/websocket.js +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Connect Agent runs on your machine and bridges the Connect web app to Claude Cod
|
|
|
18
18
|
```bash
|
|
19
19
|
# 1. Go to https://connect.siftd.app and get a pairing code
|
|
20
20
|
|
|
21
|
-
# 2. Pair your machine (with API key
|
|
21
|
+
# 2. Pair your machine (with API key)
|
|
22
22
|
npx @siftd/connect-agent pair <CODE> --api-key <YOUR_ANTHROPIC_API_KEY>
|
|
23
23
|
|
|
24
24
|
# 3. Start the agent
|
|
@@ -33,17 +33,13 @@ On first start, the agent creates `~/Lia-Hub/` with:
|
|
|
33
33
|
|
|
34
34
|
## Modes
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
When you provide an Anthropic API key, the agent runs as a **master orchestrator**:
|
|
36
|
+
The agent runs as a **master orchestrator** (requires an Anthropic API key):
|
|
38
37
|
- Uses Claude API directly for the orchestration layer
|
|
39
38
|
- Maintains persistent memory about you and your projects
|
|
40
39
|
- Delegates file/code work to Claude Code CLI workers
|
|
41
40
|
- Schedules future tasks
|
|
42
41
|
- Reads hub files for context on every startup
|
|
43
42
|
|
|
44
|
-
### Simple Relay Mode
|
|
45
|
-
Without an API key, the agent acts as a simple relay to `claude -p --continue`.
|
|
46
|
-
|
|
47
43
|
## Commands
|
|
48
44
|
|
|
49
45
|
```bash
|
|
@@ -66,7 +62,7 @@ connect-agent logout
|
|
|
66
62
|
## Special Commands (via web chat)
|
|
67
63
|
|
|
68
64
|
- `/reset` or `/clear` - Clear conversation history
|
|
69
|
-
- `/mode` -
|
|
65
|
+
- `/mode` - Show runtime details
|
|
70
66
|
- `/memory` - Show memory statistics
|
|
71
67
|
- `/verbose` - Toggle verbose tool output
|
|
72
68
|
|
package/dist/agent.js
CHANGED
|
@@ -12,10 +12,6 @@ import { startHeartbeat, stopHeartbeat, getHeartbeatState } from './heartbeat.js
|
|
|
12
12
|
import { loadHubContext, readScratchpad } from './core/hub.js';
|
|
13
13
|
import { PRODUCT_FULL_NAME } from './branding.js';
|
|
14
14
|
import { startPreviewWorker, stopPreviewWorker } from './core/preview-worker.js';
|
|
15
|
-
// Strip ANSI escape codes for clean output
|
|
16
|
-
function stripAnsi(str) {
|
|
17
|
-
return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '');
|
|
18
|
-
}
|
|
19
15
|
function parseAttachments(content) {
|
|
20
16
|
const marker = '📎 Attached files:';
|
|
21
17
|
const index = content.indexOf(marker);
|
|
@@ -162,13 +158,10 @@ function initOrchestrator() {
|
|
|
162
158
|
const instanceMode = getInstanceMode();
|
|
163
159
|
const userOrgIds = getUserOrgIds();
|
|
164
160
|
if (!apiKey) {
|
|
165
|
-
|
|
166
|
-
console.log('[AGENT] To enable orchestrator: pair with --api-key flag');
|
|
167
|
-
return null;
|
|
161
|
+
throw new Error('Missing Anthropic API key. Set ANTHROPIC_API_KEY or run `lia-agent set-key <key>`.');
|
|
168
162
|
}
|
|
169
163
|
if (!userId) {
|
|
170
|
-
|
|
171
|
-
return null;
|
|
164
|
+
throw new Error('Missing userId configuration. Re-pair the agent.');
|
|
172
165
|
}
|
|
173
166
|
console.log(`[AGENT] Initializing Master Orchestrator (mode: ${instanceMode})...`);
|
|
174
167
|
if (instanceMode === 'personal' && userOrgIds.length > 0) {
|
|
@@ -187,59 +180,11 @@ function initOrchestrator() {
|
|
|
187
180
|
userOrgIds: instanceMode === 'personal' ? userOrgIds : undefined,
|
|
188
181
|
});
|
|
189
182
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Simple relay mode - just pipes to Claude Code CLI
|
|
192
|
-
*/
|
|
193
|
-
async function sendToClaudeSimple(input) {
|
|
194
|
-
return new Promise((resolve) => {
|
|
195
|
-
console.log(`\n[CLAUDE] Sending: ${input.substring(0, 80)}...`);
|
|
196
|
-
const claude = spawn('claude', ['-p', '--continue'], {
|
|
197
|
-
cwd: process.env.HOME,
|
|
198
|
-
env: process.env,
|
|
199
|
-
shell: true,
|
|
200
|
-
});
|
|
201
|
-
let output = '';
|
|
202
|
-
let errorOutput = '';
|
|
203
|
-
claude.stdout?.on('data', (data) => {
|
|
204
|
-
const text = data.toString();
|
|
205
|
-
output += text;
|
|
206
|
-
process.stdout.write(text);
|
|
207
|
-
});
|
|
208
|
-
claude.stderr?.on('data', (data) => {
|
|
209
|
-
const text = data.toString();
|
|
210
|
-
errorOutput += text;
|
|
211
|
-
if (!text.includes('Checking') && !text.includes('Connected')) {
|
|
212
|
-
process.stderr.write(text);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
claude.on('close', (code) => {
|
|
216
|
-
if (code === 0) {
|
|
217
|
-
const response = stripAnsi(output).trim();
|
|
218
|
-
console.log(`\n[CLAUDE] Response: ${response.substring(0, 80)}...`);
|
|
219
|
-
resolve(response || 'No response from Claude');
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
const error = errorOutput || `Claude exited with code ${code}`;
|
|
223
|
-
console.error(`\n[CLAUDE] Error: ${error}`);
|
|
224
|
-
resolve(`Error: ${stripAnsi(error).trim()}`);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
claude.on('error', (err) => {
|
|
228
|
-
console.error(`\n[CLAUDE] Failed to start: ${err.message}`);
|
|
229
|
-
resolve(`Error: Failed to start Claude - ${err.message}`);
|
|
230
|
-
});
|
|
231
|
-
if (claude.stdin) {
|
|
232
|
-
claude.stdin.write(input);
|
|
233
|
-
claude.stdin.end();
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
183
|
/**
|
|
238
184
|
* Orchestrator mode - uses the master orchestrator with memory
|
|
239
185
|
* Supports WebSocket streaming for real-time progress updates
|
|
240
|
-
* @param apiKey Optional per-request API key from user
|
|
241
186
|
*/
|
|
242
|
-
async function sendToOrchestrator(input, orch, messageId
|
|
187
|
+
async function sendToOrchestrator(input, orch, messageId) {
|
|
243
188
|
console.log(`\n[ORCHESTRATOR] Processing: ${input.substring(0, 80)}...`);
|
|
244
189
|
// Send typing indicator via WebSocket
|
|
245
190
|
if (wsClient?.connected()) {
|
|
@@ -263,8 +208,7 @@ async function sendToOrchestrator(input, orch, messageId, apiKey) {
|
|
|
263
208
|
if (wsClient?.connected() && messageId) {
|
|
264
209
|
wsClient.sendProgress(messageId, msg);
|
|
265
210
|
}
|
|
266
|
-
}
|
|
267
|
-
);
|
|
211
|
+
});
|
|
268
212
|
// Update conversation history (only if response is non-empty)
|
|
269
213
|
if (response && response.trim()) {
|
|
270
214
|
conversationHistory.push({ role: 'user', content: input });
|
|
@@ -307,14 +251,11 @@ export async function processMessage(message) {
|
|
|
307
251
|
const wsStatus = wsClient?.connected() ? 'WebSocket' : 'Polling';
|
|
308
252
|
const hbState = getHeartbeatState();
|
|
309
253
|
const runnerInfo = hbState.runnerId ? ` [${hbState.runnerId}]` : '';
|
|
310
|
-
return
|
|
311
|
-
? `Running in ORCHESTRATOR mode (${wsStatus})${runnerInfo} with memory and delegation`
|
|
312
|
-
: `Running in SIMPLE mode (${wsStatus})${runnerInfo} - direct Claude Code relay`;
|
|
254
|
+
return `Running in ORCHESTRATOR mode (${wsStatus})${runnerInfo} with memory and delegation`;
|
|
313
255
|
}
|
|
314
256
|
if (content === '/memory' && orchestrator) {
|
|
315
257
|
// Trigger memory stats
|
|
316
|
-
const response = await orchestrator.processMessage('Show me my memory stats', [], undefined
|
|
317
|
-
);
|
|
258
|
+
const response = await orchestrator.processMessage('Show me my memory stats', [], undefined);
|
|
318
259
|
return response;
|
|
319
260
|
}
|
|
320
261
|
// System command: force update (sent by webapp banner)
|
|
@@ -359,12 +300,7 @@ export async function processMessage(message) {
|
|
|
359
300
|
};
|
|
360
301
|
}
|
|
361
302
|
try {
|
|
362
|
-
|
|
363
|
-
return await sendToOrchestrator(message.content, orchestrator, message.id, message.apiKey);
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
return await sendToClaudeSimple(message.content);
|
|
367
|
-
}
|
|
303
|
+
return await sendToOrchestrator(message.content, orchestrator, message.id);
|
|
368
304
|
}
|
|
369
305
|
catch (error) {
|
|
370
306
|
console.error('Error:', error);
|
|
@@ -372,9 +308,15 @@ export async function processMessage(message) {
|
|
|
372
308
|
}
|
|
373
309
|
}
|
|
374
310
|
export async function runAgent(pollInterval = 2000) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
311
|
+
try {
|
|
312
|
+
orchestrator = initOrchestrator();
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
316
|
+
console.error(`[AGENT] ${msg}`);
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
const mode = 'ORCHESTRATOR';
|
|
378
320
|
const deployment = getDeploymentInfo();
|
|
379
321
|
console.log('╔══════════════════════════════════════════════════╗');
|
|
380
322
|
console.log(`║ ${PRODUCT_FULL_NAME.padEnd(47)}║`);
|
|
@@ -385,29 +327,27 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
385
327
|
console.log(`[AGENT] Running in CLOUD mode`);
|
|
386
328
|
console.log(`[AGENT] Server: ${deployment.server}`);
|
|
387
329
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
console.log(`[AGENT] Scratchpad: ${scratchpad.length} chars of pending notes`);
|
|
407
|
-
}
|
|
330
|
+
console.log('[AGENT] Features: Memory, Scheduling, Worker Delegation');
|
|
331
|
+
// Initialize orchestrator (indexes filesystem into memory)
|
|
332
|
+
await orchestrator.initialize();
|
|
333
|
+
// Load hub context on startup
|
|
334
|
+
const hubContext = loadHubContext();
|
|
335
|
+
if (hubContext.agentIdentity) {
|
|
336
|
+
console.log('[AGENT] Hub: AGENTS.md loaded');
|
|
337
|
+
}
|
|
338
|
+
if (hubContext.claudeMd) {
|
|
339
|
+
console.log('[AGENT] Hub: CLAUDE.md loaded');
|
|
340
|
+
}
|
|
341
|
+
if (hubContext.landmarks) {
|
|
342
|
+
console.log('[AGENT] Hub: LANDMARKS.md loaded');
|
|
343
|
+
}
|
|
344
|
+
// Check scratchpad for pending plans
|
|
345
|
+
const scratchpad = readScratchpad();
|
|
346
|
+
if (scratchpad && scratchpad.length > 100) {
|
|
347
|
+
console.log(`[AGENT] Scratchpad: ${scratchpad.length} chars of pending notes`);
|
|
408
348
|
}
|
|
409
349
|
// Start preview worker for fast-path asset previews (no LLM)
|
|
410
|
-
|
|
350
|
+
startPreviewWorker({
|
|
411
351
|
verbose: true,
|
|
412
352
|
onAsset: (manifest) => {
|
|
413
353
|
console.log(`[PREVIEW] New asset: ${manifest.name} (${manifest.id})`);
|
|
@@ -425,7 +365,7 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
425
365
|
const runnerType = isCloudMode() ? 'vm' : 'local';
|
|
426
366
|
startHeartbeat({
|
|
427
367
|
runnerType,
|
|
428
|
-
capabilities:
|
|
368
|
+
capabilities: ['orchestrator', 'memory'],
|
|
429
369
|
onError: (error) => {
|
|
430
370
|
// Log only significant errors
|
|
431
371
|
if (error.message.includes('401') || error.message.includes('403')) {
|
|
@@ -449,35 +389,38 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
449
389
|
// Try WebSocket first
|
|
450
390
|
wsClient = new AgentWebSocket();
|
|
451
391
|
const wsConnected = await wsClient.connect();
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
392
|
+
// Progress bars
|
|
393
|
+
orchestrator.setWorkerStatusCallback((workers) => {
|
|
394
|
+
if (wsClient?.connected()) {
|
|
395
|
+
wsClient.sendWorkersUpdate(workers);
|
|
396
|
+
}
|
|
397
|
+
const running = workers.filter(w => w.status === 'running');
|
|
398
|
+
if (running.length > 0) {
|
|
399
|
+
console.log(`[WORKERS] ${running.length} running`);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
// Todo updates - send to user for inline display in chat
|
|
403
|
+
orchestrator.setTodoUpdateCallback((todos) => {
|
|
404
|
+
if (wsClient?.connected()) {
|
|
405
|
+
wsClient.sendTodoUpdate(todos);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
// Gallery updates - send worker assets for UI gallery view
|
|
409
|
+
orchestrator.setGalleryCallback((galleryWorkers) => {
|
|
410
|
+
if (wsClient?.connected()) {
|
|
411
|
+
wsClient.sendGalleryWorkers(galleryWorkers);
|
|
412
|
+
const totalAssets = galleryWorkers.reduce((sum, w) => sum + w.assets.length, 0);
|
|
413
|
+
console.log(`[GALLERY] ${galleryWorkers.length} workers, ${totalAssets} assets`);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
// Worker results - send to user when workers complete
|
|
417
|
+
orchestrator.setWorkerResultCallback((workerId, result) => {
|
|
418
|
+
console.log(`[WORKER DONE] ${workerId}: ${result.slice(0, 100)}...`);
|
|
419
|
+
if (wsClient?.connected()) {
|
|
420
|
+
// Send as response with worker ID as message ID
|
|
421
|
+
wsClient.sendResponse(workerId, `**Worker completed:**\n\n${result}`);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
481
424
|
if (wsConnected) {
|
|
482
425
|
console.log('[AGENT] Using WebSocket for real-time communication\n');
|
|
483
426
|
// Handle messages via WebSocket
|
|
@@ -486,8 +429,7 @@ export async function runAgent(pollInterval = 2000) {
|
|
|
486
429
|
const message = {
|
|
487
430
|
id: wsMsg.id,
|
|
488
431
|
content: wsMsg.content,
|
|
489
|
-
timestamp: wsMsg.timestamp || Date.now()
|
|
490
|
-
apiKey: wsMsg.apiKey // Pass through per-request API key
|
|
432
|
+
timestamp: wsMsg.timestamp || Date.now()
|
|
491
433
|
};
|
|
492
434
|
const response = await processMessage(message);
|
|
493
435
|
// Send response via WebSocket
|
package/dist/api.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -84,7 +84,7 @@ program
|
|
|
84
84
|
console.log(`Config file: ${getConfigPath()}`);
|
|
85
85
|
console.log(`Server URL: ${getServerUrl()}`);
|
|
86
86
|
console.log(`Configured: ${isConfigured() ? 'Yes' : 'No'}`);
|
|
87
|
-
console.log(`
|
|
87
|
+
console.log(`Anthropic API key: ${getAnthropicApiKey() ? 'Configured' : 'Missing'}`);
|
|
88
88
|
if (isConfigured()) {
|
|
89
89
|
const spinner = ora('Checking connection...').start();
|
|
90
90
|
const connected = await checkConnection();
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lia's Internal Task Queue
|
|
3
|
+
*
|
|
4
|
+
* This manages Lia's own todo list - separate from user /todos.
|
|
5
|
+
* Allows async message processing where users can keep sending
|
|
6
|
+
* while Lia works through her queue.
|
|
7
|
+
*/
|
|
8
|
+
export type TaskPriority = 'urgent' | 'high' | 'normal' | 'low';
|
|
9
|
+
export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled';
|
|
10
|
+
export interface LiaTask {
|
|
11
|
+
id: string;
|
|
12
|
+
type: 'user_message' | 'follow_up' | 'scheduled' | 'background';
|
|
13
|
+
content: string;
|
|
14
|
+
priority: TaskPriority;
|
|
15
|
+
status: TaskStatus;
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
startedAt?: Date;
|
|
18
|
+
completedAt?: Date;
|
|
19
|
+
result?: string;
|
|
20
|
+
error?: string;
|
|
21
|
+
metadata?: {
|
|
22
|
+
userId?: string;
|
|
23
|
+
messageId?: string;
|
|
24
|
+
parentTaskId?: string;
|
|
25
|
+
context?: 'personal' | 'team';
|
|
26
|
+
orgId?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface LiaPlan {
|
|
30
|
+
id: string;
|
|
31
|
+
goal: string;
|
|
32
|
+
steps: LiaPlanStep[];
|
|
33
|
+
status: 'planning' | 'executing' | 'completed' | 'failed';
|
|
34
|
+
createdAt: Date;
|
|
35
|
+
completedAt?: Date;
|
|
36
|
+
}
|
|
37
|
+
export interface LiaPlanStep {
|
|
38
|
+
id: string;
|
|
39
|
+
description: string;
|
|
40
|
+
status: TaskStatus;
|
|
41
|
+
taskId?: string;
|
|
42
|
+
notes?: string;
|
|
43
|
+
}
|
|
44
|
+
export type TaskQueueCallback = (task: LiaTask) => void;
|
|
45
|
+
export type PlanCallback = (plan: LiaPlan) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Lia's task queue - manages her internal todo list
|
|
48
|
+
*/
|
|
49
|
+
export declare class LiaTaskQueue {
|
|
50
|
+
private tasks;
|
|
51
|
+
private plans;
|
|
52
|
+
private queue;
|
|
53
|
+
private currentTask;
|
|
54
|
+
private isProcessing;
|
|
55
|
+
private onTaskUpdate?;
|
|
56
|
+
private onPlanUpdate?;
|
|
57
|
+
private processTask?;
|
|
58
|
+
constructor(options?: {
|
|
59
|
+
onTaskUpdate?: TaskQueueCallback;
|
|
60
|
+
onPlanUpdate?: PlanCallback;
|
|
61
|
+
processTask?: (task: LiaTask) => Promise<string>;
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Add a new task to the queue
|
|
65
|
+
*/
|
|
66
|
+
addTask(task: Omit<LiaTask, 'id' | 'status' | 'createdAt'>): LiaTask;
|
|
67
|
+
/**
|
|
68
|
+
* Insert task ID into queue based on priority
|
|
69
|
+
*/
|
|
70
|
+
private insertByPriority;
|
|
71
|
+
/**
|
|
72
|
+
* Start processing the queue
|
|
73
|
+
*/
|
|
74
|
+
startProcessing(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Get the current task being processed
|
|
77
|
+
*/
|
|
78
|
+
getCurrentTask(): LiaTask | null;
|
|
79
|
+
/**
|
|
80
|
+
* Get all pending tasks
|
|
81
|
+
*/
|
|
82
|
+
getPendingTasks(): LiaTask[];
|
|
83
|
+
/**
|
|
84
|
+
* Get recent tasks (last N)
|
|
85
|
+
*/
|
|
86
|
+
getRecentTasks(limit?: number): LiaTask[];
|
|
87
|
+
/**
|
|
88
|
+
* Get task by ID
|
|
89
|
+
*/
|
|
90
|
+
getTask(taskId: string): LiaTask | null;
|
|
91
|
+
/**
|
|
92
|
+
* Cancel a pending task
|
|
93
|
+
*/
|
|
94
|
+
cancelTask(taskId: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Create a plan (breaks down a goal into steps)
|
|
97
|
+
*/
|
|
98
|
+
createPlan(goal: string, steps: string[]): LiaPlan;
|
|
99
|
+
/**
|
|
100
|
+
* Update a plan step
|
|
101
|
+
*/
|
|
102
|
+
updatePlanStep(planId: string, stepId: string, update: Partial<LiaPlanStep>): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Get current plan
|
|
105
|
+
*/
|
|
106
|
+
getCurrentPlan(): LiaPlan | null;
|
|
107
|
+
/**
|
|
108
|
+
* Get all plans
|
|
109
|
+
*/
|
|
110
|
+
getPlans(): LiaPlan[];
|
|
111
|
+
/**
|
|
112
|
+
* Get queue status for display
|
|
113
|
+
*/
|
|
114
|
+
getStatus(): {
|
|
115
|
+
isProcessing: boolean;
|
|
116
|
+
currentTask: LiaTask | null;
|
|
117
|
+
pendingCount: number;
|
|
118
|
+
queuePreview: string[];
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Format tasks as readable todo list (for LLM context)
|
|
122
|
+
*/
|
|
123
|
+
formatAsTodoList(): string;
|
|
124
|
+
}
|