@adhdev/daemon-core 0.7.40 → 0.7.42
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/cli-adapters/provider-cli-adapter.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +3 -0
- package/dist/config/config.d.ts +2 -22
- package/dist/index.js +310 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +310 -34
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/extension-provider-instance.d.ts +1 -0
- package/dist/shared-types.d.ts +2 -0
- package/dist/status/normalize.js +67 -1
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +67 -1
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +1 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/forward.ts +21 -1
- package/src/agent-stream/poller.ts +6 -1
- package/src/cli-adapters/provider-cli-adapter.ts +37 -2
- package/src/commands/cli-manager.ts +45 -2
- package/src/commands/router.ts +1 -0
- package/src/commands/stream-commands.ts +14 -0
- package/src/config/config.d.ts +5 -50
- package/src/config/config.ts +71 -49
- package/src/config/workspaces.d.ts +1 -4
- package/src/providers/cli-provider-instance.ts +18 -5
- package/src/providers/contracts.ts +0 -1
- package/src/providers/extension-provider-instance.ts +27 -0
- package/src/providers/ide-provider-instance.ts +12 -0
- package/src/shared-types.ts +2 -0
- package/src/status/builders.ts +8 -1
- package/src/status/normalize.ts +85 -0
- package/src/status/reporter.ts +31 -2
|
@@ -26,10 +26,13 @@ export declare class CliProviderInstance implements ProviderInstance {
|
|
|
26
26
|
private lastApprovalEventAt;
|
|
27
27
|
private historyWriter;
|
|
28
28
|
readonly instanceId: string;
|
|
29
|
+
private presentationMode;
|
|
29
30
|
constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory);
|
|
30
31
|
init(context: InstanceContext): Promise<void>;
|
|
31
32
|
onTick(): Promise<void>;
|
|
32
33
|
getState(): ProviderState;
|
|
34
|
+
setPresentationMode(mode: 'terminal' | 'chat'): void;
|
|
35
|
+
getPresentationMode(): 'terminal' | 'chat';
|
|
33
36
|
onEvent(event: string, data?: any): void;
|
|
34
37
|
dispose(): void;
|
|
35
38
|
private completedDebounceTimer;
|
package/dist/shared-types.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export interface SessionEntry {
|
|
|
51
51
|
runtimeKey?: string;
|
|
52
52
|
runtimeDisplayName?: string;
|
|
53
53
|
runtimeWorkspaceLabel?: string;
|
|
54
|
+
/** CLI only: active presentation mode */
|
|
55
|
+
mode?: 'terminal' | 'chat';
|
|
54
56
|
runtimeWriteOwner?: RuntimeWriteOwner | null;
|
|
55
57
|
runtimeAttachedClients?: RuntimeAttachedClient[];
|
|
56
58
|
resume?: ProviderResumeCapability;
|
package/dist/status/normalize.js
CHANGED
|
@@ -34,6 +34,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
|
|
|
34
34
|
"thinking",
|
|
35
35
|
"active"
|
|
36
36
|
]);
|
|
37
|
+
var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
|
|
38
|
+
var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
|
|
39
|
+
var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
|
|
40
|
+
var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
|
|
41
|
+
var STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;
|
|
42
|
+
var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
|
|
43
|
+
var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
|
|
44
|
+
var STATUS_MODAL_BUTTON_LIMIT = 120;
|
|
45
|
+
function truncateString(value, maxChars) {
|
|
46
|
+
if (value.length <= maxChars) return value;
|
|
47
|
+
if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
|
|
48
|
+
return `${value.slice(0, maxChars - 12)}...[truncated]`;
|
|
49
|
+
}
|
|
50
|
+
function truncateStringTail(value, maxChars) {
|
|
51
|
+
if (value.length <= maxChars) return value;
|
|
52
|
+
if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
|
|
53
|
+
return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
|
|
54
|
+
}
|
|
55
|
+
function trimStructuredStrings(value, maxChars) {
|
|
56
|
+
if (typeof value === "string") return truncateString(value, maxChars);
|
|
57
|
+
if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
|
|
58
|
+
if (!value || typeof value !== "object") return value;
|
|
59
|
+
return Object.fromEntries(
|
|
60
|
+
Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function estimateBytes(value) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.stringify(value).length;
|
|
66
|
+
} catch {
|
|
67
|
+
return String(value ?? "").length;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function trimMessageForStatus(message, stringLimit) {
|
|
71
|
+
if (!message || typeof message !== "object") return message;
|
|
72
|
+
return trimStructuredStrings(message, stringLimit);
|
|
73
|
+
}
|
|
74
|
+
function trimMessagesForStatus(messages) {
|
|
75
|
+
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
76
|
+
const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
|
|
77
|
+
const kept = [];
|
|
78
|
+
let totalBytes = 0;
|
|
79
|
+
for (let i = recent.length - 1; i >= 0; i -= 1) {
|
|
80
|
+
let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
|
|
81
|
+
let size = estimateBytes(normalized);
|
|
82
|
+
if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
83
|
+
normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
|
|
84
|
+
size = estimateBytes(normalized);
|
|
85
|
+
}
|
|
86
|
+
if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
kept.push(normalized);
|
|
90
|
+
totalBytes += size;
|
|
91
|
+
}
|
|
92
|
+
return kept.reverse();
|
|
93
|
+
}
|
|
37
94
|
function hasApprovalButtons(activeModal) {
|
|
38
95
|
return (activeModal?.buttons?.length ?? 0) > 0;
|
|
39
96
|
}
|
|
@@ -60,7 +117,16 @@ function normalizeActiveChatData(activeChat) {
|
|
|
60
117
|
if (!activeChat) return activeChat;
|
|
61
118
|
return {
|
|
62
119
|
...activeChat,
|
|
63
|
-
status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
|
|
120
|
+
status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
|
|
121
|
+
messages: trimMessagesForStatus(activeChat.messages),
|
|
122
|
+
activeModal: activeChat.activeModal ? {
|
|
123
|
+
message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
|
|
124
|
+
buttons: (activeChat.activeModal.buttons || []).map(
|
|
125
|
+
(button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
|
|
126
|
+
)
|
|
127
|
+
} : activeChat.activeModal,
|
|
128
|
+
terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
|
|
129
|
+
inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
|
|
64
130
|
};
|
|
65
131
|
}
|
|
66
132
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n } as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,CAAC;
|
|
1
|
+
{"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\n// Status snapshots are sent over P2P every 5s, so keep only a recent live window here.\n// Older history is fetched on demand via `chat_history`, and CLI terminals stream via runtime events.\nconst STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;\nconst STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;\nconst STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;\nconst STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;\nconst STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;\nconst STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\nfunction trimMessagesForStatus(messages: unknown[] | null | undefined): unknown[] {\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);\n let size = estimateBytes(normalized);\n\n if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages) as T extends { messages: infer M } ? M : never,\n activeModal: activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : activeChat.activeModal,\n terminalHistory: activeChat.terminalHistory\n ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT)\n : activeChat.terminalHistory,\n inputContent: activeChat.inputContent\n ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT)\n : activeChat.inputContent,\n } as T;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -7,6 +7,63 @@ var WORKING_STATUSES = /* @__PURE__ */ new Set([
|
|
|
7
7
|
"thinking",
|
|
8
8
|
"active"
|
|
9
9
|
]);
|
|
10
|
+
var STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;
|
|
11
|
+
var STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;
|
|
12
|
+
var STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;
|
|
13
|
+
var STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;
|
|
14
|
+
var STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;
|
|
15
|
+
var STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;
|
|
16
|
+
var STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;
|
|
17
|
+
var STATUS_MODAL_BUTTON_LIMIT = 120;
|
|
18
|
+
function truncateString(value, maxChars) {
|
|
19
|
+
if (value.length <= maxChars) return value;
|
|
20
|
+
if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));
|
|
21
|
+
return `${value.slice(0, maxChars - 12)}...[truncated]`;
|
|
22
|
+
}
|
|
23
|
+
function truncateStringTail(value, maxChars) {
|
|
24
|
+
if (value.length <= maxChars) return value;
|
|
25
|
+
if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));
|
|
26
|
+
return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;
|
|
27
|
+
}
|
|
28
|
+
function trimStructuredStrings(value, maxChars) {
|
|
29
|
+
if (typeof value === "string") return truncateString(value, maxChars);
|
|
30
|
+
if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));
|
|
31
|
+
if (!value || typeof value !== "object") return value;
|
|
32
|
+
return Object.fromEntries(
|
|
33
|
+
Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)])
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function estimateBytes(value) {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.stringify(value).length;
|
|
39
|
+
} catch {
|
|
40
|
+
return String(value ?? "").length;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function trimMessageForStatus(message, stringLimit) {
|
|
44
|
+
if (!message || typeof message !== "object") return message;
|
|
45
|
+
return trimStructuredStrings(message, stringLimit);
|
|
46
|
+
}
|
|
47
|
+
function trimMessagesForStatus(messages) {
|
|
48
|
+
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
49
|
+
const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);
|
|
50
|
+
const kept = [];
|
|
51
|
+
let totalBytes = 0;
|
|
52
|
+
for (let i = recent.length - 1; i >= 0; i -= 1) {
|
|
53
|
+
let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);
|
|
54
|
+
let size = estimateBytes(normalized);
|
|
55
|
+
if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
56
|
+
normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);
|
|
57
|
+
size = estimateBytes(normalized);
|
|
58
|
+
}
|
|
59
|
+
if (kept.length > 0 && totalBytes + size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
kept.push(normalized);
|
|
63
|
+
totalBytes += size;
|
|
64
|
+
}
|
|
65
|
+
return kept.reverse();
|
|
66
|
+
}
|
|
10
67
|
function hasApprovalButtons(activeModal) {
|
|
11
68
|
return (activeModal?.buttons?.length ?? 0) > 0;
|
|
12
69
|
}
|
|
@@ -33,7 +90,16 @@ function normalizeActiveChatData(activeChat) {
|
|
|
33
90
|
if (!activeChat) return activeChat;
|
|
34
91
|
return {
|
|
35
92
|
...activeChat,
|
|
36
|
-
status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal })
|
|
93
|
+
status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),
|
|
94
|
+
messages: trimMessagesForStatus(activeChat.messages),
|
|
95
|
+
activeModal: activeChat.activeModal ? {
|
|
96
|
+
message: truncateString(activeChat.activeModal.message || "", STATUS_MODAL_MESSAGE_LIMIT),
|
|
97
|
+
buttons: (activeChat.activeModal.buttons || []).map(
|
|
98
|
+
(button) => truncateString(String(button || ""), STATUS_MODAL_BUTTON_LIMIT)
|
|
99
|
+
)
|
|
100
|
+
} : activeChat.activeModal,
|
|
101
|
+
terminalHistory: activeChat.terminalHistory ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT) : activeChat.terminalHistory,
|
|
102
|
+
inputContent: activeChat.inputContent ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT) : activeChat.inputContent
|
|
37
103
|
};
|
|
38
104
|
}
|
|
39
105
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n } as T;\n}\n"],"mappings":";AAaA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,CAAC;
|
|
1
|
+
{"version":3,"sources":["../../src/status/normalize.ts"],"sourcesContent":["import type { ActiveChatData } from '../providers/provider-instance.js';\n\nexport type ManagedStatus =\n | 'idle'\n | 'generating'\n | 'waiting_approval'\n | 'error'\n | 'stopped'\n | 'starting'\n | 'panel_hidden'\n | 'not_monitored'\n | 'disconnected';\n\nconst WORKING_STATUSES = new Set([\n 'generating',\n 'streaming',\n 'loading',\n 'loading_reference',\n 'thinking',\n 'active',\n]);\n\n// Status snapshots are sent over P2P every 5s, so keep only a recent live window here.\n// Older history is fetched on demand via `chat_history`, and CLI terminals stream via runtime events.\nconst STATUS_ACTIVE_CHAT_MESSAGE_LIMIT = 60;\nconst STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT = 96 * 1024;\nconst STATUS_ACTIVE_CHAT_STRING_LIMIT = 4 * 1024;\nconst STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT = 1024;\nconst STATUS_TERMINAL_HISTORY_LIMIT = 8 * 1024;\nconst STATUS_INPUT_CONTENT_LIMIT = 2 * 1024;\nconst STATUS_MODAL_MESSAGE_LIMIT = 2 * 1024;\nconst STATUS_MODAL_BUTTON_LIMIT = 120;\n\nfunction truncateString(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(0, Math.max(0, maxChars));\n return `${value.slice(0, maxChars - 12)}...[truncated]`;\n}\n\nfunction truncateStringTail(value: string, maxChars: number): string {\n if (value.length <= maxChars) return value;\n if (maxChars <= 12) return value.slice(value.length - Math.max(0, maxChars));\n return `...[truncated]${value.slice(value.length - (maxChars - 12))}`;\n}\n\nfunction trimStructuredStrings(value: unknown, maxChars: number): unknown {\n if (typeof value === 'string') return truncateString(value, maxChars);\n if (Array.isArray(value)) return value.map((item) => trimStructuredStrings(item, maxChars));\n if (!value || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, trimStructuredStrings(nested, maxChars)]),\n );\n}\n\nfunction estimateBytes(value: unknown): number {\n try {\n return JSON.stringify(value).length;\n } catch {\n return String(value ?? '').length;\n }\n}\n\nfunction trimMessageForStatus(message: unknown, stringLimit: number): unknown {\n if (!message || typeof message !== 'object') return message;\n return trimStructuredStrings(message, stringLimit);\n}\n\nfunction trimMessagesForStatus(messages: unknown[] | null | undefined): unknown[] {\n if (!Array.isArray(messages) || messages.length === 0) return [];\n\n const recent = messages.slice(-STATUS_ACTIVE_CHAT_MESSAGE_LIMIT);\n const kept: unknown[] = [];\n let totalBytes = 0;\n\n for (let i = recent.length - 1; i >= 0; i -= 1) {\n let normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_STRING_LIMIT);\n let size = estimateBytes(normalized);\n\n if (size > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n normalized = trimMessageForStatus(recent[i], STATUS_ACTIVE_CHAT_FALLBACK_STRING_LIMIT);\n size = estimateBytes(normalized);\n }\n\n if (kept.length > 0 && (totalBytes + size) > STATUS_ACTIVE_CHAT_TOTAL_BYTES_LIMIT) {\n continue;\n }\n\n kept.push(normalized);\n totalBytes += size;\n }\n\n return kept.reverse();\n}\n\nfunction hasApprovalButtons(activeModal?: { buttons?: unknown[] | null } | null): boolean {\n return (activeModal?.buttons?.length ?? 0) > 0;\n}\n\nexport function normalizeManagedStatus(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): ManagedStatus {\n if (hasApprovalButtons(opts?.activeModal)) return 'waiting_approval';\n\n const normalized = String(status || 'idle').trim().toLowerCase();\n if (normalized === 'waiting_approval') return 'waiting_approval';\n if (WORKING_STATUSES.has(normalized)) return 'generating';\n if (normalized === 'error') return 'error';\n if (normalized === 'stopped') return 'stopped';\n if (normalized === 'starting') return 'starting';\n if (normalized === 'panel_hidden') return 'panel_hidden';\n if (normalized === 'not_monitored') return 'not_monitored';\n if (normalized === 'disconnected') return 'disconnected';\n return 'idle';\n}\n\nexport function isManagedStatusWorking(status?: string | null): boolean {\n return normalizeManagedStatus(status) === 'generating';\n}\n\nexport function isManagedStatusWaiting(\n status?: string | null,\n opts?: { activeModal?: { buttons?: unknown[] | null } | null },\n): boolean {\n return normalizeManagedStatus(status, opts) === 'waiting_approval';\n}\n\nexport function normalizeActiveChatData<T extends ActiveChatData | null | undefined>(\n activeChat: T,\n): T {\n if (!activeChat) return activeChat;\n return {\n ...activeChat,\n status: normalizeManagedStatus(activeChat.status, { activeModal: activeChat.activeModal }),\n messages: trimMessagesForStatus(activeChat.messages) as T extends { messages: infer M } ? M : never,\n activeModal: activeChat.activeModal ? {\n message: truncateString(activeChat.activeModal.message || '', STATUS_MODAL_MESSAGE_LIMIT),\n buttons: (activeChat.activeModal.buttons || []).map((button) =>\n truncateString(String(button || ''), STATUS_MODAL_BUTTON_LIMIT)\n ),\n } : activeChat.activeModal,\n terminalHistory: activeChat.terminalHistory\n ? truncateStringTail(activeChat.terminalHistory, STATUS_TERMINAL_HISTORY_LIMIT)\n : activeChat.terminalHistory,\n inputContent: activeChat.inputContent\n ? truncateString(activeChat.inputContent, STATUS_INPUT_CONTENT_LIMIT)\n : activeChat.inputContent,\n } as T;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -61,6 +61,7 @@ export declare class DaemonStatusReporter {
|
|
|
61
61
|
/** Reset P2P dedup hash — forces next send to transmit even if content unchanged */
|
|
62
62
|
resetP2PHash(): void;
|
|
63
63
|
private ts;
|
|
64
|
+
private summarizeLargePayloadSessions;
|
|
64
65
|
sendUnifiedStatusReport(opts?: {
|
|
65
66
|
p2pOnly?: boolean;
|
|
66
67
|
}): Promise<void>;
|
package/package.json
CHANGED
|
@@ -10,12 +10,20 @@ export function forwardAgentStreamsToIdeInstance(
|
|
|
10
10
|
streams: any[],
|
|
11
11
|
): void {
|
|
12
12
|
const ideInstance = instanceManager.getInstance(`ide:${ideType}`) as
|
|
13
|
-
| {
|
|
13
|
+
| {
|
|
14
|
+
onEvent?: (event: string, payload?: Record<string, unknown>) => void;
|
|
15
|
+
getExtensionTypes?: () => string[];
|
|
16
|
+
}
|
|
14
17
|
| undefined;
|
|
15
18
|
|
|
16
19
|
if (!ideInstance?.onEvent) return;
|
|
17
20
|
|
|
21
|
+
const seenExtensionTypes = new Set<string>();
|
|
22
|
+
|
|
18
23
|
for (const stream of streams) {
|
|
24
|
+
if (typeof stream.agentType === 'string' && stream.agentType) {
|
|
25
|
+
seenExtensionTypes.add(stream.agentType);
|
|
26
|
+
}
|
|
19
27
|
ideInstance.onEvent('stream_update', {
|
|
20
28
|
extensionType: stream.agentType,
|
|
21
29
|
streams: [stream],
|
|
@@ -32,4 +40,16 @@ export function forwardAgentStreamsToIdeInstance(
|
|
|
32
40
|
inputContent: stream.inputContent || '',
|
|
33
41
|
});
|
|
34
42
|
}
|
|
43
|
+
|
|
44
|
+
const extensionTypes = ideInstance.getExtensionTypes?.() || [];
|
|
45
|
+
if (streams.length === 0) {
|
|
46
|
+
ideInstance.onEvent('stream_reset_all');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const extensionType of extensionTypes) {
|
|
51
|
+
if (!seenExtensionTypes.has(extensionType)) {
|
|
52
|
+
ideInstance.onEvent('stream_reset', { extensionType });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
35
55
|
}
|
|
@@ -167,7 +167,12 @@ export class AgentStreamPoller {
|
|
|
167
167
|
} catch { }
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
if (!resolvedActiveSessionId || !parentSessionId)
|
|
170
|
+
if (!resolvedActiveSessionId || !parentSessionId) {
|
|
171
|
+
if (parentSessionId) {
|
|
172
|
+
this.deps.onStreamsUpdated?.(ideType, []);
|
|
173
|
+
}
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
171
176
|
|
|
172
177
|
try {
|
|
173
178
|
await agentStreamManager.syncActiveSession(cdp, parentSessionId);
|
|
@@ -440,6 +440,18 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
440
440
|
this.structuredMessages = [...this.committedMessages];
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
+
private normalizeParsedMessages(parsedMessages: any[]): CliChatMessage[] {
|
|
444
|
+
return parsedMessages
|
|
445
|
+
.filter((message) => message && (message.role === 'user' || message.role === 'assistant'))
|
|
446
|
+
.map((message) => ({
|
|
447
|
+
role: message.role,
|
|
448
|
+
content: typeof message.content === 'string' ? message.content : String(message.content || ''),
|
|
449
|
+
timestamp: typeof message.timestamp === 'number' && Number.isFinite(message.timestamp)
|
|
450
|
+
? message.timestamp
|
|
451
|
+
: Date.now(),
|
|
452
|
+
}));
|
|
453
|
+
}
|
|
454
|
+
|
|
443
455
|
private sliceFromOffset(text: string, start: number): string {
|
|
444
456
|
if (!text) return '';
|
|
445
457
|
if (!Number.isFinite(start) || start <= 0) return text;
|
|
@@ -951,8 +963,15 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
951
963
|
}
|
|
952
964
|
|
|
953
965
|
private commitCurrentTranscript(): void {
|
|
954
|
-
|
|
955
|
-
|
|
966
|
+
const parsed = this.parseCurrentTranscript(
|
|
967
|
+
this.committedMessages,
|
|
968
|
+
this.responseBuffer,
|
|
969
|
+
this.currentTurnScope,
|
|
970
|
+
);
|
|
971
|
+
if (parsed && Array.isArray(parsed.messages)) {
|
|
972
|
+
this.committedMessages = this.normalizeParsedMessages(parsed.messages);
|
|
973
|
+
this.syncMessageViews();
|
|
974
|
+
}
|
|
956
975
|
}
|
|
957
976
|
|
|
958
977
|
// ─── Script Execution ──────────────────────────
|
|
@@ -1003,6 +1022,22 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1003
1022
|
* Called by command handler / dashboard for rich content rendering.
|
|
1004
1023
|
*/
|
|
1005
1024
|
getScriptParsedStatus(): any {
|
|
1025
|
+
const parsed = this.parseCurrentTranscript(
|
|
1026
|
+
this.committedMessages,
|
|
1027
|
+
this.responseBuffer,
|
|
1028
|
+
this.currentTurnScope,
|
|
1029
|
+
);
|
|
1030
|
+
if (parsed && Array.isArray(parsed.messages)) {
|
|
1031
|
+
return {
|
|
1032
|
+
id: parsed.id || 'cli_session',
|
|
1033
|
+
status: parsed.status || this.currentStatus,
|
|
1034
|
+
title: parsed.title || this.cliName,
|
|
1035
|
+
terminalHistory: this.terminalHistory,
|
|
1036
|
+
messages: parsed.messages,
|
|
1037
|
+
activeModal: parsed.activeModal ?? this.activeModal,
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1006
1041
|
const messages = [...this.committedMessages];
|
|
1007
1042
|
return {
|
|
1008
1043
|
id: 'cli_session',
|
|
@@ -90,6 +90,19 @@ export class DaemonCliManager {
|
|
|
90
90
|
return `${cliType}_${hash}`;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
getSessionPresentationMode(sessionId: string): 'terminal' | 'chat' | null {
|
|
94
|
+
if (!sessionId) return null;
|
|
95
|
+
const instance = this.deps.getInstanceManager()?.getInstance(sessionId) as any;
|
|
96
|
+
const mode = instance?.category === 'cli'
|
|
97
|
+
? instance.getPresentationMode?.()
|
|
98
|
+
: null;
|
|
99
|
+
return mode === 'chat' || mode === 'terminal' ? mode : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
isTerminalSession(sessionId: string): boolean {
|
|
103
|
+
return this.getSessionPresentationMode(sessionId) === 'terminal';
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
private persistRecentActivity(entry: {
|
|
94
107
|
kind: 'ide' | 'cli' | 'acp';
|
|
95
108
|
providerType: string;
|
|
@@ -318,6 +331,9 @@ export class DaemonCliManager {
|
|
|
318
331
|
console.log(colorize('cyan', ` 📦 Using provider: ${provider.name} (${provider.type})`));
|
|
319
332
|
}
|
|
320
333
|
|
|
334
|
+
// ─── Resolve launch options → extra args ───
|
|
335
|
+
const resolvedCliArgs = cliArgs;
|
|
336
|
+
|
|
321
337
|
// If InstanceManager exists, manage as CliProviderInstance unified
|
|
322
338
|
const instanceManager = this.deps.getInstanceManager();
|
|
323
339
|
if (provider && instanceManager) {
|
|
@@ -327,7 +343,7 @@ export class DaemonCliManager {
|
|
|
327
343
|
normalizedType,
|
|
328
344
|
cliType,
|
|
329
345
|
resolvedDir,
|
|
330
|
-
|
|
346
|
+
resolvedCliArgs,
|
|
331
347
|
resolvedProvider,
|
|
332
348
|
{},
|
|
333
349
|
false,
|
|
@@ -335,7 +351,7 @@ export class DaemonCliManager {
|
|
|
335
351
|
console.log(colorize('green', ` ✓ CLI started: ${cliInfo.displayName} v${cliInfo.version || 'unknown'} in ${resolvedDir}`));
|
|
336
352
|
} else {
|
|
337
353
|
// Fallback: InstanceManager without directly adapter manage
|
|
338
|
-
const adapter = this.createAdapter(cliType, resolvedDir,
|
|
354
|
+
const adapter = this.createAdapter(cliType, resolvedDir, resolvedCliArgs, key, false);
|
|
339
355
|
try {
|
|
340
356
|
await adapter.spawn();
|
|
341
357
|
} catch (spawnErr: any) {
|
|
@@ -507,6 +523,15 @@ export class DaemonCliManager {
|
|
|
507
523
|
return null;
|
|
508
524
|
}
|
|
509
525
|
|
|
526
|
+
private findAdapterBySessionId(instanceKey?: string): { adapter: CliAdapter; key: string } | null {
|
|
527
|
+
if (!instanceKey) return null;
|
|
528
|
+
let ik = instanceKey;
|
|
529
|
+
const colonIdx = ik.lastIndexOf(':');
|
|
530
|
+
if (colonIdx >= 0) ik = ik.substring(colonIdx + 1);
|
|
531
|
+
const adapter = this.adapters.get(ik);
|
|
532
|
+
return adapter ? { adapter, key: ik } : null;
|
|
533
|
+
}
|
|
534
|
+
|
|
510
535
|
// ─── CLI command handling ────────────────────────────
|
|
511
536
|
|
|
512
537
|
async handleCliCommand(cmd: string, args: any): Promise<CommandResult | null> {
|
|
@@ -563,6 +588,24 @@ export class DaemonCliManager {
|
|
|
563
588
|
}
|
|
564
589
|
return { success: true, cliType, dir, stopped: true, mode };
|
|
565
590
|
}
|
|
591
|
+
case 'set_cli_view_mode': {
|
|
592
|
+
const mode = args?.mode === 'chat' ? 'chat' : 'terminal';
|
|
593
|
+
const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId : '';
|
|
594
|
+
const cliType = args?.cliType || args?.agentType || '';
|
|
595
|
+
const dir = args?.dir || '';
|
|
596
|
+
const found = this.findAdapterBySessionId(targetSessionId)
|
|
597
|
+
|| (cliType ? this.findAdapter(cliType, { instanceKey: targetSessionId, dir }) : null);
|
|
598
|
+
if (!found) {
|
|
599
|
+
return { success: false, error: 'CLI session not found', code: 'CLI_SESSION_NOT_FOUND' };
|
|
600
|
+
}
|
|
601
|
+
const instance = this.deps.getInstanceManager()?.getInstance(found.key);
|
|
602
|
+
if (!(instance instanceof CliProviderInstance)) {
|
|
603
|
+
return { success: false, error: 'CLI instance not found', code: 'CLI_INSTANCE_NOT_FOUND' };
|
|
604
|
+
}
|
|
605
|
+
instance.setPresentationMode(mode);
|
|
606
|
+
this.deps.onStatusChange();
|
|
607
|
+
return { success: true, id: found.key, mode };
|
|
608
|
+
}
|
|
566
609
|
case 'restart_session': {
|
|
567
610
|
const cliType = args?.cliType || args?.agentType || args?.ideType;
|
|
568
611
|
const cfg = loadConfig();
|
package/src/commands/router.ts
CHANGED
|
@@ -7,6 +7,14 @@ import type { CommandResult, CommandHelpers } from './handler.js';
|
|
|
7
7
|
import type { ProviderLoader } from '../providers/provider-loader.js';
|
|
8
8
|
import { LOG } from '../logging/logger.js';
|
|
9
9
|
|
|
10
|
+
function getCliPresentationMode(h: CommandHelpers, targetSessionId?: string): 'terminal' | 'chat' | null {
|
|
11
|
+
if (!targetSessionId) return null;
|
|
12
|
+
const instance = h.ctx.instanceManager?.getInstance(targetSessionId) as any;
|
|
13
|
+
if (instance?.category !== 'cli') return null;
|
|
14
|
+
const mode = instance.getPresentationMode?.();
|
|
15
|
+
return mode === 'chat' || mode === 'terminal' ? mode : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
export async function handleFocusSession(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
11
19
|
if (!h.agentStream || !h.getCdp()) return { success: false, error: 'AgentStream or CDP not available' };
|
|
12
20
|
const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
|
|
@@ -20,6 +28,9 @@ export async function handleFocusSession(h: CommandHelpers, args: any): Promise<
|
|
|
20
28
|
export function handlePtyInput(h: CommandHelpers, args: any): CommandResult {
|
|
21
29
|
const { cliType, data, targetSessionId } = args || {};
|
|
22
30
|
if (!data) return { success: false, error: 'data required' };
|
|
31
|
+
if (getCliPresentationMode(h, targetSessionId) === 'chat') {
|
|
32
|
+
return { success: false, error: 'CLI session is in chat mode', code: 'CLI_VIEW_MODE_NOT_TERMINAL' };
|
|
33
|
+
}
|
|
23
34
|
const adapter = h.getCliAdapter(targetSessionId || cliType);
|
|
24
35
|
if (!adapter || typeof adapter.writeRaw !== 'function') {
|
|
25
36
|
return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
|
|
@@ -31,6 +42,9 @@ export function handlePtyInput(h: CommandHelpers, args: any): CommandResult {
|
|
|
31
42
|
export function handlePtyResize(h: CommandHelpers, args: any): CommandResult {
|
|
32
43
|
const { cliType, cols, rows, force, targetSessionId } = args || {};
|
|
33
44
|
if (!cols || !rows) return { success: false, error: 'cols and rows required' };
|
|
45
|
+
if (getCliPresentationMode(h, targetSessionId) === 'chat') {
|
|
46
|
+
return { success: false, error: 'CLI session is in chat mode', code: 'CLI_VIEW_MODE_NOT_TERMINAL' };
|
|
47
|
+
}
|
|
34
48
|
const adapter = h.getCliAdapter(targetSessionId || cliType);
|
|
35
49
|
if (!adapter || typeof adapter.resize !== 'function') {
|
|
36
50
|
return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
|
package/src/config/config.d.ts
CHANGED
|
@@ -1,65 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ADHDev Launcher — Configuration
|
|
3
3
|
*
|
|
4
|
-
* Manages launcher config,
|
|
4
|
+
* Manages launcher config, machine auth, and user preferences.
|
|
5
5
|
*/
|
|
6
6
|
import type { WorkspaceEntry } from './workspaces.js';
|
|
7
|
-
import type { WorkspaceActivityEntry } from './workspace-activity.js';
|
|
8
7
|
import type { RecentActivityEntry } from './recent-activity.js';
|
|
9
8
|
export type { WorkspaceEntry } from './workspaces.js';
|
|
10
|
-
export type { WorkspaceActivityEntry } from './workspace-activity.js';
|
|
11
9
|
export type { RecentActivityEntry } from './recent-activity.js';
|
|
12
10
|
export interface ADHDevConfig {
|
|
13
11
|
serverUrl: string;
|
|
14
|
-
apiToken: string | null;
|
|
15
|
-
connectionToken: string | null;
|
|
16
12
|
selectedIde: string | null;
|
|
17
13
|
configuredIdes: string[];
|
|
18
14
|
installedExtensions: string[];
|
|
19
|
-
autoConnect: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* @deprecated Not read at runtime. Notification preferences are now managed by:
|
|
22
|
-
* - Web UI layer: useNotificationPrefs (localStorage)
|
|
23
|
-
* - Daemon layer: per-provider settings (approvalAlert, longGeneratingAlert)
|
|
24
|
-
* Kept for backward config compat — will be removed in v0.7+.
|
|
25
|
-
*/
|
|
26
|
-
notifications: boolean;
|
|
27
15
|
userEmail: string | null;
|
|
28
16
|
userName: string | null;
|
|
29
17
|
setupCompleted: boolean;
|
|
30
18
|
setupDate: string | null;
|
|
31
|
-
configuredCLIs: string[];
|
|
32
19
|
enabledIdes: string[];
|
|
33
|
-
recentCliWorkspaces: string[];
|
|
34
20
|
/** Saved workspaces for IDE/CLI/ACP launch (daemon-local) */
|
|
35
21
|
workspaces?: WorkspaceEntry[];
|
|
36
22
|
/** Default workspace id (from workspaces[]) — never used implicitly for launch */
|
|
37
23
|
defaultWorkspaceId?: string | null;
|
|
38
|
-
/** Recently used workspaces (IDE / CLI / ACP / default) for quick resume */
|
|
39
|
-
recentWorkspaceActivity?: WorkspaceActivityEntry[];
|
|
40
24
|
/** Unified recent activity across IDE / CLI / ACP launch flows */
|
|
41
25
|
recentActivity?: RecentActivityEntry[];
|
|
26
|
+
/** Last seen timestamps for live sessions, keyed by sessionId */
|
|
27
|
+
sessionReads?: Record<string, number>;
|
|
28
|
+
/** Last seen completion marker for live sessions, keyed by sessionId */
|
|
29
|
+
sessionReadMarkers?: Record<string, string>;
|
|
42
30
|
machineNickname: string | null;
|
|
43
31
|
/**
|
|
44
32
|
* Stable local machine ID (prefix: `mach_`) — generated locally on first run.
|
|
45
33
|
* Used as daemon instance key (`daemon_<machineId>`) and in status reports.
|
|
46
|
-
* NOT the same as the server-side D1 `machines.id` — see `registeredMachineId`.
|
|
47
34
|
*/
|
|
48
35
|
machineId?: string;
|
|
49
36
|
machineSecret?: string | null;
|
|
50
|
-
/**
|
|
51
|
-
* Server-side D1 `machines.id` — the row ID assigned when daemon registers via
|
|
52
|
-
* `POST /cli/complete`. Corresponds to `machineId` in server DO context
|
|
53
|
-
* (`DaemonConnection.machineId`, `StatusContext.machineId`).
|
|
54
|
-
*
|
|
55
|
-
* Naming differs from server-side `machineId` to avoid confusion with the local
|
|
56
|
-
* `config.machineId` (mach_ prefix) which is a different value.
|
|
57
|
-
*
|
|
58
|
-
* @deprecated Legacy bridge field — will be removed after 2026-04-06.
|
|
59
|
-
* Modern auth flow uses `machineSecret` (adm_) to identify machines.
|
|
60
|
-
*/
|
|
61
|
-
registeredMachineId?: string;
|
|
62
|
-
cliHistory: CliHistoryEntry[];
|
|
63
37
|
providerSettings: Record<string, Record<string, any>>;
|
|
64
38
|
ideSettings: Record<string, {
|
|
65
39
|
extensions?: Record<string, {
|
|
@@ -69,17 +43,6 @@ export interface ADHDevConfig {
|
|
|
69
43
|
disableUpstream?: boolean;
|
|
70
44
|
providerDir?: string;
|
|
71
45
|
}
|
|
72
|
-
export interface CliHistoryEntry {
|
|
73
|
-
category?: 'ide' | 'cli' | 'acp';
|
|
74
|
-
cliType: string;
|
|
75
|
-
dir: string;
|
|
76
|
-
cliArgs?: string[];
|
|
77
|
-
workspace?: string;
|
|
78
|
-
newWindow?: boolean;
|
|
79
|
-
model?: string;
|
|
80
|
-
timestamp: number;
|
|
81
|
-
label?: string;
|
|
82
|
-
}
|
|
83
46
|
export declare function generateMachineId(): string;
|
|
84
47
|
export declare function isStableMachineId(machineId?: string | null): boolean;
|
|
85
48
|
/**
|
|
@@ -110,11 +73,3 @@ export declare function isSetupComplete(): boolean;
|
|
|
110
73
|
* Reset configuration
|
|
111
74
|
*/
|
|
112
75
|
export declare function resetConfig(): void;
|
|
113
|
-
/**
|
|
114
|
-
* Generate a connection token for server authentication
|
|
115
|
-
*/
|
|
116
|
-
export declare function generateConnectionToken(): string;
|
|
117
|
-
/**
|
|
118
|
-
* Add launch to history (max 20, dedup by category+type+dir+args+workspace+model)
|
|
119
|
-
*/
|
|
120
|
-
export declare function addCliHistory(entry: Omit<CliHistoryEntry, 'timestamp'>): void;
|