@agi-cli/server 0.1.147 → 0.1.149

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agi-cli/server",
3
- "version": "0.1.147",
3
+ "version": "0.1.149",
4
4
  "description": "HTTP API server for AGI CLI",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -29,8 +29,8 @@
29
29
  "typecheck": "tsc --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "@agi-cli/sdk": "0.1.147",
33
- "@agi-cli/database": "0.1.147",
32
+ "@agi-cli/sdk": "0.1.149",
33
+ "@agi-cli/database": "0.1.149",
34
34
  "drizzle-orm": "^0.44.5",
35
35
  "hono": "^4.9.9",
36
36
  "zod": "^4.1.8"
@@ -228,7 +228,12 @@ export const schemas = {
228
228
  type: 'array',
229
229
  items: { $ref: '#/components/schemas/GitFile' },
230
230
  },
231
+ conflicted: {
232
+ type: 'array',
233
+ items: { $ref: '#/components/schemas/GitFile' },
234
+ },
231
235
  hasChanges: { type: 'boolean' },
236
+ hasConflicts: { type: 'boolean' },
232
237
  },
233
238
  required: [
234
239
  'branch',
@@ -237,7 +242,9 @@ export const schemas = {
237
242
  'staged',
238
243
  'unstaged',
239
244
  'untracked',
245
+ 'conflicted',
240
246
  'hasChanges',
247
+ 'hasConflicts',
241
248
  ],
242
249
  },
243
250
  GitFile: {
@@ -246,12 +253,29 @@ export const schemas = {
246
253
  path: { type: 'string' },
247
254
  status: {
248
255
  type: 'string',
249
- enum: ['modified', 'added', 'deleted', 'renamed', 'untracked'],
256
+ enum: [
257
+ 'modified',
258
+ 'added',
259
+ 'deleted',
260
+ 'renamed',
261
+ 'untracked',
262
+ 'conflicted',
263
+ ],
250
264
  },
251
265
  staged: { type: 'boolean' },
252
266
  insertions: { type: 'integer' },
253
267
  deletions: { type: 'integer' },
254
268
  oldPath: { type: 'string' },
269
+ conflictType: {
270
+ type: 'string',
271
+ enum: [
272
+ 'both-modified',
273
+ 'deleted-by-us',
274
+ 'deleted-by-them',
275
+ 'both-added',
276
+ 'both-deleted',
277
+ ],
278
+ },
255
279
  },
256
280
  required: ['path', 'status', 'staged'],
257
281
  },
@@ -36,7 +36,7 @@ export function registerStatusRoute(app: Hono) {
36
36
  { cwd: gitRoot },
37
37
  );
38
38
 
