@adhdev/daemon-core 0.8.19 → 0.8.20
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/config/config.d.ts +1 -10
- package/dist/config/recent-activity.d.ts +7 -7
- package/dist/config/saved-sessions.d.ts +4 -4
- package/dist/config/state-store.d.ts +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +129 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +126 -61
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/cli-manager.ts +5 -4
- package/src/commands/router.ts +11 -10
- package/src/config/config.d.ts +1 -10
- package/src/config/config.ts +47 -29
- package/src/config/recent-activity.ts +16 -16
- package/src/config/saved-sessions.ts +9 -9
- package/src/config/state-store.ts +94 -0
- package/src/index.ts +4 -0
- package/src/status/snapshot.ts +5 -3
package/dist/config/config.d.ts
CHANGED
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
* Manages launcher config, machine auth, and user preferences.
|
|
5
5
|
*/
|
|
6
6
|
import type { WorkspaceEntry } from './workspaces.js';
|
|
7
|
-
import type { RecentActivityEntry } from './recent-activity.js';
|
|
8
|
-
import type { SavedProviderSessionEntry } from './saved-sessions.js';
|
|
9
7
|
export type { WorkspaceEntry } from './workspaces.js';
|
|
10
8
|
export type { RecentActivityEntry } from './recent-activity.js';
|
|
11
9
|
export type { SavedProviderSessionEntry } from './saved-sessions.js';
|
|
10
|
+
export type { DaemonState } from './state-store.js';
|
|
12
11
|
export interface ADHDevConfig {
|
|
13
12
|
serverUrl: string;
|
|
14
13
|
selectedIde: string | null;
|
|
@@ -23,14 +22,6 @@ export interface ADHDevConfig {
|
|
|
23
22
|
workspaces?: WorkspaceEntry[];
|
|
24
23
|
/** Default workspace id (from workspaces[]) — never used implicitly for launch */
|
|
25
24
|
defaultWorkspaceId?: string | null;
|
|
26
|
-
/** Unified recent activity across IDE / CLI / ACP launch flows */
|
|
27
|
-
recentActivity?: RecentActivityEntry[];
|
|
28
|
-
/** Persistent resume-capable provider sessions keyed by providerSessionId */
|
|
29
|
-
savedProviderSessions?: SavedProviderSessionEntry[];
|
|
30
|
-
/** Last seen timestamps for live sessions, keyed by sessionId */
|
|
31
|
-
sessionReads?: Record<string, number>;
|
|
32
|
-
/** Last seen completion marker for live sessions, keyed by sessionId */
|
|
33
|
-
sessionReadMarkers?: Record<string, string>;
|
|
34
25
|
machineNickname: string | null;
|
|
35
26
|
/**
|
|
36
27
|
* Stable local machine ID (prefix: `mach_`) — generated locally on first run.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - deduped by provider session when available, else by kind + providerType + workspace
|
|
7
7
|
* - used only for quick-launch shortcuts
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { DaemonState } from './state-store.js';
|
|
10
10
|
export interface RecentActivityEntry {
|
|
11
11
|
id: string;
|
|
12
12
|
kind: 'ide' | 'cli' | 'acp';
|
|
@@ -20,10 +20,10 @@ export interface RecentActivityEntry {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function buildRecentActivityKey(entry: Pick<RecentActivityEntry, 'kind' | 'providerType' | 'workspace'>): string;
|
|
22
22
|
export declare function buildRecentActivityKeyForEntry(entry: Pick<RecentActivityEntry, 'kind' | 'providerType' | 'workspace' | 'providerSessionId'>): string;
|
|
23
|
-
export declare function appendRecentActivity(
|
|
23
|
+
export declare function appendRecentActivity(state: DaemonState, entry: Omit<RecentActivityEntry, 'id' | 'lastUsedAt'> & {
|
|
24
24
|
lastUsedAt?: number;
|
|
25
|
-
}):
|
|
26
|
-
export declare function getRecentActivity(
|
|
27
|
-
export declare function getSessionSeenAt(
|
|
28
|
-
export declare function getSessionSeenMarker(
|
|
29
|
-
export declare function markSessionSeen(
|
|
25
|
+
}): DaemonState;
|
|
26
|
+
export declare function getRecentActivity(state: DaemonState, limit?: number): RecentActivityEntry[];
|
|
27
|
+
export declare function getSessionSeenAt(state: DaemonState, sessionId: string): number;
|
|
28
|
+
export declare function getSessionSeenMarker(state: DaemonState, sessionId: string): string;
|
|
29
|
+
export declare function markSessionSeen(state: DaemonState, sessionId: string, seenAt?: number, completionMarker?: string | null): DaemonState;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DaemonState } from './state-store.js';
|
|
2
2
|
export interface SavedProviderSessionEntry {
|
|
3
3
|
id: string;
|
|
4
4
|
kind: 'cli' | 'acp';
|
|
@@ -12,11 +12,11 @@ export interface SavedProviderSessionEntry {
|
|
|
12
12
|
lastUsedAt: number;
|
|
13
13
|
}
|
|
14
14
|
export declare function buildSavedProviderSessionKey(providerSessionId: string): string;
|
|
15
|
-
export declare function upsertSavedProviderSession(
|
|
15
|
+
export declare function upsertSavedProviderSession(state: DaemonState, entry: Omit<SavedProviderSessionEntry, 'id' | 'createdAt' | 'lastUsedAt'> & {
|
|
16
16
|
createdAt?: number;
|
|
17
17
|
lastUsedAt?: number;
|
|
18
|
-
}):
|
|
19
|
-
export declare function getSavedProviderSessions(
|
|
18
|
+
}): DaemonState;
|
|
19
|
+
export declare function getSavedProviderSessions(state: DaemonState, filters?: {
|
|
20
20
|
providerType?: string;
|
|
21
21
|
kind?: SavedProviderSessionEntry['kind'];
|
|
22
22
|
}): SavedProviderSessionEntry[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADHDev State Store — Runtime state persistence
|
|
3
|
+
*
|
|
4
|
+
* Separates volatile runtime state (sessions, activity, read markers)
|
|
5
|
+
* from static configuration (config.json).
|
|
6
|
+
*
|
|
7
|
+
* State is stored in ~/.adhdev/state.json
|
|
8
|
+
*/
|
|
9
|
+
import type { RecentActivityEntry } from './recent-activity.js';
|
|
10
|
+
import type { SavedProviderSessionEntry } from './saved-sessions.js';
|
|
11
|
+
export interface DaemonState {
|
|
12
|
+
/** Unified recent activity across IDE / CLI / ACP launch flows */
|
|
13
|
+
recentActivity: RecentActivityEntry[];
|
|
14
|
+
/** Persistent resume-capable provider sessions keyed by providerSessionId */
|
|
15
|
+
savedProviderSessions: SavedProviderSessionEntry[];
|
|
16
|
+
/** Last seen timestamps for live sessions, keyed by sessionId */
|
|
17
|
+
sessionReads: Record<string, number>;
|
|
18
|
+
/** Last seen completion marker for live sessions, keyed by sessionId */
|
|
19
|
+
sessionReadMarkers: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Load runtime state from disk
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadState(): DaemonState;
|
|
25
|
+
/**
|
|
26
|
+
* Save runtime state to disk
|
|
27
|
+
*/
|
|
28
|
+
export declare function saveState(state: DaemonState): void;
|
|
29
|
+
/**
|
|
30
|
+
* Reset runtime state
|
|
31
|
+
*/
|
|
32
|
+
export declare function resetState(): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export { appendRecentActivity, getRecentActivity } from './config/recent-activit
|
|
|
22
22
|
export type { RecentActivityEntry } from './config/recent-activity.js';
|
|
23
23
|
export { getSavedProviderSessions, upsertSavedProviderSession } from './config/saved-sessions.js';
|
|
24
24
|
export type { SavedProviderSessionEntry } from './config/saved-sessions.js';
|
|
25
|
+
export { loadState, saveState, resetState } from './config/state-store.js';
|
|
26
|
+
export type { DaemonState } from './config/state-store.js';
|
|
25
27
|
export { detectIDEs } from './detection/ide-detector.js';
|
|
26
28
|
export type { IDEInfo } from './detection/ide-detector.js';
|
|
27
29
|
export { detectCLIs } from './detection/cli-detector.js';
|
package/dist/index.js
CHANGED
|
@@ -61,14 +61,6 @@ function asBoolean(value, fallback) {
|
|
|
61
61
|
}
|
|
62
62
|
function normalizeConfig(raw) {
|
|
63
63
|
const parsed = isPlainObject(raw) ? raw : {};
|
|
64
|
-
const legacySessionReads = isPlainObject(parsed.recentSessionReads) ? parsed.recentSessionReads : {};
|
|
65
|
-
const sessionReads = isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {};
|
|
66
|
-
const mergedSessionReads = Object.fromEntries(
|
|
67
|
-
Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
|
|
68
|
-
);
|
|
69
|
-
const sessionReadMarkers = Object.fromEntries(
|
|
70
|
-
Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
|
|
71
|
-
);
|
|
72
64
|
return {
|
|
73
65
|
serverUrl: typeof parsed.serverUrl === "string" && parsed.serverUrl.trim() ? parsed.serverUrl : DEFAULT_CONFIG.serverUrl,
|
|
74
66
|
selectedIde: asNullableString(parsed.selectedIde),
|
|
@@ -81,10 +73,6 @@ function normalizeConfig(raw) {
|
|
|
81
73
|
enabledIdes: asStringArray(parsed.enabledIdes),
|
|
82
74
|
workspaces: Array.isArray(parsed.workspaces) ? parsed.workspaces : [],
|
|
83
75
|
defaultWorkspaceId: asNullableString(parsed.defaultWorkspaceId) ?? asNullableString(parsed.activeWorkspaceId),
|
|
84
|
-
recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
|
|
85
|
-
savedProviderSessions: Array.isArray(parsed.savedProviderSessions) ? parsed.savedProviderSessions : [],
|
|
86
|
-
sessionReads: mergedSessionReads,
|
|
87
|
-
sessionReadMarkers,
|
|
88
76
|
machineNickname: asNullableString(parsed.machineNickname),
|
|
89
77
|
machineId: asOptionalString(parsed.machineId),
|
|
90
78
|
machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
|
|
@@ -125,6 +113,30 @@ function getConfigDir() {
|
|
|
125
113
|
function getConfigPath() {
|
|
126
114
|
return (0, import_path.join)(getConfigDir(), "config.json");
|
|
127
115
|
}
|
|
116
|
+
function migrateStateToStateFile(raw) {
|
|
117
|
+
const statePath = (0, import_path.join)(getConfigDir(), "state.json");
|
|
118
|
+
if ((0, import_fs.existsSync)(statePath)) return;
|
|
119
|
+
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
120
|
+
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
121
|
+
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
122
|
+
const sessionReads = isPlainObject(raw.sessionReads) ? raw.sessionReads : {};
|
|
123
|
+
const sessionReadMarkers = isPlainObject(raw.sessionReadMarkers) ? raw.sessionReadMarkers : {};
|
|
124
|
+
const hasData = recentActivity.length > 0 || savedProviderSessions.length > 0 || Object.keys(sessionReads).length > 0 || Object.keys(legacySessionReads).length > 0 || Object.keys(sessionReadMarkers).length > 0;
|
|
125
|
+
if (!hasData) return;
|
|
126
|
+
const mergedReads = Object.fromEntries(
|
|
127
|
+
Object.entries({ ...legacySessionReads, ...sessionReads }).filter(([, v]) => typeof v === "number" && Number.isFinite(v))
|
|
128
|
+
);
|
|
129
|
+
const cleanedMarkers = Object.fromEntries(
|
|
130
|
+
Object.entries(sessionReadMarkers).filter(([, v]) => typeof v === "string")
|
|
131
|
+
);
|
|
132
|
+
const state = {
|
|
133
|
+
recentActivity,
|
|
134
|
+
savedProviderSessions,
|
|
135
|
+
sessionReads: mergedReads,
|
|
136
|
+
sessionReadMarkers: cleanedMarkers
|
|
137
|
+
};
|
|
138
|
+
(0, import_fs.writeFileSync)(statePath, JSON.stringify(state, null, 2), { encoding: "utf-8", mode: 384 });
|
|
139
|
+
}
|
|
128
140
|
function loadConfig() {
|
|
129
141
|
const configPath = getConfigPath();
|
|
130
142
|
if (!(0, import_fs.existsSync)(configPath)) {
|
|
@@ -138,6 +150,7 @@ function loadConfig() {
|
|
|
138
150
|
try {
|
|
139
151
|
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
140
152
|
const parsed = JSON.parse(raw);
|
|
153
|
+
migrateStateToStateFile(parsed);
|
|
141
154
|
const normalizedInput = normalizeConfig(parsed);
|
|
142
155
|
const ensured = ensureMachineId(normalizedInput);
|
|
143
156
|
const normalized = ensured.config;
|
|
@@ -209,10 +222,6 @@ var init_config = __esm({
|
|
|
209
222
|
enabledIdes: [],
|
|
210
223
|
workspaces: [],
|
|
211
224
|
defaultWorkspaceId: null,
|
|
212
|
-
recentActivity: [],
|
|
213
|
-
savedProviderSessions: [],
|
|
214
|
-
sessionReads: {},
|
|
215
|
-
sessionReadMarkers: {},
|
|
216
225
|
machineNickname: null,
|
|
217
226
|
machineId: void 0,
|
|
218
227
|
machineSecret: null,
|
|
@@ -2604,6 +2613,7 @@ __export(index_exports, {
|
|
|
2604
2613
|
launchWithCdp: () => launchWithCdp,
|
|
2605
2614
|
listHostedCliRuntimes: () => listHostedCliRuntimes,
|
|
2606
2615
|
loadConfig: () => loadConfig,
|
|
2616
|
+
loadState: () => loadState,
|
|
2607
2617
|
logCommand: () => logCommand,
|
|
2608
2618
|
markSetupComplete: () => markSetupComplete,
|
|
2609
2619
|
maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
|
|
@@ -2613,7 +2623,9 @@ __export(index_exports, {
|
|
|
2613
2623
|
readChatHistory: () => readChatHistory,
|
|
2614
2624
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
2615
2625
|
resetConfig: () => resetConfig,
|
|
2626
|
+
resetState: () => resetState,
|
|
2616
2627
|
saveConfig: () => saveConfig,
|
|
2628
|
+
saveState: () => saveState,
|
|
2617
2629
|
setLogLevel: () => setLogLevel,
|
|
2618
2630
|
setupIdeInstance: () => setupIdeInstance,
|
|
2619
2631
|
shutdownDaemonComponents: () => shutdownDaemonComponents,
|
|
@@ -2812,35 +2824,35 @@ function buildRecentActivityKeyForEntry(entry) {
|
|
|
2812
2824
|
}
|
|
2813
2825
|
return buildRecentActivityKey(entry);
|
|
2814
2826
|
}
|
|
2815
|
-
function appendRecentActivity(
|
|
2827
|
+
function appendRecentActivity(state, entry) {
|
|
2816
2828
|
const nextEntry = {
|
|
2817
2829
|
...entry,
|
|
2818
2830
|
workspace: entry.workspace ? normalizeWorkspace(entry.workspace) : void 0,
|
|
2819
2831
|
id: buildRecentActivityKeyForEntry(entry),
|
|
2820
2832
|
lastUsedAt: entry.lastUsedAt || Date.now()
|
|
2821
2833
|
};
|
|
2822
|
-
const filtered = (
|
|
2834
|
+
const filtered = (state.recentActivity || []).filter((item) => item.id !== nextEntry.id);
|
|
2823
2835
|
return {
|
|
2824
|
-
...
|
|
2836
|
+
...state,
|
|
2825
2837
|
recentActivity: [nextEntry, ...filtered].slice(0, MAX_ACTIVITY)
|
|
2826
2838
|
};
|
|
2827
2839
|
}
|
|
2828
|
-
function getRecentActivity(
|
|
2829
|
-
return [...
|
|
2840
|
+
function getRecentActivity(state, limit = 20) {
|
|
2841
|
+
return [...state.recentActivity || []].sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, limit);
|
|
2830
2842
|
}
|
|
2831
|
-
function getSessionSeenAt(
|
|
2832
|
-
return
|
|
2843
|
+
function getSessionSeenAt(state, sessionId) {
|
|
2844
|
+
return state.sessionReads?.[sessionId] || 0;
|
|
2833
2845
|
}
|
|
2834
|
-
function getSessionSeenMarker(
|
|
2835
|
-
return
|
|
2846
|
+
function getSessionSeenMarker(state, sessionId) {
|
|
2847
|
+
return state.sessionReadMarkers?.[sessionId] || "";
|
|
2836
2848
|
}
|
|
2837
|
-
function markSessionSeen(
|
|
2838
|
-
const prev =
|
|
2849
|
+
function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker) {
|
|
2850
|
+
const prev = state.sessionReads || {};
|
|
2839
2851
|
const nextSeenAt = Math.max(prev[sessionId] || 0, seenAt);
|
|
2840
|
-
const prevMarkers =
|
|
2852
|
+
const prevMarkers = state.sessionReadMarkers || {};
|
|
2841
2853
|
const nextMarker = typeof completionMarker === "string" ? completionMarker : "";
|
|
2842
2854
|
return {
|
|
2843
|
-
...
|
|
2855
|
+
...state,
|
|
2844
2856
|
sessionReads: {
|
|
2845
2857
|
...prev,
|
|
2846
2858
|
[sessionId]: nextSeenAt
|
|
@@ -2866,11 +2878,11 @@ function normalizeWorkspace2(workspace) {
|
|
|
2866
2878
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
2867
2879
|
return `saved:${providerSessionId.trim()}`;
|
|
2868
2880
|
}
|
|
2869
|
-
function upsertSavedProviderSession(
|
|
2881
|
+
function upsertSavedProviderSession(state, entry) {
|
|
2870
2882
|
const providerSessionId = typeof entry.providerSessionId === "string" ? entry.providerSessionId.trim() : "";
|
|
2871
|
-
if (!providerSessionId) return
|
|
2883
|
+
if (!providerSessionId) return state;
|
|
2872
2884
|
const id = buildSavedProviderSessionKey(providerSessionId);
|
|
2873
|
-
const existing = (
|
|
2885
|
+
const existing = (state.savedProviderSessions || []).find((item) => item.id === id);
|
|
2874
2886
|
const nextEntry = {
|
|
2875
2887
|
id,
|
|
2876
2888
|
kind: entry.kind,
|
|
@@ -2883,23 +2895,75 @@ function upsertSavedProviderSession(config, entry) {
|
|
|
2883
2895
|
createdAt: existing?.createdAt || entry.createdAt || Date.now(),
|
|
2884
2896
|
lastUsedAt: entry.lastUsedAt || Date.now()
|
|
2885
2897
|
};
|
|
2886
|
-
const filtered = (
|
|
2898
|
+
const filtered = (state.savedProviderSessions || []).filter((item) => item.id !== id);
|
|
2887
2899
|
return {
|
|
2888
|
-
...
|
|
2900
|
+
...state,
|
|
2889
2901
|
savedProviderSessions: [nextEntry, ...filtered].slice(0, MAX_SAVED_SESSIONS)
|
|
2890
2902
|
};
|
|
2891
2903
|
}
|
|
2892
|
-
function getSavedProviderSessions(
|
|
2893
|
-
return [...
|
|
2904
|
+
function getSavedProviderSessions(state, filters) {
|
|
2905
|
+
return [...state.savedProviderSessions || []].filter((entry) => {
|
|
2894
2906
|
if (filters?.providerType && entry.providerType !== filters.providerType) return false;
|
|
2895
2907
|
if (filters?.kind && entry.kind !== filters.kind) return false;
|
|
2896
2908
|
return true;
|
|
2897
2909
|
}).sort((a, b) => b.lastUsedAt - a.lastUsedAt);
|
|
2898
2910
|
}
|
|
2899
2911
|
|
|
2912
|
+
// src/config/state-store.ts
|
|
2913
|
+
var import_fs2 = require("fs");
|
|
2914
|
+
var import_path2 = require("path");
|
|
2915
|
+
init_config();
|
|
2916
|
+
var DEFAULT_STATE = {
|
|
2917
|
+
recentActivity: [],
|
|
2918
|
+
savedProviderSessions: [],
|
|
2919
|
+
sessionReads: {},
|
|
2920
|
+
sessionReadMarkers: {}
|
|
2921
|
+
};
|
|
2922
|
+
function isPlainObject2(value) {
|
|
2923
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
2924
|
+
}
|
|
2925
|
+
function getStatePath() {
|
|
2926
|
+
return (0, import_path2.join)(getConfigDir(), "state.json");
|
|
2927
|
+
}
|
|
2928
|
+
function normalizeState(raw) {
|
|
2929
|
+
const parsed = isPlainObject2(raw) ? raw : {};
|
|
2930
|
+
const sessionReads = Object.fromEntries(
|
|
2931
|
+
Object.entries(isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {}).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
|
|
2932
|
+
);
|
|
2933
|
+
const sessionReadMarkers = Object.fromEntries(
|
|
2934
|
+
Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
|
|
2935
|
+
);
|
|
2936
|
+
return {
|
|
2937
|
+
recentActivity: Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [],
|
|
2938
|
+
savedProviderSessions: Array.isArray(parsed.savedProviderSessions) ? parsed.savedProviderSessions : [],
|
|
2939
|
+
sessionReads,
|
|
2940
|
+
sessionReadMarkers
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
function loadState() {
|
|
2944
|
+
const statePath = getStatePath();
|
|
2945
|
+
if (!(0, import_fs2.existsSync)(statePath)) {
|
|
2946
|
+
return { ...DEFAULT_STATE };
|
|
2947
|
+
}
|
|
2948
|
+
try {
|
|
2949
|
+
const raw = (0, import_fs2.readFileSync)(statePath, "utf-8");
|
|
2950
|
+
return normalizeState(JSON.parse(raw));
|
|
2951
|
+
} catch {
|
|
2952
|
+
return { ...DEFAULT_STATE };
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
function saveState(state) {
|
|
2956
|
+
const statePath = getStatePath();
|
|
2957
|
+
const normalized = normalizeState(state);
|
|
2958
|
+
(0, import_fs2.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
2959
|
+
}
|
|
2960
|
+
function resetState() {
|
|
2961
|
+
saveState({ ...DEFAULT_STATE });
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2900
2964
|
// src/detection/ide-detector.ts
|
|
2901
2965
|
var import_child_process = require("child_process");
|
|
2902
|
-
var
|
|
2966
|
+
var import_fs3 = require("fs");
|
|
2903
2967
|
var import_os2 = require("os");
|
|
2904
2968
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
2905
2969
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
@@ -2945,9 +3009,9 @@ function checkPathExists(paths) {
|
|
|
2945
3009
|
if (p.includes("*")) {
|
|
2946
3010
|
const username = home.split(/[\\/]/).pop() || "";
|
|
2947
3011
|
const resolved = p.replace("*", username);
|
|
2948
|
-
if ((0,
|
|
3012
|
+
if ((0, import_fs3.existsSync)(resolved)) return resolved;
|
|
2949
3013
|
} else {
|
|
2950
|
-
if ((0,
|
|
3014
|
+
if ((0, import_fs3.existsSync)(p)) return p;
|
|
2951
3015
|
}
|
|
2952
3016
|
}
|
|
2953
3017
|
return null;
|
|
@@ -2962,7 +3026,7 @@ async function detectIDEs() {
|
|
|
2962
3026
|
let resolvedCli = cliPath;
|
|
2963
3027
|
if (!resolvedCli && appPath && os18 === "darwin") {
|
|
2964
3028
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
2965
|
-
if ((0,
|
|
3029
|
+
if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
2966
3030
|
}
|
|
2967
3031
|
if (!resolvedCli && appPath && os18 === "win32") {
|
|
2968
3032
|
const { dirname: dirname6 } = await import("path");
|
|
@@ -2975,7 +3039,7 @@ async function detectIDEs() {
|
|
|
2975
3039
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
2976
3040
|
];
|
|
2977
3041
|
for (const c of candidates) {
|
|
2978
|
-
if ((0,
|
|
3042
|
+
if ((0, import_fs3.existsSync)(c)) {
|
|
2979
3043
|
resolvedCli = c;
|
|
2980
3044
|
break;
|
|
2981
3045
|
}
|
|
@@ -9609,9 +9673,9 @@ var DaemonCliManager = class {
|
|
|
9609
9673
|
}
|
|
9610
9674
|
persistRecentActivity(entry) {
|
|
9611
9675
|
try {
|
|
9612
|
-
let
|
|
9676
|
+
let nextState = appendRecentActivity(loadState(), entry);
|
|
9613
9677
|
if (entry.providerSessionId && (entry.kind === "cli" || entry.kind === "acp")) {
|
|
9614
|
-
|
|
9678
|
+
nextState = upsertSavedProviderSession(nextState, {
|
|
9615
9679
|
kind: entry.kind,
|
|
9616
9680
|
providerType: entry.providerType,
|
|
9617
9681
|
providerName: entry.providerName,
|
|
@@ -9621,7 +9685,7 @@ var DaemonCliManager = class {
|
|
|
9621
9685
|
title: entry.title
|
|
9622
9686
|
});
|
|
9623
9687
|
}
|
|
9624
|
-
|
|
9688
|
+
saveState(nextState);
|
|
9625
9689
|
} catch (e) {
|
|
9626
9690
|
console.error(colorize("red", ` \u2717 Failed to save recent activity: ${e}`));
|
|
9627
9691
|
}
|
|
@@ -10413,14 +10477,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
10413
10477
|
*/
|
|
10414
10478
|
setIdeExtensionEnabled(ideType, extensionType, enabled) {
|
|
10415
10479
|
try {
|
|
10416
|
-
const { loadConfig: loadConfig2, saveConfig:
|
|
10480
|
+
const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
|
|
10417
10481
|
const config = loadConfig2();
|
|
10418
10482
|
const baseIdeType = ideType.split("_")[0];
|
|
10419
10483
|
if (!config.ideSettings) config.ideSettings = {};
|
|
10420
10484
|
if (!config.ideSettings[baseIdeType]) config.ideSettings[baseIdeType] = {};
|
|
10421
10485
|
if (!config.ideSettings[baseIdeType].extensions) config.ideSettings[baseIdeType].extensions = {};
|
|
10422
10486
|
config.ideSettings[baseIdeType].extensions[extensionType] = { enabled };
|
|
10423
|
-
|
|
10487
|
+
saveConfig3(config);
|
|
10424
10488
|
this.log(`IDE extension setting: ${ideType}.${extensionType}.enabled = ${enabled}`);
|
|
10425
10489
|
return true;
|
|
10426
10490
|
} catch (e) {
|
|
@@ -10985,12 +11049,12 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
10985
11049
|
}
|
|
10986
11050
|
if (schemaDef.type === "select" && schemaDef.options && !schemaDef.options.includes(value)) return false;
|
|
10987
11051
|
try {
|
|
10988
|
-
const { loadConfig: loadConfig2, saveConfig:
|
|
11052
|
+
const { loadConfig: loadConfig2, saveConfig: saveConfig3 } = (init_config(), __toCommonJS(config_exports));
|
|
10989
11053
|
const config = loadConfig2();
|
|
10990
11054
|
if (!config.providerSettings) config.providerSettings = {};
|
|
10991
11055
|
if (!config.providerSettings[type]) config.providerSettings[type] = {};
|
|
10992
11056
|
config.providerSettings[type][key] = value;
|
|
10993
|
-
|
|
11057
|
+
saveConfig3(config);
|
|
10994
11058
|
this.log(`Setting updated: ${type}.${key} = ${JSON.stringify(value)}`);
|
|
10995
11059
|
return true;
|
|
10996
11060
|
} catch (e) {
|
|
@@ -11768,16 +11832,17 @@ function buildRecentLaunches(recentActivity) {
|
|
|
11768
11832
|
}
|
|
11769
11833
|
function buildStatusSnapshot(options) {
|
|
11770
11834
|
const cfg = loadConfig();
|
|
11835
|
+
const state = loadState();
|
|
11771
11836
|
const wsState = getWorkspaceState(cfg);
|
|
11772
11837
|
const memSnap = getHostMemorySnapshot();
|
|
11773
|
-
const recentActivity = getRecentActivity(
|
|
11838
|
+
const recentActivity = getRecentActivity(state, 20);
|
|
11774
11839
|
const sessions = buildSessionEntries(
|
|
11775
11840
|
options.allStates,
|
|
11776
11841
|
options.cdpManagers
|
|
11777
11842
|
);
|
|
11778
11843
|
for (const session of sessions) {
|
|
11779
|
-
const lastSeenAt = getSessionSeenAt(
|
|
11780
|
-
const seenCompletionMarker = getSessionSeenMarker(
|
|
11844
|
+
const lastSeenAt = getSessionSeenAt(state, session.id);
|
|
11845
|
+
const seenCompletionMarker = getSessionSeenMarker(state, session.id);
|
|
11781
11846
|
const lastUsedAt = getSessionLastUsedAt(session);
|
|
11782
11847
|
const completionMarker = getSessionCompletionMarker(session);
|
|
11783
11848
|
const { unread, inboxBucket } = session.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
|
|
@@ -12115,9 +12180,9 @@ var DaemonCommandRouter = class {
|
|
|
12115
12180
|
const offset = Math.max(0, Number(args?.offset) || 0);
|
|
12116
12181
|
const limit = Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
12117
12182
|
const { sessions: historySessions, hasMore } = listSavedHistorySessions(providerType, { offset, limit });
|
|
12118
|
-
const
|
|
12119
|
-
const savedSessions = getSavedProviderSessions(
|
|
12120
|
-
const recentSessions = getRecentActivity(
|
|
12183
|
+
const state = loadState();
|
|
12184
|
+
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
12185
|
+
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
12121
12186
|
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
12122
12187
|
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
12123
12188
|
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
@@ -12208,19 +12273,19 @@ var DaemonCommandRouter = class {
|
|
|
12208
12273
|
this.deps.onIdeConnected?.();
|
|
12209
12274
|
if (result.success && resolvedWorkspace) {
|
|
12210
12275
|
try {
|
|
12211
|
-
const next = appendRecentActivity(
|
|
12276
|
+
const next = appendRecentActivity(loadState(), {
|
|
12212
12277
|
kind: "ide",
|
|
12213
12278
|
providerType: result.ideId || ideKey,
|
|
12214
12279
|
providerName: result.ideId || ideKey,
|
|
12215
12280
|
workspace: resolvedWorkspace,
|
|
12216
12281
|
title: result.ideId || ideKey
|
|
12217
12282
|
});
|
|
12218
|
-
|
|
12283
|
+
saveState(next);
|
|
12219
12284
|
} catch {
|
|
12220
12285
|
}
|
|
12221
12286
|
} else if (result.success && (result.ideId || ideKey)) {
|
|
12222
12287
|
try {
|
|
12223
|
-
|
|
12288
|
+
saveState(appendRecentActivity(loadState(), {
|
|
12224
12289
|
kind: "ide",
|
|
12225
12290
|
providerType: result.ideId || ideKey,
|
|
12226
12291
|
providerName: result.ideId || ideKey,
|
|
@@ -12249,8 +12314,8 @@ var DaemonCommandRouter = class {
|
|
|
12249
12314
|
if (!sessionId || typeof sessionId !== "string") {
|
|
12250
12315
|
return { success: false, error: "sessionId is required" };
|
|
12251
12316
|
}
|
|
12252
|
-
const
|
|
12253
|
-
const prevSeenAt =
|
|
12317
|
+
const currentState = loadState();
|
|
12318
|
+
const prevSeenAt = currentState.sessionReads?.[sessionId] || 0;
|
|
12254
12319
|
const sessionEntries = buildSessionEntries(
|
|
12255
12320
|
this.deps.instanceManager.collectAllStates(),
|
|
12256
12321
|
this.deps.cdpManagers
|
|
@@ -12258,7 +12323,7 @@ var DaemonCommandRouter = class {
|
|
|
12258
12323
|
const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
|
|
12259
12324
|
const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : "";
|
|
12260
12325
|
const next = markSessionSeen(
|
|
12261
|
-
|
|
12326
|
+
currentState,
|
|
12262
12327
|
sessionId,
|
|
12263
12328
|
typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
|
|
12264
12329
|
completionMarker
|
|
@@ -12266,7 +12331,7 @@ var DaemonCommandRouter = class {
|
|
|
12266
12331
|
if (READ_DEBUG_ENABLED2) {
|
|
12267
12332
|
LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
|
|
12268
12333
|
}
|
|
12269
|
-
|
|
12334
|
+
saveState(next);
|
|
12270
12335
|
this.deps.onStatusChange?.();
|
|
12271
12336
|
return {
|
|
12272
12337
|
success: true,
|
|
@@ -19612,6 +19677,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
19612
19677
|
launchWithCdp,
|
|
19613
19678
|
listHostedCliRuntimes,
|
|
19614
19679
|
loadConfig,
|
|
19680
|
+
loadState,
|
|
19615
19681
|
logCommand,
|
|
19616
19682
|
markSetupComplete,
|
|
19617
19683
|
maybeRunDaemonUpgradeHelperFromEnv,
|
|
@@ -19621,7 +19687,9 @@ async function shutdownDaemonComponents(components) {
|
|
|
19621
19687
|
readChatHistory,
|
|
19622
19688
|
registerExtensionProviders,
|
|
19623
19689
|
resetConfig,
|
|
19690
|
+
resetState,
|
|
19624
19691
|
saveConfig,
|
|
19692
|
+
saveState,
|
|
19625
19693
|
setLogLevel,
|
|
19626
19694
|
setupIdeInstance,
|
|
19627
19695
|
shutdownDaemonComponents,
|