@lovelybunch/api 1.0.69-alpha.7 → 1.0.69-alpha.9

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.
@@ -4,6 +4,7 @@ export interface UserProfile {
4
4
  lastName?: string;
5
5
  email?: string;
6
6
  role?: AgentRoleId;
7
+ roleDescription?: string;
7
8
  }
8
9
  export interface UserPreferences {
9
10
  theme?: 'light' | 'dark' | 'coconut' | 'system';
@@ -16,7 +16,7 @@ export declare function PUT(c: Context): Promise<(Response & import("hono").Type
16
16
  error: string;
17
17
  }, 500, "json">) | (Response & import("hono").TypedResponse<{
18
18
  error: string;
19
- }, 405, "json">)>;
19
+ }, 404, "json">)>;
20
20
  export declare function TEST(c: Context): Promise<(Response & import("hono").TypedResponse<{
21
21
  success: false;
22
22
  message: string;
@@ -124,7 +124,51 @@ export async function PUT(c) {
124
124
  }
125
125
  }
126
126
  else {
127
- return c.json({ error: 'PUT not supported for project config' }, 405);
127
+ // Update project config (coconut object)
128
+ try {
129
+ const body = await c.req.json();
130
+ const { coconut } = body;
131
+ if (!coconut) {
132
+ return c.json({ error: 'Missing coconut object in request body' }, 400);
133
+ }
134
+ const configPath = await getConfigPath();
135
+ if (!configPath) {
136
+ return c.json({ error: 'GAIT directory not found' }, 404);
137
+ }
138
+ // Load existing config
139
+ let config = {};
140
+ try {
141
+ const content = await fs.readFile(configPath, 'utf-8');
142
+ config = JSON.parse(content);
143
+ }
144
+ catch (error) {
145
+ if (error.code === 'ENOENT') {
146
+ config = {};
147
+ }
148
+ else {
149
+ throw error;
150
+ }
151
+ }
152
+ // Ensure .nut directory exists
153
+ const configDir = path.dirname(configPath);
154
+ await fs.mkdir(configDir, { recursive: true });
155
+ // Merge coconut object with existing config
156
+ config.coconut = {
157
+ ...config.coconut,
158
+ ...coconut,
159
+ };
160
+ // Save config
161
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
162
+ return c.json({
163
+ success: true,
164
+ message: 'Project configuration updated successfully',
165
+ data: config
166
+ });
167
+ }
168
+ catch (error) {
169
+ console.error('Error updating project config:', error);
170
+ return c.json({ error: 'Failed to update project config' }, 500);
171
+ }
128
172
  }
129
173
  }
130
174
  // POST /api/v1/config/test
@@ -341,6 +341,46 @@ app.post('/commits', async (c) => {
341
341
  return c.json({ success: false, error: { message: e.message } }, 500);
342
342
  }
343
343
  });
344
+ // Discard file changes
345
+ app.post('/discard', async (c) => {
346
+ try {
347
+ const body = await c.req.json();
348
+ const filePath = String(body?.file || body?.path || '');
349
+ if (!filePath) {
350
+ return c.json({ success: false, error: { message: 'file path required' } }, 400);
351
+ }
352
+ const { runGit, getRepoStatus } = await import('../../../../lib/git.js');
353
+ // Get current status to determine file state
354
+ const status = await getRepoStatus();
355
+ const fileChange = status.changes.find((c) => c.path === filePath);
356
+ if (!fileChange) {
357
+ return c.json({ success: false, error: { message: 'File not found in uncommitted changes' } }, 404);
358
+ }
359
+ const statusCode = fileChange.status.trim();
360
+ // Handle different file statuses
361
+ if (statusCode === '??' || statusCode.includes('U')) {
362
+ // Untracked file - remove it
363
+ const { unlink } = await import('fs/promises');
364
+ const { getRepoRoot } = await import('../../../../lib/git.js');
365
+ const repoRoot = await getRepoRoot();
366
+ const { join } = await import('path');
367
+ const fullPath = join(repoRoot, filePath);
368
+ await unlink(fullPath);
369
+ }
370
+ else if (statusCode.includes('D')) {
371
+ // Deleted file - restore it
372
+ await runGit(['checkout', '--', filePath]);
373
+ }
374
+ else {
375
+ // Modified or Added file - discard changes
376
+ await runGit(['checkout', '--', filePath]);
377
+ }
378
+ return c.json({ success: true, data: { file: filePath, status: statusCode } });
379
+ }
380
+ catch (e) {
381
+ return c.json({ success: false, error: { message: e.message } }, 500);
382
+ }
383
+ });
344
384
  // Push / Pull (current)
