@adhdev/daemon-core 0.5.3
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/dist/index.d.ts +2662 -0
- package/dist/index.js +11341 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/providers/_builtin/.github/workflows/generate-registry.yml +57 -0
- package/providers/_builtin/COMPATIBILITY.md +217 -0
- package/providers/_builtin/CONTRIBUTING.md +200 -0
- package/providers/_builtin/README.md +119 -0
- package/providers/_builtin/_helpers/index.js +188 -0
- package/providers/_builtin/acp/agentpool/provider.json +54 -0
- package/providers/_builtin/acp/amp/provider.json +52 -0
- package/providers/_builtin/acp/auggie/provider.json +57 -0
- package/providers/_builtin/acp/autodev/provider.json +54 -0
- package/providers/_builtin/acp/autohand/provider.json +52 -0
- package/providers/_builtin/acp/blackbox-ai/provider.json +54 -0
- package/providers/_builtin/acp/claude-agent/provider.json +57 -0
- package/providers/_builtin/acp/cline-acp/provider.json +54 -0
- package/providers/_builtin/acp/codebuddy/provider.json +54 -0
- package/providers/_builtin/acp/codex-cli/provider.json +57 -0
- package/providers/_builtin/acp/corust-agent/provider.json +52 -0
- package/providers/_builtin/acp/crow-cli/provider.json +54 -0
- package/providers/_builtin/acp/cursor-acp/provider.json +54 -0
- package/providers/_builtin/acp/deepagents/provider.json +52 -0
- package/providers/_builtin/acp/dimcode/provider.json +54 -0
- package/providers/_builtin/acp/docker-cagent/provider.json +57 -0
- package/providers/_builtin/acp/factory-droid/provider.json +60 -0
- package/providers/_builtin/acp/fast-agent/provider.json +52 -0
- package/providers/_builtin/acp/gemini-cli/provider.json +114 -0
- package/providers/_builtin/acp/github-copilot/provider.json +54 -0
- package/providers/_builtin/acp/goose/provider.json +57 -0
- package/providers/_builtin/acp/junie/provider.json +52 -0
- package/providers/_builtin/acp/kilo/provider.json +54 -0
- package/providers/_builtin/acp/kimi-cli/provider.json +57 -0
- package/providers/_builtin/acp/minion-code/provider.json +52 -0
- package/providers/_builtin/acp/mistral-vibe/provider.json +57 -0
- package/providers/_builtin/acp/nova/provider.json +54 -0
- package/providers/_builtin/acp/openclaw/provider.json +54 -0
- package/providers/_builtin/acp/opencode/provider.json +52 -0
- package/providers/_builtin/acp/openhands/provider.json +54 -0
- package/providers/_builtin/acp/pi-acp/provider.json +52 -0
- package/providers/_builtin/acp/qoder/provider.json +54 -0
- package/providers/_builtin/acp/qwen-code/provider.json +60 -0
- package/providers/_builtin/acp/stakpak/provider.json +54 -0
- package/providers/_builtin/acp/vtcode/provider.json +54 -0
- package/providers/_builtin/cli/claude-cli/provider.json +100 -0
- package/providers/_builtin/cli/codex-cli/provider.json +89 -0
- package/providers/_builtin/cli/gemini-cli/provider.json +93 -0
- package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +370 -0
- package/providers/_builtin/docs/PROVIDER_GUIDE.md +916 -0
- package/providers/_builtin/extension/cline/provider.json +35 -0
- package/providers/_builtin/extension/cline/scripts/focus_editor.js +48 -0
- package/providers/_builtin/extension/cline/scripts/list_chats.js +100 -0
- package/providers/_builtin/extension/cline/scripts/list_models.js +43 -0
- package/providers/_builtin/extension/cline/scripts/list_modes.js +35 -0
- package/providers/_builtin/extension/cline/scripts/new_session.js +85 -0
- package/providers/_builtin/extension/cline/scripts/open_panel.js +25 -0
- package/providers/_builtin/extension/cline/scripts/read_chat.js +257 -0
- package/providers/_builtin/extension/cline/scripts/resolve_action.js +83 -0
- package/providers/_builtin/extension/cline/scripts/send_message.js +95 -0
- package/providers/_builtin/extension/cline/scripts/set_mode.js +36 -0
- package/providers/_builtin/extension/cline/scripts/set_model.js +36 -0
- package/providers/_builtin/extension/cline/scripts/switch_session.js +206 -0
- package/providers/_builtin/extension/cline/scripts.js +73 -0
- package/providers/_builtin/extension/roo-code/provider.json +35 -0
- package/providers/_builtin/extension/roo-code/scripts.js +659 -0
- package/providers/_builtin/ide/antigravity/provider.json +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +38 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +48 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +57 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +34 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +47 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/switch_session.js +114 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_models.js +61 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_modes.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/scripts.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_mode.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_model.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +114 -0
- package/providers/_builtin/ide/cursor/provider.json +70 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +30 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +13 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +40 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +42 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +20 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +75 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/resolve_action.js +19 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/scripts.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +38 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +81 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +28 -0
- package/providers/_builtin/ide/kiro/provider.json +67 -0
- package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
- package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
- package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
- package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
- package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
- package/providers/_builtin/ide/kiro/scripts.js +62 -0
- package/providers/_builtin/ide/pearai/provider.json +67 -0
- package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/pearai/scripts/list_sessions.js +38 -0
- package/providers/_builtin/ide/pearai/scripts/new_session.js +55 -0
- package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
- package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +62 -0
- package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +49 -0
- package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
- package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
- package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +34 -0
- package/providers/_builtin/ide/pearai/scripts.js +74 -0
- package/providers/_builtin/ide/trae/provider.json +66 -0
- package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
- package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
- package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
- package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
- package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/trae/scripts/send_message.js +69 -0
- package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
- package/providers/_builtin/ide/trae/scripts.js +57 -0
- package/providers/_builtin/ide/vscode/provider.json +64 -0
- package/providers/_builtin/ide/vscode-insiders/provider.json +62 -0
- package/providers/_builtin/ide/vscodium/provider.json +63 -0
- package/providers/_builtin/ide/windsurf/provider.json +53 -0
- package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +30 -0
- package/providers/_builtin/ide/windsurf/scripts/list_chats.js +117 -0
- package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/new_session.js +69 -0
- package/providers/_builtin/ide/windsurf/scripts/open_panel.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts/read_chat.js +297 -0
- package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +68 -0
- package/providers/_builtin/ide/windsurf/scripts/send_message.js +87 -0
- package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/switch_session.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts.js +57 -0
- package/providers/_builtin/registry.json +266 -0
- package/providers/_builtin/validate.js +156 -0
- package/src/agent-stream/index.ts +6 -0
- package/src/agent-stream/manager.ts +286 -0
- package/src/agent-stream/poller.ts +154 -0
- package/src/agent-stream/provider-adapter.ts +138 -0
- package/src/agent-stream/types.ts +61 -0
- package/src/boot/daemon-lifecycle.ts +252 -0
- package/src/cdp/devtools.ts +335 -0
- package/src/cdp/initializer.ts +191 -0
- package/src/cdp/manager.ts +897 -0
- package/src/cdp/scanner.ts +185 -0
- package/src/cdp/setup.ts +150 -0
- package/src/cli-adapter-types.ts +25 -0
- package/src/cli-adapters/provider-cli-adapter.ts +448 -0
- package/src/commands/cdp-commands.ts +208 -0
- package/src/commands/chat-commands.ts +675 -0
- package/src/commands/cli-manager.ts +353 -0
- package/src/commands/handler.ts +328 -0
- package/src/commands/router.ts +258 -0
- package/src/commands/stream-commands.ts +325 -0
- package/src/config/chat-history.ts +211 -0
- package/src/config/config.ts +219 -0
- package/src/daemon/dev-server.ts +2378 -0
- package/src/daemon/scaffold-template.ts +394 -0
- package/src/daemon-core.ts +50 -0
- package/src/detection/cli-detector.ts +89 -0
- package/src/detection/ide-detector.ts +157 -0
- package/src/index.ts +103 -0
- package/src/installer.ts +263 -0
- package/src/ipc-protocol.ts +133 -0
- package/src/launch.ts +433 -0
- package/src/logging/command-log.ts +180 -0
- package/src/logging/logger.ts +316 -0
- package/src/providers/acp-provider-instance.ts +1140 -0
- package/src/providers/cli-provider-instance.ts +207 -0
- package/src/providers/contracts.ts +524 -0
- package/src/providers/extension-provider-instance.ts +156 -0
- package/src/providers/ide-provider-instance.ts +377 -0
- package/src/providers/index.ts +18 -0
- package/src/providers/provider-instance-manager.ts +182 -0
- package/src/providers/provider-instance.ts +112 -0
- package/src/providers/provider-loader.ts +1031 -0
- package/src/providers/status-monitor.ts +125 -0
- package/src/providers/version-archive.ts +266 -0
- package/src/status/reporter.ts +294 -0
- package/src/types.ts +206 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat History Persistence — Persist completed chat messages to local disk
|
|
3
|
+
*
|
|
4
|
+
* Design:
|
|
5
|
+
* - ~/.adhdev/history/{agentType}/YYYY-MM-DD.jsonl
|
|
6
|
+
* - JSONL format (one line = one message, append-friendly)
|
|
7
|
+
* - Track only new messages (hash comparison with previous)
|
|
8
|
+
* - Auto-rotation (delete files older than 30 days)
|
|
9
|
+
* - Async/non-blocking (no impact on chat collection)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as os from 'os';
|
|
15
|
+
|
|
16
|
+
const HISTORY_DIR = path.join(os.homedir(), '.adhdev', 'history');
|
|
17
|
+
const RETAIN_DAYS = 30;
|
|
18
|
+
|
|
19
|
+
interface HistoryMessage {
|
|
20
|
+
ts: string; // ISO timestamp
|
|
21
|
+
receivedAt: number; // epoch ms
|
|
22
|
+
role: 'user' | 'assistant' | 'system';
|
|
23
|
+
content: string;
|
|
24
|
+
agent: string; // e.g. 'antigravity', 'cursor', 'gemini-cli'
|
|
25
|
+
instanceId?: string; // IDE instance UUID (distinguishes windows of the same agent type)
|
|
26
|
+
sessionTitle?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class ChatHistoryWriter {
|
|
30
|
+
/** Last seen message count per agent (deduplication) */
|
|
31
|
+
private lastSeenCounts = new Map<string, number>();
|
|
32
|
+
/** Last seen message hash per agent (deduplication) */
|
|
33
|
+
private lastSeenHashes = new Map<string, Set<string>>();
|
|
34
|
+
private rotated = false;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Append new messages to history
|
|
38
|
+
*
|
|
39
|
+
* @param agentType agent type (e.g. 'antigravity', 'cursor')
|
|
40
|
+
* @param messages Message array received from readChat
|
|
41
|
+
* @param sessionTitle Current session title
|
|
42
|
+
* @param instanceId IDE instance UUID (distinguishes windows of the same agent)
|
|
43
|
+
*/
|
|
44
|
+
appendNewMessages(
|
|
45
|
+
agentType: string,
|
|
46
|
+
messages: Array<{ role: string; content: string; receivedAt?: number }>,
|
|
47
|
+
sessionTitle?: string,
|
|
48
|
+
instanceId?: string,
|
|
49
|
+
): void {
|
|
50
|
+
if (!messages || messages.length === 0) return;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// dedup key: agentType + instanceId
|
|
54
|
+
const dedupKey = instanceId ? `${agentType}:${instanceId}` : agentType;
|
|
55
|
+
let seenHashes = this.lastSeenHashes.get(dedupKey);
|
|
56
|
+
if (!seenHashes) {
|
|
57
|
+
seenHashes = new Set<string>();
|
|
58
|
+
this.lastSeenHashes.set(dedupKey, seenHashes);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Filter new messages
|
|
62
|
+
const newMessages: HistoryMessage[] = [];
|
|
63
|
+
for (const msg of messages) {
|
|
64
|
+
const hash = `${msg.role}:${(msg.content || '').slice(0, 50)}`;
|
|
65
|
+
if (seenHashes.has(hash)) continue;
|
|
66
|
+
seenHashes.add(hash);
|
|
67
|
+
newMessages.push({
|
|
68
|
+
ts: new Date(msg.receivedAt || Date.now()).toISOString(),
|
|
69
|
+
receivedAt: msg.receivedAt || Date.now(),
|
|
70
|
+
role: msg.role as 'user' | 'assistant' | 'system',
|
|
71
|
+
content: msg.content || '',
|
|
72
|
+
agent: agentType,
|
|
73
|
+
instanceId,
|
|
74
|
+
sessionTitle,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (newMessages.length === 0) return;
|
|
79
|
+
|
|
80
|
+
// Append to file — separate file if instanceId exists
|
|
81
|
+
const dir = path.join(HISTORY_DIR, this.sanitize(agentType));
|
|
82
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
|
+
|
|
84
|
+
const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
|
85
|
+
const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : '';
|
|
86
|
+
const filePath = path.join(dir, `${filePrefix}${date}.jsonl`);
|
|
87
|
+
const lines = newMessages.map(m => JSON.stringify(m)).join('\n') + '\n';
|
|
88
|
+
fs.appendFileSync(filePath, lines, 'utf-8');
|
|
89
|
+
|
|
90
|
+
// Detect session switch — reset hash if message count decreases
|
|
91
|
+
const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
|
|
92
|
+
if (messages.length < prevCount * 0.5 && prevCount > 3) {
|
|
93
|
+
seenHashes.clear();
|
|
94
|
+
for (const msg of messages) {
|
|
95
|
+
seenHashes.add(`${msg.role}:${(msg.content || '').slice(0, 50)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
this.lastSeenCounts.set(dedupKey, messages.length);
|
|
99
|
+
|
|
100
|
+
// Rotate only once on first call
|
|
101
|
+
if (!this.rotated) {
|
|
102
|
+
this.rotated = true;
|
|
103
|
+
this.rotateOldFiles().catch(() => {});
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// Ignore history save failures (must not affect main functionality)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Called when agent session is explicitly changed */
|
|
111
|
+
onSessionChange(agentType: string): void {
|
|
112
|
+
this.lastSeenHashes.delete(agentType);
|
|
113
|
+
this.lastSeenCounts.delete(agentType);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Delete history files older than 30 days */
|
|
117
|
+
private async rotateOldFiles(): Promise<void> {
|
|
118
|
+
try {
|
|
119
|
+
if (!fs.existsSync(HISTORY_DIR)) return;
|
|
120
|
+
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1000;
|
|
121
|
+
|
|
122
|
+
const agentDirs = fs.readdirSync(HISTORY_DIR, { withFileTypes: true })
|
|
123
|
+
.filter(d => d.isDirectory());
|
|
124
|
+
|
|
125
|
+
for (const dir of agentDirs) {
|
|
126
|
+
const dirPath = path.join(HISTORY_DIR, dir.name);
|
|
127
|
+
const files = fs.readdirSync(dirPath)
|
|
128
|
+
.filter(f => f.endsWith('.jsonl'));
|
|
129
|
+
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
const filePath = path.join(dirPath, file);
|
|
132
|
+
const stat = fs.statSync(filePath);
|
|
133
|
+
if (stat.mtimeMs < cutoff) {
|
|
134
|
+
fs.unlinkSync(filePath);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
// Ignore rotate failure
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Allow only filename-safe characters */
|
|
144
|
+
private sanitize(name: string): string {
|
|
145
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Read history (static — called from P2P commands)
|
|
151
|
+
*
|
|
152
|
+
* Read JSONL files in reverse order, returning most recent messages first.
|
|
153
|
+
* When instanceId is specified, reads only that instance file.
|
|
154
|
+
* Offset/limit-based paging.
|
|
155
|
+
*/
|
|
156
|
+
export function readChatHistory(
|
|
157
|
+
agentType: string,
|
|
158
|
+
offset: number = 0,
|
|
159
|
+
limit: number = 30,
|
|
160
|
+
instanceId?: string,
|
|
161
|
+
): { messages: HistoryMessage[]; hasMore: boolean } {
|
|
162
|
+
try {
|
|
163
|
+
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
164
|
+
const dir = path.join(HISTORY_DIR, sanitized);
|
|
165
|
+
if (!fs.existsSync(dir)) return { messages: [], hasMore: false };
|
|
166
|
+
|
|
167
|
+
// JSONL file list — only matching prefix if instanceId is specified
|
|
168
|
+
const sanitizedInstance = instanceId?.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
169
|
+
const files = fs.readdirSync(dir)
|
|
170
|
+
.filter(f => {
|
|
171
|
+
if (!f.endsWith('.jsonl')) return false;
|
|
172
|
+
if (sanitizedInstance) {
|
|
173
|
+
return f.startsWith(`${sanitizedInstance}_`);
|
|
174
|
+
}
|
|
175
|
+
// Without instanceId, only files without prefix (legacy compatible)
|
|
176
|
+
return !f.includes('_') || f.match(/^\d{4}-\d{2}-\d{2}\.jsonl$/);
|
|
177
|
+
})
|
|
178
|
+
.sort()
|
|
179
|
+
.reverse();
|
|
180
|
+
|
|
181
|
+
// Read lines from all files (reverse order)
|
|
182
|
+
const allMessages: HistoryMessage[] = [];
|
|
183
|
+
const needed = offset + limit + 1; // hasMore check +1
|
|
184
|
+
|
|
185
|
+
for (const file of files) {
|
|
186
|
+
if (allMessages.length >= needed) break;
|
|
187
|
+
const filePath = path.join(dir, file);
|
|
188
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
189
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
190
|
+
|
|
191
|
+
// Parse in reverse order
|
|
192
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
193
|
+
if (allMessages.length >= needed) break;
|
|
194
|
+
try {
|
|
195
|
+
allMessages.push(JSON.parse(lines[i]));
|
|
196
|
+
} catch { /* skip invalid lines */ }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// offset/limit apply
|
|
201
|
+
const sliced = allMessages.slice(offset, offset + limit);
|
|
202
|
+
const hasMore = allMessages.length > offset + limit;
|
|
203
|
+
|
|
204
|
+
// Sort in chronological order (top→bottom = oldest→newest)
|
|
205
|
+
sliced.reverse();
|
|
206
|
+
|
|
207
|
+
return { messages: sliced, hasMore };
|
|
208
|
+
} catch {
|
|
209
|
+
return { messages: [], hasMore: false };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADHDev Launcher — Configuration
|
|
3
|
+
*
|
|
4
|
+
* Manages launcher config, server connection tokens, and user preferences.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'fs';
|
|
10
|
+
|
|
11
|
+
export interface ADHDevConfig {
|
|
12
|
+
// Server connection
|
|
13
|
+
serverUrl: string;
|
|
14
|
+
apiToken: string | null;
|
|
15
|
+
connectionToken: string | null;
|
|
16
|
+
|
|
17
|
+
// Selected IDE (primary)
|
|
18
|
+
selectedIde: string | null;
|
|
19
|
+
|
|
20
|
+
// All configured IDEs (multiple)
|
|
21
|
+
configuredIdes: string[];
|
|
22
|
+
|
|
23
|
+
// Installed extensions
|
|
24
|
+
installedExtensions: string[];
|
|
25
|
+
|
|
26
|
+
// User preferences
|
|
27
|
+
autoConnect: boolean;
|
|
28
|
+
notifications: boolean;
|
|
29
|
+
|
|
30
|
+
// Auth
|
|
31
|
+
userEmail: string | null;
|
|
32
|
+
userName: string | null;
|
|
33
|
+
|
|
34
|
+
// Setup state
|
|
35
|
+
setupCompleted: boolean;
|
|
36
|
+
setupDate: string | null;
|
|
37
|
+
|
|
38
|
+
// Configured CLI agents
|
|
39
|
+
configuredCLIs: string[];
|
|
40
|
+
|
|
41
|
+
// Daemon: which IDEs to connect (empty = all)
|
|
42
|
+
enabledIdes: string[];
|
|
43
|
+
recentCliWorkspaces: string[];
|
|
44
|
+
|
|
45
|
+
// Machine nickname (user-customizable label for this machine)
|
|
46
|
+
machineNickname: string | null;
|
|
47
|
+
|
|
48
|
+
// CLI launch history
|
|
49
|
+
cliHistory: CliHistoryEntry[];
|
|
50
|
+
|
|
51
|
+
// Per-provider user config (public setting values)
|
|
52
|
+
providerSettings: Record<string, Record<string, any>>;
|
|
53
|
+
|
|
54
|
+
// Per-IDE extension config (per-IDE on/off control)
|
|
55
|
+
ideSettings: Record<string, {
|
|
56
|
+
extensions?: Record<string, { enabled: boolean }>;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface CliHistoryEntry {
|
|
61
|
+
cliType: string;
|
|
62
|
+
dir: string;
|
|
63
|
+
cliArgs?: string[];
|
|
64
|
+
timestamp: number;
|
|
65
|
+
label?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const DEFAULT_CONFIG: ADHDevConfig = {
|
|
69
|
+
serverUrl: 'https://api.adhf.dev',
|
|
70
|
+
apiToken: null,
|
|
71
|
+
connectionToken: null,
|
|
72
|
+
selectedIde: null,
|
|
73
|
+
configuredIdes: [],
|
|
74
|
+
installedExtensions: [],
|
|
75
|
+
autoConnect: true,
|
|
76
|
+
notifications: true,
|
|
77
|
+
userEmail: null,
|
|
78
|
+
userName: null,
|
|
79
|
+
setupCompleted: false,
|
|
80
|
+
setupDate: null,
|
|
81
|
+
configuredCLIs: [],
|
|
82
|
+
enabledIdes: [],
|
|
83
|
+
recentCliWorkspaces: [],
|
|
84
|
+
machineNickname: null,
|
|
85
|
+
cliHistory: [],
|
|
86
|
+
providerSettings: {},
|
|
87
|
+
ideSettings: {},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the config directory path
|
|
92
|
+
*/
|
|
93
|
+
export function getConfigDir(): string {
|
|
94
|
+
const dir = join(homedir(), '.adhdev');
|
|
95
|
+
if (!existsSync(dir)) {
|
|
96
|
+
mkdirSync(dir, { recursive: true });
|
|
97
|
+
}
|
|
98
|
+
return dir;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the config file path
|
|
103
|
+
*/
|
|
104
|
+
function getConfigPath(): string {
|
|
105
|
+
return join(getConfigDir(), 'config.json');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Load configuration from disk
|
|
110
|
+
*/
|
|
111
|
+
export function loadConfig(): ADHDevConfig {
|
|
112
|
+
const configPath = getConfigPath();
|
|
113
|
+
|
|
114
|
+
if (!existsSync(configPath)) {
|
|
115
|
+
return { ...DEFAULT_CONFIG };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
120
|
+
const parsed = JSON.parse(raw);
|
|
121
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
122
|
+
} catch {
|
|
123
|
+
return { ...DEFAULT_CONFIG };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Save configuration to disk
|
|
129
|
+
*/
|
|
130
|
+
export function saveConfig(config: ADHDevConfig): void {
|
|
131
|
+
const configPath = getConfigPath();
|
|
132
|
+
const dir = getConfigDir();
|
|
133
|
+
|
|
134
|
+
if (!existsSync(dir)) {
|
|
135
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
139
|
+
try { chmodSync(configPath, 0o600); } catch { /* Windows etc. not supported */ }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Update specific config fields
|
|
144
|
+
*/
|
|
145
|
+
export function updateConfig(updates: Partial<ADHDevConfig>): ADHDevConfig {
|
|
146
|
+
const config = loadConfig();
|
|
147
|
+
const updated = { ...config, ...updates };
|
|
148
|
+
saveConfig(updated);
|
|
149
|
+
return updated;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Mark setup as completed
|
|
154
|
+
*/
|
|
155
|
+
export function markSetupComplete(
|
|
156
|
+
ideId: string | string[],
|
|
157
|
+
extensions: string[]
|
|
158
|
+
): ADHDevConfig {
|
|
159
|
+
const ideIds = Array.isArray(ideId) ? ideId : [ideId];
|
|
160
|
+
return updateConfig({
|
|
161
|
+
selectedIde: ideIds[0],
|
|
162
|
+
configuredIdes: ideIds,
|
|
163
|
+
installedExtensions: extensions,
|
|
164
|
+
setupCompleted: true,
|
|
165
|
+
setupDate: new Date().toISOString(),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check if setup has been completed before
|
|
171
|
+
*/
|
|
172
|
+
export function isSetupComplete(): boolean {
|
|
173
|
+
const config = loadConfig();
|
|
174
|
+
return config.setupCompleted;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Reset configuration
|
|
179
|
+
*/
|
|
180
|
+
export function resetConfig(): void {
|
|
181
|
+
saveConfig({ ...DEFAULT_CONFIG });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Generate a connection token for server authentication
|
|
186
|
+
*/
|
|
187
|
+
export function generateConnectionToken(): string {
|
|
188
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
189
|
+
let token = 'db_';
|
|
190
|
+
for (let i = 0; i < 32; i++) {
|
|
191
|
+
token += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
192
|
+
}
|
|
193
|
+
return token;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Add CLI launch to history (max 20, dedup by cliType+dir+args)
|
|
197
|
+
*/
|
|
198
|
+
export function addCliHistory(entry: Omit<CliHistoryEntry, 'timestamp'>): void {
|
|
199
|
+
const config = loadConfig();
|
|
200
|
+
const history = config.cliHistory || [];
|
|
201
|
+
const argsKey = (entry.cliArgs || []).join(' ');
|
|
202
|
+
|
|
203
|
+
// Remove duplicate (same cliType + dir + args)
|
|
204
|
+
const filtered = history.filter(h => {
|
|
205
|
+
const hArgsKey = (h.cliArgs || []).join(' ');
|
|
206
|
+
return !(h.cliType === entry.cliType && h.dir === entry.dir && hArgsKey === argsKey);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Add to front
|
|
210
|
+
filtered.unshift({
|
|
211
|
+
...entry,
|
|
212
|
+
timestamp: Date.now(),
|
|
213
|
+
label: entry.label || `${entry.cliType} · ${entry.dir.split('/').filter(Boolean).pop() || 'root'}${argsKey ? ` (${argsKey})` : ''}`,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Keep max 20
|
|
217
|
+
config.cliHistory = filtered.slice(0, 20);
|
|
218
|
+
saveConfig(config);
|
|
219
|
+
}
|