39
- const { staged, unstaged, untracked } = parseGitStatus(
39
+ const { staged, unstaged, untracked, conflicted } = parseGitStatus(
40
40
  statusOutput,
41
41
  gitRoot,
42
42
  );
@@ -46,7 +46,12 @@ export function registerStatusRoute(app: Hono) {
46
46
  const branch = await getCurrentBranch(gitRoot);
47
47
 
48
48
  const hasChanges =
49
- staged.length > 0 || unstaged.length > 0 || untracked.length > 0;
49
+ staged.length > 0 ||
50
+ unstaged.length > 0 ||
51
+ untracked.length > 0 ||
52
+ conflicted.length > 0;
53
+
54
+ const hasConflicts = conflicted.length > 0;
50
55
 
51
56
  return c.json({
52
57
  status: 'ok',
@@ -59,7 +64,9 @@ export function registerStatusRoute(app: Hono) {
59
64
  staged,
60
65
  unstaged,
61
66
  untracked,
67
+ conflicted,
62
68
  hasChanges,
69
+ hasConflicts,
63
70
  },
64
71
  });
65
72
  } catch (error) {
@@ -1,12 +1,24 @@
1
1
  export interface GitFile {
2
2
  path: string;
3
3
  absPath: string;
4
- status: 'modified' | 'added' | 'deleted' | 'renamed' | 'untracked';
4
+ status:
5
+ | 'modified'
6
+ | 'added'
7
+ | 'deleted'
8
+ | 'renamed'
9
+ | 'untracked'
10
+ | 'conflicted';
5
11
  staged: boolean;
6
12
  insertions?: number;
7
13
  deletions?: number;
8
14
  oldPath?: string;
9
15
  isNew: boolean;
16
+ conflictType?:
17
+ | 'both-modified'
18
+ | 'deleted-by-us'
19
+ | 'deleted-by-them'
20
+ | 'both-added'
21
+ | 'both-deleted';
10
22
  }
11
23
 
12
24
  export interface GitRoot {
@@ -121,6 +121,25 @@ function getStatusFromCodeV2(code: string): GitFile['status'] {
121
121
  }
122
122
  }
123
123
 
124
+ function getConflictType(xy: string): GitFile['conflictType'] {
125
+ switch (xy) {
126
+ case 'UU':
127
+ return 'both-modified';
128
+ case 'AA':
129
+ return 'both-added';
130
+ case 'DD':
131
+ return 'both-deleted';
132
+ case 'DU':
133
+ case 'UD':
134
+ return 'deleted-by-us';
135
+ case 'AU':
136
+ case 'UA':
137
+ return 'deleted-by-them';
138
+ default:
139
+ return 'both-modified';
140
+ }
141
+ }
142
+
124
143
  export function parseGitStatus(
125
144
  statusOutput: string,
126
145
  gitRoot: string,
@@ -128,11 +147,13 @@ export function parseGitStatus(
128
147
  staged: GitFile[];
129
148
  unstaged: GitFile[];
130
149
  untracked: GitFile[];
150
+ conflicted: GitFile[];
131
151
  } {
132
152
  const lines = statusOutput.trim().split('\n').filter(Boolean);
133
153
  const staged: GitFile[] = [];
134
154
  const unstaged: GitFile[] = [];
135
155
  const untracked: GitFile[] = [];
156
+ const conflicted: GitFile[] = [];
136
157
 
137
158
  for (const line of lines) {
138
159
  if (line.startsWith('1 ') || line.startsWith('2 ')) {
@@ -174,10 +195,26 @@ export function parseGitStatus(
174
195
  staged: false,
175
196
  isNew: true,
176
197
  });
198
+ } else if (line.startsWith('u ')) {
199
+ const parts = line.split(' ');
200
+ if (parts.length < 11) continue;
201
+
202
+ const xy = parts[1];
203
+ const path = parts.slice(10).join(' ');
204
+ const absPath = join(gitRoot, path);
205
+
206
+ conflicted.push({
207
+ path,
208
+ absPath,
209
+ status: 'conflicted',
210
+ staged: false,
211
+ isNew: false,
212
+ conflictType: getConflictType(xy),
213
+ });
177
214
  }
178
215
  }
179
216
 
180
- return { staged, unstaged, untracked };
217
+ return { staged, unstaged, untracked, conflicted };
181
218
  }
182
219
 
183
220
  export async function getAheadBehind(
@@ -8,7 +8,7 @@ import {
8
8
  messageParts,
9
9
  shares,
10
10
  } from '@agi-cli/database/schema';
11
- import { desc, eq, and, ne, inArray } from 'drizzle-orm';
11
+ import { desc, eq, and, ne, inArray, or } from 'drizzle-orm';
12
12
  import type { ProviderId } from '@agi-cli/sdk';
13
13
  import { isProviderId, catalog } from '@agi-cli/sdk';
14
14
  import { resolveAgentConfig } from '../runtime/agent/registry.ts';
@@ -745,10 +745,21 @@ export function registerSessionsRoutes(app: Hono) {
745
745
  return c.json({ error: 'Session not found' }, 404);
746
746
  }
747
747
 
748
- // Delete existing message parts (the error content)
748
+ // Delete only error parts - preserve valid text/tool content
749
749
  await db
750
750
  .delete(messageParts)
751
- .where(eq(messageParts.messageId, messageId));
751
+ .where(
752
+ and(
753
+ eq(messageParts.messageId, messageId),
754
+ or(
755
+ eq(messageParts.type, 'error'),
756
+ and(
757
+ eq(messageParts.type, 'tool_call'),
758
+ eq(messageParts.toolName, 'finish'),
759
+ ),
760
+ ),
761
+ ),
762
+ );
752
763
 
753
764
  // Reset message status to pending
754
765
  await db