pulse-coder-cli 0.0.1-alpha.1

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/src/session.ts ADDED
@@ -0,0 +1,171 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { homedir } from 'os';
4
+ import { randomUUID } from 'crypto';
5
+
6
+ export interface SessionMessage {
7
+ role: 'user' | 'assistant' | 'system' | 'clarification';
8
+ content: string;
9
+ timestamp: number;
10
+ metadata?: {
11
+ clarificationType?: 'question' | 'answer';
12
+ clarificationId?: string;
13
+ [key: string]: any;
14
+ };
15
+ }
16
+
17
+ export interface Session {
18
+ id: string;
19
+ title: string;
20
+ createdAt: number;
21
+ updatedAt: number;
22
+ messages: SessionMessage[];
23
+ metadata: {
24
+ totalMessages: number;
25
+ lastMessageAt?: number;
26
+ tags?: string[];
27
+ };
28
+ }
29
+
30
+ export interface SessionSummary {
31
+ id: string;
32
+ title: string;
33
+ createdAt: number;
34
+ updatedAt: number;
35
+ messageCount: number;
36
+ preview: string;
37
+ }
38
+
39
+ export class SessionManager {
40
+ private sessionsDir: string;
41
+
42
+ constructor() {
43
+ this.sessionsDir = path.join(homedir(), '.pulse-coder', 'sessions');
44
+ }
45
+
46
+ async initialize(): Promise<void> {
47
+ try {
48
+ await fs.mkdir(this.sessionsDir, { recursive: true });
49
+ } catch (error) {
50
+ // Directory might already exist
51
+ }
52
+ }
53
+
54
+ async createSession(title?: string): Promise<Session> {
55
+ const session: Session = {
56
+ id: randomUUID(),
57
+ title: title || `Session ${new Date().toLocaleString()}`,
58
+ createdAt: Date.now(),
59
+ updatedAt: Date.now(),
60
+ messages: [],
61
+ metadata: {
62
+ totalMessages: 0,
63
+ },
64
+ };
65
+
66
+ await this.saveSession(session);
67
+ return session;
68
+ }
69
+
70
+ async saveSession(session: Session): Promise<void> {
71
+ session.updatedAt = Date.now();
72
+ session.metadata.totalMessages = session.messages.length;
73
+ if (session.messages.length > 0) {
74
+ session.metadata.lastMessageAt = session.messages[session.messages.length - 1].timestamp;
75
+ }
76
+
77
+ const filePath = path.join(this.sessionsDir, `${session.id}.json`);
78
+ await fs.writeFile(filePath, JSON.stringify(session, null, 2));
79
+ }
80
+
81
+ async loadSession(id: string): Promise<Session | null> {
82
+ try {
83
+ const filePath = path.join(this.sessionsDir, `${id}.json`);
84
+ const data = await fs.readFile(filePath, 'utf-8');
85
+ return JSON.parse(data);
86
+ } catch (error) {
87
+ return null;
88
+ }
89
+ }
90
+
91
+ private safeContent(content: any): string {
92
+ if (typeof content === 'string') {
93
+ return content;
94
+ }
95
+ if (content === null || content === undefined) {
96
+ return '';
97
+ }
98
+ return String(content);
99
+ }
100
+
101
+ async listSessions(limit = 20): Promise<SessionSummary[]> {
102
+ try {
103
+ const files = await fs.readdir(this.sessionsDir);
104
+ const sessionFiles = files.filter(file => file.endsWith('.json'));
105
+
106
+ const sessions: Session[] = [];
107
+ for (const file of sessionFiles) {
108
+ const data = await fs.readFile(path.join(this.sessionsDir, file), 'utf-8');
109
+ sessions.push(JSON.parse(data));
110
+ }
111
+
112
+ return sessions
113
+ .sort((a, b) => b.updatedAt - a.updatedAt)
114
+ .slice(0, limit)
115
+ .map(session => ({
116
+ id: session.id,
117
+ title: session.title,
118
+ createdAt: session.createdAt,
119
+ updatedAt: session.updatedAt,
120
+ messageCount: session.messages.length,
121
+ preview: session.messages.length > 0
122
+ ? this.safeContent(session.messages[session.messages.length - 1].content).substring(0, 100) + '...'
123
+ : 'No messages',
124
+ }));
125
+ } catch (error) {
126
+ return [];
127
+ }
128
+ }
129
+
130
+ async deleteSession(id: string): Promise<boolean> {
131
+ try {
132
+ const filePath = path.join(this.sessionsDir, `${id}.json`);
133
+ await fs.unlink(filePath);
134
+ return true;
135
+ } catch (error) {
136
+ return false;
137
+ }
138
+ }
139
+
140
+ async updateSessionTitle(id: string, title: string): Promise<boolean> {
141
+ const session = await this.loadSession(id);
142
+ if (!session) return false;
143
+
144
+ session.title = title;
145
+ await this.saveSession(session);
146
+ return true;
147
+ }
148
+
149
+ async addMessage(id: string, message: Omit<SessionMessage, 'timestamp'>): Promise<boolean> {
150
+ const session = await this.loadSession(id);
151
+ if (!session) return false;
152
+
153
+ session.messages.push({
154
+ ...message,
155
+ timestamp: Date.now(),
156
+ });
157
+
158
+ await this.saveSession(session);
159
+ return true;
160
+ }
161
+
162
+ async searchSessions(query: string): Promise<SessionSummary[]> {
163
+ const sessions = await this.listSessions(100); // Get more for search
164
+ const lowercaseQuery = query.toLowerCase();
165
+
166
+ return sessions.filter(session =>
167
+ session.title.toLowerCase().includes(lowercaseQuery) ||
168
+ session.preview.toLowerCase().includes(lowercaseQuery)
169
+ );
170
+ }
171
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["**/*.test.ts", "**/*.spec.ts"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm'],
6
+ dts: false,
7
+ clean: true,
8
+ splitting: false,
9
+ sourcemap: true,
10
+ target: 'es2022',
11
+ banner: { js: '#!/usr/bin/env node' }
12
+ });