@sumicom/quicksave-shared 0.1.0 → 0.3.0
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/crypto.d.ts +25 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +64 -0
- package/dist/crypto.js.map +1 -1
- package/dist/crypto.test.js +41 -1
- package/dist/crypto.test.js.map +1 -1
- package/dist/types.d.ts +20 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +19 -1
- package/src/crypto.test.ts +0 -337
- package/src/crypto.ts +0 -335
- package/src/index.ts +0 -8
- package/src/protocol.test.ts +0 -197
- package/src/protocol.ts +0 -92
- package/src/types.ts +0 -400
- package/tsconfig.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -9
package/src/protocol.test.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
generateMessageId,
|
|
4
|
-
createMessage,
|
|
5
|
-
createRequest,
|
|
6
|
-
parseMessage,
|
|
7
|
-
serializeMessage,
|
|
8
|
-
isResponseMessage,
|
|
9
|
-
getRequestType,
|
|
10
|
-
REQUEST_RESPONSE_MAP,
|
|
11
|
-
} from './protocol.js';
|
|
12
|
-
|
|
13
|
-
describe('generateMessageId', () => {
|
|
14
|
-
it('should generate unique IDs', () => {
|
|
15
|
-
const ids = new Set<string>();
|
|
16
|
-
for (let i = 0; i < 100; i++) {
|
|
17
|
-
ids.add(generateMessageId());
|
|
18
|
-
}
|
|
19
|
-
expect(ids.size).toBe(100);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should generate IDs with expected format', () => {
|
|
23
|
-
const id = generateMessageId();
|
|
24
|
-
// Format: timestamp-randomString
|
|
25
|
-
expect(id).toMatch(/^\d+-[a-z0-9]+$/);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('createMessage', () => {
|
|
30
|
-
it('should create a properly structured message', () => {
|
|
31
|
-
const payload = { test: 'data' };
|
|
32
|
-
const message = createMessage('ping', payload);
|
|
33
|
-
|
|
34
|
-
expect(message.id).toBeDefined();
|
|
35
|
-
expect(message.type).toBe('ping');
|
|
36
|
-
expect(message.payload).toEqual(payload);
|
|
37
|
-
expect(message.timestamp).toBeDefined();
|
|
38
|
-
expect(typeof message.timestamp).toBe('number');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should create unique IDs for each message', () => {
|
|
42
|
-
const msg1 = createMessage('ping', {});
|
|
43
|
-
const msg2 = createMessage('ping', {});
|
|
44
|
-
|
|
45
|
-
expect(msg1.id).not.toBe(msg2.id);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('should set timestamp close to current time', () => {
|
|
49
|
-
const before = Date.now();
|
|
50
|
-
const message = createMessage('pong', { timestamp: 0 });
|
|
51
|
-
const after = Date.now();
|
|
52
|
-
|
|
53
|
-
expect(message.timestamp).toBeGreaterThanOrEqual(before);
|
|
54
|
-
expect(message.timestamp).toBeLessThanOrEqual(after);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('createRequest', () => {
|
|
59
|
-
it('should create request with correct response type', () => {
|
|
60
|
-
const { message, responseType } = createRequest('git:status', { path: '/' });
|
|
61
|
-
|
|
62
|
-
expect(message.type).toBe('git:status');
|
|
63
|
-
expect(message.payload).toEqual({ path: '/' });
|
|
64
|
-
expect(responseType).toBe('git:status:response');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should work with different request types', () => {
|
|
68
|
-
const types = ['git:diff', 'git:stage', 'git:commit', 'git:log'];
|
|
69
|
-
|
|
70
|
-
for (const type of types) {
|
|
71
|
-
const { responseType } = createRequest(type as any, {});
|
|
72
|
-
expect(responseType).toBe(`${type}:response`);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('parseMessage', () => {
|
|
78
|
-
it('should parse valid JSON message', () => {
|
|
79
|
-
const original = createMessage('ping', { data: 'test' });
|
|
80
|
-
const json = JSON.stringify(original);
|
|
81
|
-
|
|
82
|
-
const parsed = parseMessage(json);
|
|
83
|
-
|
|
84
|
-
expect(parsed.id).toBe(original.id);
|
|
85
|
-
expect(parsed.type).toBe(original.type);
|
|
86
|
-
expect(parsed.payload).toEqual(original.payload);
|
|
87
|
-
expect(parsed.timestamp).toBe(original.timestamp);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should throw on invalid JSON', () => {
|
|
91
|
-
expect(() => parseMessage('not valid json')).toThrow();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should throw on missing id', () => {
|
|
95
|
-
const invalid = JSON.stringify({ type: 'ping', payload: {}, timestamp: 123 });
|
|
96
|
-
expect(() => parseMessage(invalid)).toThrow('Invalid message format');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should throw on missing type', () => {
|
|
100
|
-
const invalid = JSON.stringify({ id: '123', payload: {}, timestamp: 123 });
|
|
101
|
-
expect(() => parseMessage(invalid)).toThrow('Invalid message format');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should throw on missing timestamp', () => {
|
|
105
|
-
const invalid = JSON.stringify({ id: '123', type: 'ping', payload: {} });
|
|
106
|
-
expect(() => parseMessage(invalid)).toThrow('Invalid message format');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should throw on null message', () => {
|
|
110
|
-
expect(() => parseMessage('null')).toThrow('Invalid message format');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('should throw on array', () => {
|
|
114
|
-
expect(() => parseMessage('[]')).toThrow('Invalid message format');
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe('serializeMessage', () => {
|
|
119
|
-
it('should serialize message to JSON string', () => {
|
|
120
|
-
const message = createMessage('ping', { test: true });
|
|
121
|
-
const json = serializeMessage(message);
|
|
122
|
-
|
|
123
|
-
expect(typeof json).toBe('string');
|
|
124
|
-
|
|
125
|
-
const parsed = JSON.parse(json);
|
|
126
|
-
expect(parsed.id).toBe(message.id);
|
|
127
|
-
expect(parsed.type).toBe(message.type);
|
|
128
|
-
expect(parsed.payload).toEqual(message.payload);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should produce valid JSON that can be parsed back', () => {
|
|
132
|
-
const original = createMessage('git:status:response', {
|
|
133
|
-
branch: 'main',
|
|
134
|
-
staged: [],
|
|
135
|
-
unstaged: [],
|
|
136
|
-
untracked: [],
|
|
137
|
-
ahead: 0,
|
|
138
|
-
behind: 0,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const json = serializeMessage(original);
|
|
142
|
-
const parsed = parseMessage(json);
|
|
143
|
-
|
|
144
|
-
expect(parsed).toEqual(original);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('isResponseMessage', () => {
|
|
149
|
-
it('should identify response messages', () => {
|
|
150
|
-
expect(isResponseMessage({ id: '1', type: 'git:status:response', payload: {}, timestamp: 1 })).toBe(true);
|
|
151
|
-
expect(isResponseMessage({ id: '1', type: 'git:diff:response', payload: {}, timestamp: 1 })).toBe(true);
|
|
152
|
-
expect(isResponseMessage({ id: '1', type: 'handshake:ack', payload: {}, timestamp: 1 })).toBe(false);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('should identify non-response messages', () => {
|
|
156
|
-
expect(isResponseMessage({ id: '1', type: 'ping', payload: {}, timestamp: 1 })).toBe(false);
|
|
157
|
-
expect(isResponseMessage({ id: '1', type: 'git:status', payload: {}, timestamp: 1 })).toBe(false);
|
|
158
|
-
expect(isResponseMessage({ id: '1', type: 'handshake', payload: {}, timestamp: 1 })).toBe(false);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe('getRequestType', () => {
|
|
163
|
-
it('should extract request type from response type', () => {
|
|
164
|
-
expect(getRequestType('git:status:response' as any)).toBe('git:status');
|
|
165
|
-
expect(getRequestType('git:diff:response' as any)).toBe('git:diff');
|
|
166
|
-
expect(getRequestType('git:commit:response' as any)).toBe('git:commit');
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('REQUEST_RESPONSE_MAP', () => {
|
|
171
|
-
it('should contain all git operations', () => {
|
|
172
|
-
const expectedOperations = [
|
|
173
|
-
'git:status',
|
|
174
|
-
'git:diff',
|
|
175
|
-
'git:stage',
|
|
176
|
-
'git:unstage',
|
|
177
|
-
'git:commit',
|
|
178
|
-
'git:log',
|
|
179
|
-
'git:branches',
|
|
180
|
-
'git:checkout',
|
|
181
|
-
'git:discard',
|
|
182
|
-
];
|
|
183
|
-
|
|
184
|
-
for (const op of expectedOperations) {
|
|
185
|
-
expect(REQUEST_RESPONSE_MAP[op]).toBeDefined();
|
|
186
|
-
expect(REQUEST_RESPONSE_MAP[op]).toBe(`${op}:response`);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('should contain handshake mapping', () => {
|
|
191
|
-
expect(REQUEST_RESPONSE_MAP['handshake']).toBe('handshake:ack');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should contain ping/pong mapping', () => {
|
|
195
|
-
expect(REQUEST_RESPONSE_MAP['ping']).toBe('pong');
|
|
196
|
-
});
|
|
197
|
-
});
|
package/src/protocol.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { Message, MessageType } from './types.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generate a unique message ID
|
|
5
|
-
*/
|
|
6
|
-
export function generateMessageId(): string {
|
|
7
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Create a typed message
|
|
12
|
-
*/
|
|
13
|
-
export function createMessage<T>(type: MessageType, payload: T): Message<T> {
|
|
14
|
-
return {
|
|
15
|
-
id: generateMessageId(),
|
|
16
|
-
type,
|
|
17
|
-
payload,
|
|
18
|
-
timestamp: Date.now(),
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Create a request message and return both the message and a response handler
|
|
24
|
-
*/
|
|
25
|
-
export function createRequest<TReq>(
|
|
26
|
-
type: MessageType,
|
|
27
|
-
payload: TReq
|
|
28
|
-
): {
|
|
29
|
-
message: Message<TReq>;
|
|
30
|
-
responseType: MessageType;
|
|
31
|
-
} {
|
|
32
|
-
const message = createMessage(type, payload);
|
|
33
|
-
const responseType = `${type}:response` as MessageType;
|
|
34
|
-
return { message, responseType };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Parse and validate a message
|
|
39
|
-
*/
|
|
40
|
-
export function parseMessage(data: string): Message {
|
|
41
|
-
const parsed = JSON.parse(data);
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
typeof parsed !== 'object' ||
|
|
45
|
-
parsed === null ||
|
|
46
|
-
typeof parsed.id !== 'string' ||
|
|
47
|
-
typeof parsed.type !== 'string' ||
|
|
48
|
-
typeof parsed.timestamp !== 'number'
|
|
49
|
-
) {
|
|
50
|
-
throw new Error('Invalid message format');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return parsed as Message;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Serialize a message to JSON
|
|
58
|
-
*/
|
|
59
|
-
export function serializeMessage(message: Message): string {
|
|
60
|
-
return JSON.stringify(message);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Type guard for response messages
|
|
65
|
-
*/
|
|
66
|
-
export function isResponseMessage(message: Message): boolean {
|
|
67
|
-
return message.type.endsWith(':response');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get the request type from a response type
|
|
72
|
-
*/
|
|
73
|
-
export function getRequestType(responseType: MessageType): MessageType {
|
|
74
|
-
return responseType.replace(':response', '') as MessageType;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Request types and their expected response types
|
|
79
|
-
*/
|
|
80
|
-
export const REQUEST_RESPONSE_MAP: Record<string, string> = {
|
|
81
|
-
'git:status': 'git:status:response',
|
|
82
|
-
'git:diff': 'git:diff:response',
|
|
83
|
-
'git:stage': 'git:stage:response',
|
|
84
|
-
'git:unstage': 'git:unstage:response',
|
|
85
|
-
'git:commit': 'git:commit:response',
|
|
86
|
-
'git:log': 'git:log:response',
|
|
87
|
-
'git:branches': 'git:branches:response',
|
|
88
|
-
'git:checkout': 'git:checkout:response',
|
|
89
|
-
'git:discard': 'git:discard:response',
|
|
90
|
-
handshake: 'handshake:ack',
|
|
91
|
-
ping: 'pong',
|
|
92
|
-
};
|
package/src/types.ts
DELETED
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Message Types
|
|
3
|
-
// ============================================================================
|
|
4
|
-
|
|
5
|
-
export interface Message<T = unknown> {
|
|
6
|
-
id: string;
|
|
7
|
-
type: MessageType;
|
|
8
|
-
payload: T;
|
|
9
|
-
timestamp: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type MessageType =
|
|
13
|
-
| 'ping'
|
|
14
|
-
| 'pong'
|
|
15
|
-
| 'handshake'
|
|
16
|
-
| 'handshake:ack'
|
|
17
|
-
| 'git:status'
|
|
18
|
-
| 'git:status:response'
|
|
19
|
-
| 'git:diff'
|
|
20
|
-
| 'git:diff:response'
|
|
21
|
-
| 'git:stage'
|
|
22
|
-
| 'git:stage:response'
|
|
23
|
-
| 'git:unstage'
|
|
24
|
-
| 'git:unstage:response'
|
|
25
|
-
| 'git:stage-patch'
|
|
26
|
-
| 'git:stage-patch:response'
|
|
27
|
-
| 'git:unstage-patch'
|
|
28
|
-
| 'git:unstage-patch:response'
|
|
29
|
-
| 'git:commit'
|
|
30
|
-
| 'git:commit:response'
|
|
31
|
-
| 'git:log'
|
|
32
|
-
| 'git:log:response'
|
|
33
|
-
| 'git:branches'
|
|
34
|
-
| 'git:branches:response'
|
|
35
|
-
| 'git:checkout'
|
|
36
|
-
| 'git:checkout:response'
|
|
37
|
-
| 'git:discard'
|
|
38
|
-
| 'git:discard:response'
|
|
39
|
-
| 'ai:generate-commit-summary'
|
|
40
|
-
| 'ai:generate-commit-summary:response'
|
|
41
|
-
| 'ai:set-api-key'
|
|
42
|
-
| 'ai:set-api-key:response'
|
|
43
|
-
| 'ai:get-api-key-status'
|
|
44
|
-
| 'ai:get-api-key-status:response'
|
|
45
|
-
| 'agent:list-repos'
|
|
46
|
-
| 'agent:list-repos:response'
|
|
47
|
-
| 'agent:switch-repo'
|
|
48
|
-
| 'agent:switch-repo:response'
|
|
49
|
-
| 'agent:browse-directory'
|
|
50
|
-
| 'agent:browse-directory:response'
|
|
51
|
-
| 'agent:add-repo'
|
|
52
|
-
| 'agent:add-repo:response'
|
|
53
|
-
| 'error';
|
|
54
|
-
|
|
55
|
-
// ============================================================================
|
|
56
|
-
// Git Types
|
|
57
|
-
// ============================================================================
|
|
58
|
-
|
|
59
|
-
export type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed' | 'copied';
|
|
60
|
-
|
|
61
|
-
export interface FileChange {
|
|
62
|
-
path: string;
|
|
63
|
-
status: FileStatus;
|
|
64
|
-
oldPath?: string; // For renamed/copied files
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface GitStatus {
|
|
68
|
-
branch: string;
|
|
69
|
-
ahead: number;
|
|
70
|
-
behind: number;
|
|
71
|
-
staged: FileChange[];
|
|
72
|
-
unstaged: FileChange[];
|
|
73
|
-
untracked: string[];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface DiffHunk {
|
|
77
|
-
oldStart: number;
|
|
78
|
-
oldLines: number;
|
|
79
|
-
newStart: number;
|
|
80
|
-
newLines: number;
|
|
81
|
-
content: string;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface FileDiff {
|
|
85
|
-
path: string;
|
|
86
|
-
oldPath?: string;
|
|
87
|
-
hunks: DiffHunk[];
|
|
88
|
-
isBinary: boolean;
|
|
89
|
-
truncated?: boolean;
|
|
90
|
-
truncatedReason?: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface Commit {
|
|
94
|
-
hash: string;
|
|
95
|
-
shortHash: string;
|
|
96
|
-
message: string;
|
|
97
|
-
author: string;
|
|
98
|
-
email: string;
|
|
99
|
-
date: string;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface Branch {
|
|
103
|
-
name: string;
|
|
104
|
-
current: boolean;
|
|
105
|
-
remote?: string;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export interface Repository {
|
|
109
|
-
path: string;
|
|
110
|
-
name: string;
|
|
111
|
-
currentBranch?: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ============================================================================
|
|
115
|
-
// Request/Response Payloads
|
|
116
|
-
// ============================================================================
|
|
117
|
-
|
|
118
|
-
// Handshake
|
|
119
|
-
export interface HandshakePayload {
|
|
120
|
-
publicKey: string; // Base64 encoded
|
|
121
|
-
license?: License;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export interface HandshakeAckPayload {
|
|
125
|
-
success: boolean;
|
|
126
|
-
agentVersion: string;
|
|
127
|
-
repoPath: string;
|
|
128
|
-
availableRepos?: Repository[];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Status
|
|
132
|
-
export interface StatusRequestPayload {
|
|
133
|
-
path?: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export type StatusResponsePayload = GitStatus;
|
|
137
|
-
|
|
138
|
-
// Diff
|
|
139
|
-
export interface DiffRequestPayload {
|
|
140
|
-
path: string;
|
|
141
|
-
staged?: boolean;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export type DiffResponsePayload = FileDiff;
|
|
145
|
-
|
|
146
|
-
// Stage/Unstage
|
|
147
|
-
export interface StageRequestPayload {
|
|
148
|
-
paths: string[];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface StageResponsePayload {
|
|
152
|
-
success: boolean;
|
|
153
|
-
error?: string;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export type UnstageRequestPayload = StageRequestPayload;
|
|
157
|
-
export type UnstageResponsePayload = StageResponsePayload;
|
|
158
|
-
|
|
159
|
-
// Stage/Unstage Patch (for line-level staging)
|
|
160
|
-
export interface StagePatchRequestPayload {
|
|
161
|
-
patch: string; // Unified diff format
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export interface StagePatchResponsePayload {
|
|
165
|
-
success: boolean;
|
|
166
|
-
error?: string;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export type UnstagePatchRequestPayload = StagePatchRequestPayload;
|
|
170
|
-
export type UnstagePatchResponsePayload = StagePatchResponsePayload;
|
|
171
|
-
|
|
172
|
-
// Commit
|
|
173
|
-
export interface CommitRequestPayload {
|
|
174
|
-
message: string;
|
|
175
|
-
description?: string;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export interface CommitResponsePayload {
|
|
179
|
-
success: boolean;
|
|
180
|
-
hash?: string;
|
|
181
|
-
error?: string;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Log
|
|
185
|
-
export interface LogRequestPayload {
|
|
186
|
-
limit?: number;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface LogResponsePayload {
|
|
190
|
-
commits: Commit[];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Branches
|
|
194
|
-
export type BranchesRequestPayload = Record<string, never>;
|
|
195
|
-
|
|
196
|
-
export interface BranchesResponsePayload {
|
|
197
|
-
branches: Branch[];
|
|
198
|
-
current: string;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Checkout
|
|
202
|
-
export interface CheckoutRequestPayload {
|
|
203
|
-
branch: string;
|
|
204
|
-
create?: boolean;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export interface CheckoutResponsePayload {
|
|
208
|
-
success: boolean;
|
|
209
|
-
error?: string;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Discard
|
|
213
|
-
export interface DiscardRequestPayload {
|
|
214
|
-
paths: string[];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export interface DiscardResponsePayload {
|
|
218
|
-
success: boolean;
|
|
219
|
-
error?: string;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Error
|
|
223
|
-
export interface ErrorPayload {
|
|
224
|
-
code: string;
|
|
225
|
-
message: string;
|
|
226
|
-
details?: unknown;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// List Repos
|
|
230
|
-
export type ListReposRequestPayload = Record<string, never>;
|
|
231
|
-
|
|
232
|
-
export interface ListReposResponsePayload {
|
|
233
|
-
repos: Repository[];
|
|
234
|
-
current: string;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Switch Repo
|
|
238
|
-
export interface SwitchRepoRequestPayload {
|
|
239
|
-
path: string;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export interface SwitchRepoResponsePayload {
|
|
243
|
-
success: boolean;
|
|
244
|
-
newPath: string;
|
|
245
|
-
error?: string;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Browse Directory
|
|
249
|
-
export interface BrowseDirectoryRequestPayload {
|
|
250
|
-
path: string;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export interface DirectoryEntry {
|
|
254
|
-
name: string;
|
|
255
|
-
path: string;
|
|
256
|
-
isDirectory: boolean;
|
|
257
|
-
isGitRepo: boolean;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export interface BrowseDirectoryResponsePayload {
|
|
261
|
-
path: string;
|
|
262
|
-
parentPath: string | null;
|
|
263
|
-
entries: DirectoryEntry[];
|
|
264
|
-
error?: string;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Add Repo
|
|
268
|
-
export interface AddRepoRequestPayload {
|
|
269
|
-
path: string;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export interface AddRepoResponsePayload {
|
|
273
|
-
success: boolean;
|
|
274
|
-
repo?: Repository;
|
|
275
|
-
error?: string;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// ============================================================================
|
|
279
|
-
// License Types
|
|
280
|
-
// ============================================================================
|
|
281
|
-
|
|
282
|
-
export interface License {
|
|
283
|
-
version: 1;
|
|
284
|
-
publicKey: string;
|
|
285
|
-
issuedAt: number;
|
|
286
|
-
type: 'pro';
|
|
287
|
-
signature: string;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// ============================================================================
|
|
291
|
-
// Signaling Types
|
|
292
|
-
// ============================================================================
|
|
293
|
-
|
|
294
|
-
export type SignalingMessageType =
|
|
295
|
-
| 'peer-connected'
|
|
296
|
-
| 'peer-offline'
|
|
297
|
-
| 'data'
|
|
298
|
-
| 'bye';
|
|
299
|
-
|
|
300
|
-
export interface SignalingMessage {
|
|
301
|
-
type: SignalingMessageType;
|
|
302
|
-
payload?: unknown;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// ============================================================================
|
|
306
|
-
// Key Exchange Types (V2 Protocol)
|
|
307
|
-
// ============================================================================
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Key exchange message - PWA sends encrypted session DEK to Agent
|
|
311
|
-
* This provides forward secrecy: if Agent is compromised, only current session is exposed
|
|
312
|
-
*/
|
|
313
|
-
export interface KeyExchangeV2 {
|
|
314
|
-
type: 'key-exchange';
|
|
315
|
-
version: 2;
|
|
316
|
-
encryptedDEK: string; // Session DEK encrypted with Agent's public key (base64)
|
|
317
|
-
timestamp: number; // Unix timestamp for replay protection
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* V2 key exchange acknowledgment from Agent
|
|
322
|
-
*/
|
|
323
|
-
export interface KeyExchangeV2Ack {
|
|
324
|
-
type: 'key-exchange-ack';
|
|
325
|
-
version: 2;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Key exchange message type
|
|
330
|
-
*/
|
|
331
|
-
export type KeyExchangeMessage = KeyExchangeV2;
|
|
332
|
-
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Connection Types
|
|
335
|
-
// ============================================================================
|
|
336
|
-
|
|
337
|
-
export type ConnectionState =
|
|
338
|
-
| 'disconnected'
|
|
339
|
-
| 'connecting'
|
|
340
|
-
| 'connected'
|
|
341
|
-
| 'reconnecting'
|
|
342
|
-
| 'error';
|
|
343
|
-
|
|
344
|
-
export interface ConnectionInfo {
|
|
345
|
-
state: ConnectionState;
|
|
346
|
-
agentId: string;
|
|
347
|
-
signalingServer: string;
|
|
348
|
-
connectedAt?: number;
|
|
349
|
-
error?: string;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// ============================================================================
|
|
353
|
-
// AI Types
|
|
354
|
-
// ============================================================================
|
|
355
|
-
|
|
356
|
-
export type ClaudeModel =
|
|
357
|
-
| 'claude-haiku-4-5'
|
|
358
|
-
| 'claude-sonnet-4-5'
|
|
359
|
-
| 'claude-opus-4-5';
|
|
360
|
-
|
|
361
|
-
export const CLAUDE_MODELS: { id: ClaudeModel; name: string; description: string }[] = [
|
|
362
|
-
{ id: 'claude-haiku-4-5', name: 'Haiku', description: 'Fast & affordable' },
|
|
363
|
-
{ id: 'claude-sonnet-4-5', name: 'Sonnet', description: 'Balanced speed & quality' },
|
|
364
|
-
{ id: 'claude-opus-4-5', name: 'Opus', description: 'Highest quality' },
|
|
365
|
-
];
|
|
366
|
-
|
|
367
|
-
// Generate Commit Summary
|
|
368
|
-
export interface GenerateCommitSummaryRequestPayload {
|
|
369
|
-
context?: string;
|
|
370
|
-
model?: ClaudeModel;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
export interface TokenUsage {
|
|
374
|
-
inputTokens: number;
|
|
375
|
-
outputTokens: number;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
export interface GenerateCommitSummaryResponsePayload {
|
|
379
|
-
success: boolean;
|
|
380
|
-
summary?: string;
|
|
381
|
-
description?: string;
|
|
382
|
-
error?: string;
|
|
383
|
-
errorCode?: 'NO_API_KEY' | 'NO_STAGED_CHANGES' | 'API_ERROR' | 'RATE_LIMITED';
|
|
384
|
-
tokenUsage?: TokenUsage;
|
|
385
|
-
cached?: boolean;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// API Key Management
|
|
389
|
-
export interface SetApiKeyRequestPayload {
|
|
390
|
-
apiKey: string;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
export interface SetApiKeyResponsePayload {
|
|
394
|
-
success: boolean;
|
|
395
|
-
error?: string;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
export interface GetApiKeyStatusResponsePayload {
|
|
399
|
-
configured: boolean;
|
|
400
|
-
}
|