345
385
  app.post('/push', async (c) => {
346
386
  try {
@@ -1,5 +1,8 @@
1
1
  import { Hono } from 'hono';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
2
4
  import { loadUserSettings, saveUserSettings } from '../../../../../lib/user-preferences.js';
5
+ import { findGaitDirectory } from '../../../../../lib/gait-path.js';
3
6
  const app = new Hono();
4
7
  /**
5
8
  * GET /api/v1/user/settings
@@ -22,9 +25,9 @@ app.get('/', async (c) => {
22
25
  app.put('/', async (c) => {
23
26
  try {
24
27
  const body = await c.req.json();
25
- const { profile, preferences } = body;
26
- if (!profile && !preferences) {
27
- return c.json({ success: false, error: 'Profile or preferences data required' }, 400);
28
+ const { profile, preferences, coconut } = body;
29
+ if (!profile && !preferences && !coconut) {
30
+ return c.json({ success: false, error: 'Profile, preferences, or coconut data required' }, 400);
28
31
  }
29
32
  let settings = await loadUserSettings();
30
33
  if (profile) {
@@ -41,6 +44,43 @@ app.put('/', async (c) => {
41
44
  };
42
45
  }
43
46
  await saveUserSettings(settings);
47
+ // If coconut.id is provided, update .nut/config.json
48
+ if (coconut?.id) {
49
+ try {
50
+ const gaitDir = await findGaitDirectory();
51
+ if (gaitDir) {
52
+ const configPath = path.join(gaitDir, 'config.json');
53
+ // Load existing config
54
+ let config = {};
55
+ try {
56
+ const content = await fs.readFile(configPath, 'utf-8');
57
+ config = JSON.parse(content);
58
+ }
59
+ catch (error) {
60
+ if (error.code === 'ENOENT') {
61
+ config = {};
62
+ }
63
+ else {
64
+ throw error;
65
+ }
66
+ }
67
+ // Ensure .nut directory exists
68
+ const configDir = path.dirname(configPath);
69
+ await fs.mkdir(configDir, { recursive: true });
70
+ // Update coconut.id
71
+ if (!config.coconut) {
72
+ config.coconut = {};
73
+ }
74
+ config.coconut.id = coconut.id;
75
+ // Save config
76
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
77
+ }
78
+ }
79
+ catch (error) {
80
+ console.error('Failed to update coconut.id in config.json:', error);
81
+ // Don't fail the request if config update fails
82
+ }
83
+ }
44
84
  return c.json({ success: true, data: settings });
45
85
  }
46
86
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovelybunch/api",
3
- "version": "1.0.69-alpha.7",
3
+ "version": "1.0.69-alpha.9",
4
4
  "type": "module",
5
5
  "main": "dist/server-with-static.js",
6
6
  "exports": {
@@ -36,9 +36,9 @@
36
36
  "dependencies": {
37
37
  "@hono/node-server": "^1.13.7",
38
38
  "@hono/node-ws": "^1.0.6",
39
- "@lovelybunch/core": "^1.0.69-alpha.7",
40
- "@lovelybunch/mcp": "^1.0.69-alpha.7",
41
- "@lovelybunch/types": "^1.0.69-alpha.7",
39
+ "@lovelybunch/core": "^1.0.69-alpha.9",
40
+ "@lovelybunch/mcp": "^1.0.69-alpha.9",
41
+ "@lovelybunch/types": "^1.0.69-alpha.9",
42
42
  "arctic": "^1.9.2",
43
43
  "bcrypt": "^5.1.1",
44
44
  "cookie": "^0.6.0",