@lovelybunch/api 1.0.7
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/lib/gait-path.d.ts +13 -0
- package/dist/lib/gait-path.js +57 -0
- package/dist/lib/project-paths.d.ts +13 -0
- package/dist/lib/project-paths.js +57 -0
- package/dist/lib/storage/file-storage.d.ts +28 -0
- package/dist/lib/storage/file-storage.js +224 -0
- package/dist/lib/symlinks/symlink-manager.d.ts +66 -0
- package/dist/lib/symlinks/symlink-manager.js +444 -0
- package/dist/lib/symlinks/types.d.ts +23 -0
- package/dist/lib/symlinks/types.js +4 -0
- package/dist/lib/terminal/context-helper.d.ts +11 -0
- package/dist/lib/terminal/context-helper.js +164 -0
- package/dist/lib/terminal/global-manager.d.ts +2 -0
- package/dist/lib/terminal/global-manager.js +15 -0
- package/dist/lib/terminal/shell-utils.d.ts +33 -0
- package/dist/lib/terminal/shell-utils.js +176 -0
- package/dist/lib/terminal/terminal-manager.d.ts +26 -0
- package/dist/lib/terminal/terminal-manager.js +276 -0
- package/dist/lib/user-preferences.d.ts +48 -0
- package/dist/lib/user-preferences.js +87 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/routes/api/symlink-status/route.d.ts +1 -0
- package/dist/routes/api/symlink-status/route.js +37 -0
- package/dist/routes/api/symlinks/[id]/route.d.ts +19 -0
- package/dist/routes/api/symlinks/[id]/route.js +95 -0
- package/dist/routes/api/symlinks/[id]/toggle/route.d.ts +11 -0
- package/dist/routes/api/symlinks/[id]/toggle/route.js +32 -0
- package/dist/routes/api/symlinks/debug/route.d.ts +1 -0
- package/dist/routes/api/symlinks/debug/route.js +35 -0
- package/dist/routes/api/symlinks/route.d.ts +9 -0
- package/dist/routes/api/symlinks/route.js +72 -0
- package/dist/routes/api/toggle-symlink/route.d.ts +2 -0
- package/dist/routes/api/toggle-symlink/route.js +94 -0
- package/dist/routes/api/v1/agents/[id]/index.d.ts +1 -0
- package/dist/routes/api/v1/agents/[id]/index.js +1 -0
- package/dist/routes/api/v1/agents/[id]/route.d.ts +3 -0
- package/dist/routes/api/v1/agents/[id]/route.js +163 -0
- package/dist/routes/api/v1/agents/index.d.ts +1 -0
- package/dist/routes/api/v1/agents/index.js +1 -0
- package/dist/routes/api/v1/agents/route.d.ts +3 -0
- package/dist/routes/api/v1/agents/route.js +133 -0
- package/dist/routes/api/v1/ai/index.d.ts +3 -0
- package/dist/routes/api/v1/ai/index.js +5 -0
- package/dist/routes/api/v1/ai/route.d.ts +8 -0
- package/dist/routes/api/v1/ai/route.js +86 -0
- package/dist/routes/api/v1/chats/[id]/index.d.ts +3 -0
- package/dist/routes/api/v1/chats/[id]/index.js +6 -0
- package/dist/routes/api/v1/chats/[id]/route.d.ts +12 -0
- package/dist/routes/api/v1/chats/[id]/route.js +31 -0
- package/dist/routes/api/v1/chats/index.d.ts +3 -0
- package/dist/routes/api/v1/chats/index.js +6 -0
- package/dist/routes/api/v1/chats/route.d.ts +32 -0
- package/dist/routes/api/v1/chats/route.js +67 -0
- package/dist/routes/api/v1/config/index.d.ts +3 -0
- package/dist/routes/api/v1/config/index.js +5 -0
- package/dist/routes/api/v1/config/route.d.ts +9 -0
- package/dist/routes/api/v1/config/route.js +29 -0
- package/dist/routes/api/v1/context/[...path]/route.d.ts +16 -0
- package/dist/routes/api/v1/context/[...path]/route.js +107 -0
- package/dist/routes/api/v1/context/architecture/route.d.ts +3 -0
- package/dist/routes/api/v1/context/architecture/route.js +198 -0
- package/dist/routes/api/v1/context/index.d.ts +3 -0
- package/dist/routes/api/v1/context/index.js +9 -0
- package/dist/routes/api/v1/context/knowledge/[filename]/index.d.ts +1 -0
- package/dist/routes/api/v1/context/knowledge/[filename]/index.js +1 -0
- package/dist/routes/api/v1/context/knowledge/[filename]/route.d.ts +3 -0
- package/dist/routes/api/v1/context/knowledge/[filename]/route.js +165 -0
- package/dist/routes/api/v1/context/knowledge/index.d.ts +1 -0
- package/dist/routes/api/v1/context/knowledge/index.js +1 -0
- package/dist/routes/api/v1/context/knowledge/route.d.ts +3 -0
- package/dist/routes/api/v1/context/knowledge/route.js +121 -0
- package/dist/routes/api/v1/context/project/route.d.ts +3 -0
- package/dist/routes/api/v1/context/project/route.js +153 -0
- package/dist/routes/api/v1/proposals/[id]/route.d.ts +337 -0
- package/dist/routes/api/v1/proposals/[id]/route.js +99 -0
- package/dist/routes/api/v1/proposals/index.d.ts +3 -0
- package/dist/routes/api/v1/proposals/index.js +10 -0
- package/dist/routes/api/v1/proposals/route.d.ts +315 -0
- package/dist/routes/api/v1/proposals/route.js +103 -0
- package/dist/routes/api/v1/resources/[id]/index.d.ts +3 -0
- package/dist/routes/api/v1/resources/[id]/index.js +7 -0
- package/dist/routes/api/v1/resources/[id]/route.d.ts +46 -0
- package/dist/routes/api/v1/resources/[id]/route.js +143 -0
- package/dist/routes/api/v1/resources/[id]/thumbnail/index.d.ts +3 -0
- package/dist/routes/api/v1/resources/[id]/thumbnail/index.js +5 -0
- package/dist/routes/api/v1/resources/[id]/thumbnail/route.d.ts +2 -0
- package/dist/routes/api/v1/resources/[id]/thumbnail/route.js +50 -0
- package/dist/routes/api/v1/resources/index.d.ts +3 -0
- package/dist/routes/api/v1/resources/index.js +6 -0
- package/dist/routes/api/v1/resources/route.d.ts +51 -0
- package/dist/routes/api/v1/resources/route.js +147 -0
- package/dist/routes/api/v1/search/route.d.ts +3 -0
- package/dist/routes/api/v1/search/route.js +39 -0
- package/dist/routes/api/v1/terminal/[proposalId]/create/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[proposalId]/create/index.js +5 -0
- package/dist/routes/api/v1/terminal/[proposalId]/create/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[proposalId]/create/route.js +27 -0
- package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[proposalId]/destroy/index.js +5 -0
- package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[proposalId]/destroy/route.js +21 -0
- package/dist/routes/api/v1/terminal/[proposalId]/resize/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/[proposalId]/resize/index.js +5 -0
- package/dist/routes/api/v1/terminal/[proposalId]/resize/route.d.ts +10 -0
- package/dist/routes/api/v1/terminal/[proposalId]/resize/route.js +21 -0
- package/dist/routes/api/v1/terminal/sessions/index.d.ts +3 -0
- package/dist/routes/api/v1/terminal/sessions/index.js +5 -0
- package/dist/routes/api/v1/terminal/sessions/route.d.ts +6 -0
- package/dist/routes/api/v1/terminal/sessions/route.js +29 -0
- package/dist/routes/api/v1/user/index.d.ts +3 -0
- package/dist/routes/api/v1/user/index.js +5 -0
- package/dist/routes/api/v1/user/preferences/route.d.ts +11 -0
- package/dist/routes/api/v1/user/preferences/route.js +31 -0
- package/dist/routes/api/v1/user/profile/route.d.ts +11 -0
- package/dist/routes/api/v1/user/profile/route.js +31 -0
- package/dist/routes/api/v1/user/settings/index.d.ts +1 -0
- package/dist/routes/api/v1/user/settings/index.js +1 -0
- package/dist/routes/api/v1/user/settings/route.d.ts +3 -0
- package/dist/routes/api/v1/user/settings/route.js +51 -0
- package/dist/server-with-static.d.ts +4 -0
- package/dist/server-with-static.js +144 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +91 -0
- package/package.json +42 -0
- package/static/assets/index-BvTnrm0O.js +576 -0
- package/static/assets/index-Cm5dZHTl.css +33 -0
- package/static/assets/index-ORkAkJNi.js +576 -0
- package/static/assets/index-_Keadpms.js +576 -0
- package/static/index.html +17 -0
- package/static/vite.svg +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import { getSymlinkPath } from '@/lib/project-paths';
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const symlinkPath = await getSymlinkPath();
|
|
7
|
+
try {
|
|
8
|
+
const stats = await fs.lstat(symlinkPath);
|
|
9
|
+
const exists = stats.isSymbolicLink();
|
|
10
|
+
return NextResponse.json({
|
|
11
|
+
success: true,
|
|
12
|
+
exists,
|
|
13
|
+
path: symlinkPath
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error.code === 'ENOENT') {
|
|
18
|
+
return NextResponse.json({
|
|
19
|
+
success: true,
|
|
20
|
+
exists: false,
|
|
21
|
+
path: symlinkPath
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('Error checking symlink status:', error);
|
|
29
|
+
return NextResponse.json({
|
|
30
|
+
success: false,
|
|
31
|
+
error: {
|
|
32
|
+
code: 'SYMLINK_STATUS_ERROR',
|
|
33
|
+
message: error.message
|
|
34
|
+
}
|
|
35
|
+
}, { status: 500 });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
interface RouteParams {
|
|
3
|
+
params: {
|
|
4
|
+
id: string;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* GET /api/symlinks/[id] - Get a specific symlink configuration
|
|
9
|
+
*/
|
|
10
|
+
export declare function GET(request: NextRequest, { params }: RouteParams): Promise<any>;
|
|
11
|
+
/**
|
|
12
|
+
* PATCH /api/symlinks/[id] - Update a symlink configuration
|
|
13
|
+
*/
|
|
14
|
+
export declare function PATCH(request: NextRequest, { params }: RouteParams): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* DELETE /api/symlinks/[id] - Delete a symlink configuration
|
|
17
|
+
*/
|
|
18
|
+
export declare function DELETE(request: NextRequest, { params }: RouteParams): Promise<any>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSymlinkManager } from '@/lib/symlinks/symlink-manager';
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/symlinks/[id] - Get a specific symlink configuration
|
|
5
|
+
*/
|
|
6
|
+
export async function GET(request, { params }) {
|
|
7
|
+
try {
|
|
8
|
+
const manager = await getSymlinkManager();
|
|
9
|
+
const symlink = await manager.getSymlink(params.id);
|
|
10
|
+
if (!symlink) {
|
|
11
|
+
return NextResponse.json({
|
|
12
|
+
success: false,
|
|
13
|
+
error: {
|
|
14
|
+
code: 'NOT_FOUND',
|
|
15
|
+
message: `Symlink with ID ${params.id} not found`
|
|
16
|
+
}
|
|
17
|
+
}, { status: 404 });
|
|
18
|
+
}
|
|
19
|
+
return NextResponse.json({
|
|
20
|
+
success: true,
|
|
21
|
+
symlink
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error('Error fetching symlink:', error);
|
|
26
|
+
return NextResponse.json({
|
|
27
|
+
success: false,
|
|
28
|
+
error: {
|
|
29
|
+
code: 'FETCH_SYMLINK_ERROR',
|
|
30
|
+
message: error.message
|
|
31
|
+
}
|
|
32
|
+
}, { status: 500 });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* PATCH /api/symlinks/[id] - Update a symlink configuration
|
|
37
|
+
*/
|
|
38
|
+
export async function PATCH(request, { params }) {
|
|
39
|
+
try {
|
|
40
|
+
const body = await request.json();
|
|
41
|
+
const manager = await getSymlinkManager();
|
|
42
|
+
const result = await manager.updateSymlink(params.id, body);
|
|
43
|
+
if (!result.success) {
|
|
44
|
+
return NextResponse.json({
|
|
45
|
+
success: false,
|
|
46
|
+
error: {
|
|
47
|
+
code: 'UPDATE_SYMLINK_ERROR',
|
|
48
|
+
message: result.message,
|
|
49
|
+
details: result.error
|
|
50
|
+
}
|
|
51
|
+
}, { status: 400 });
|
|
52
|
+
}
|
|
53
|
+
return NextResponse.json(result);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('Error updating symlink:', error);
|
|
57
|
+
return NextResponse.json({
|
|
58
|
+
success: false,
|
|
59
|
+
error: {
|
|
60
|
+
code: 'UPDATE_SYMLINK_ERROR',
|
|
61
|
+
message: error.message
|
|
62
|
+
}
|
|
63
|
+
}, { status: 500 });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* DELETE /api/symlinks/[id] - Delete a symlink configuration
|
|
68
|
+
*/
|
|
69
|
+
export async function DELETE(request, { params }) {
|
|
70
|
+
try {
|
|
71
|
+
const manager = await getSymlinkManager();
|
|
72
|
+
const result = await manager.deleteSymlink(params.id);
|
|
73
|
+
if (!result.success) {
|
|
74
|
+
return NextResponse.json({
|
|
75
|
+
success: false,
|
|
76
|
+
error: {
|
|
77
|
+
code: 'DELETE_SYMLINK_ERROR',
|
|
78
|
+
message: result.message,
|
|
79
|
+
details: result.error
|
|
80
|
+
}
|
|
81
|
+
}, { status: 400 });
|
|
82
|
+
}
|
|
83
|
+
return NextResponse.json(result);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error('Error deleting symlink:', error);
|
|
87
|
+
return NextResponse.json({
|
|
88
|
+
success: false,
|
|
89
|
+
error: {
|
|
90
|
+
code: 'DELETE_SYMLINK_ERROR',
|
|
91
|
+
message: error.message
|
|
92
|
+
}
|
|
93
|
+
}, { status: 500 });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
interface RouteParams {
|
|
3
|
+
params: {
|
|
4
|
+
id: string;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* POST /api/symlinks/[id]/toggle - Toggle a symlink on/off
|
|
9
|
+
*/
|
|
10
|
+
export declare function POST(request: NextRequest, { params }: RouteParams): Promise<any>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSymlinkManager } from '@/lib/symlinks/symlink-manager';
|
|
3
|
+
/**
|
|
4
|
+
* POST /api/symlinks/[id]/toggle - Toggle a symlink on/off
|
|
5
|
+
*/
|
|
6
|
+
export async function POST(request, { params }) {
|
|
7
|
+
try {
|
|
8
|
+
const manager = await getSymlinkManager();
|
|
9
|
+
const result = await manager.toggleSymlink(params.id);
|
|
10
|
+
if (!result.success) {
|
|
11
|
+
return NextResponse.json({
|
|
12
|
+
success: false,
|
|
13
|
+
error: {
|
|
14
|
+
code: 'TOGGLE_SYMLINK_ERROR',
|
|
15
|
+
message: result.message,
|
|
16
|
+
details: result.error
|
|
17
|
+
}
|
|
18
|
+
}, { status: 400 });
|
|
19
|
+
}
|
|
20
|
+
return NextResponse.json(result);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error('Error toggling symlink:', error);
|
|
24
|
+
return NextResponse.json({
|
|
25
|
+
success: false,
|
|
26
|
+
error: {
|
|
27
|
+
code: 'TOGGLE_SYMLINK_ERROR',
|
|
28
|
+
message: error.message
|
|
29
|
+
}
|
|
30
|
+
}, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function GET(): Promise<any>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
export async function GET() {
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
const calculatedRoot = path.resolve(cwd, '../..');
|
|
7
|
+
const envRoot = process.env.GAIT_PROJECT_ROOT;
|
|
8
|
+
// Check what files exist
|
|
9
|
+
const checks = {
|
|
10
|
+
cwd,
|
|
11
|
+
calculatedRoot,
|
|
12
|
+
envRoot: envRoot || 'not set',
|
|
13
|
+
gaitDirExists: false,
|
|
14
|
+
symlinksJsonExists: false,
|
|
15
|
+
symlinksJsonPath: path.join(calculatedRoot, '.gait', 'symlinks.json'),
|
|
16
|
+
actualFiles: []
|
|
17
|
+
};
|
|
18
|
+
try {
|
|
19
|
+
await fs.access(path.join(calculatedRoot, '.gait'));
|
|
20
|
+
checks.gaitDirExists = true;
|
|
21
|
+
const files = await fs.readdir(path.join(calculatedRoot, '.gait'));
|
|
22
|
+
checks.actualFiles = files;
|
|
23
|
+
try {
|
|
24
|
+
await fs.access(checks.symlinksJsonPath);
|
|
25
|
+
checks.symlinksJsonExists = true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// File doesn't exist
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Directory doesn't exist
|
|
33
|
+
}
|
|
34
|
+
return NextResponse.json(checks);
|
|
35
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
/**
|
|
3
|
+
* GET /api/symlinks - Get all symlink configurations
|
|
4
|
+
*/
|
|
5
|
+
export declare function GET(): Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* POST /api/symlinks - Add a new symlink configuration
|
|
8
|
+
*/
|
|
9
|
+
export declare function POST(request: NextRequest): Promise<any>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSymlinkManager } from '@/lib/symlinks/symlink-manager';
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/symlinks - Get all symlink configurations
|
|
5
|
+
*/
|
|
6
|
+
export async function GET() {
|
|
7
|
+
try {
|
|
8
|
+
const manager = await getSymlinkManager();
|
|
9
|
+
const symlinks = await manager.getSymlinks();
|
|
10
|
+
return NextResponse.json({
|
|
11
|
+
success: true,
|
|
12
|
+
symlinks
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error('Error fetching symlinks:', error);
|
|
17
|
+
return NextResponse.json({
|
|
18
|
+
success: false,
|
|
19
|
+
error: {
|
|
20
|
+
code: 'FETCH_SYMLINKS_ERROR',
|
|
21
|
+
message: error.message
|
|
22
|
+
}
|
|
23
|
+
}, { status: 500 });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* POST /api/symlinks - Add a new symlink configuration
|
|
28
|
+
*/
|
|
29
|
+
export async function POST(request) {
|
|
30
|
+
try {
|
|
31
|
+
const body = await request.json();
|
|
32
|
+
const { name, description, linkPath, targetPath, isActive } = body;
|
|
33
|
+
if (!name || !linkPath || !targetPath) {
|
|
34
|
+
return NextResponse.json({
|
|
35
|
+
success: false,
|
|
36
|
+
error: {
|
|
37
|
+
code: 'INVALID_REQUEST',
|
|
38
|
+
message: 'Missing required fields: name, linkPath, targetPath'
|
|
39
|
+
}
|
|
40
|
+
}, { status: 400 });
|
|
41
|
+
}
|
|
42
|
+
const manager = await getSymlinkManager();
|
|
43
|
+
const result = await manager.addSymlink({
|
|
44
|
+
name,
|
|
45
|
+
description,
|
|
46
|
+
linkPath,
|
|
47
|
+
targetPath,
|
|
48
|
+
isActive: isActive || false
|
|
49
|
+
});
|
|
50
|
+
if (!result.success) {
|
|
51
|
+
return NextResponse.json({
|
|
52
|
+
success: false,
|
|
53
|
+
error: {
|
|
54
|
+
code: 'ADD_SYMLINK_ERROR',
|
|
55
|
+
message: result.message,
|
|
56
|
+
details: result.error
|
|
57
|
+
}
|
|
58
|
+
}, { status: 400 });
|
|
59
|
+
}
|
|
60
|
+
return NextResponse.json(result);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('Error adding symlink:', error);
|
|
64
|
+
return NextResponse.json({
|
|
65
|
+
success: false,
|
|
66
|
+
error: {
|
|
67
|
+
code: 'ADD_SYMLINK_ERROR',
|
|
68
|
+
message: error.message
|
|
69
|
+
}
|
|
70
|
+
}, { status: 500 });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { getSymlinkPath, getTargetPath } from '@/lib/project-paths';
|
|
5
|
+
export async function POST(request) {
|
|
6
|
+
try {
|
|
7
|
+
const body = await request.json();
|
|
8
|
+
const { active } = body;
|
|
9
|
+
const symlinkPath = await getSymlinkPath();
|
|
10
|
+
const targetPath = await getTargetPath();
|
|
11
|
+
if (active) {
|
|
12
|
+
// Create symlink
|
|
13
|
+
try {
|
|
14
|
+
// Ensure the target directory and file exist
|
|
15
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
16
|
+
// Check if target file exists, create if not
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(targetPath);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
await fs.writeFile(targetPath, `# Claude Rules
|
|
22
|
+
|
|
23
|
+
This file contains project-specific rules and guidelines for Claude AI assistant.
|
|
24
|
+
|
|
25
|
+
## Project Context
|
|
26
|
+
Add project-specific context and guidelines here.
|
|
27
|
+
|
|
28
|
+
## Coding Standards
|
|
29
|
+
Add coding standards and conventions here.
|
|
30
|
+
|
|
31
|
+
## Best Practices
|
|
32
|
+
Add best practices and patterns specific to this project.
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
// Remove existing file/symlink if it exists
|
|
36
|
+
try {
|
|
37
|
+
await fs.unlink(symlinkPath);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code !== 'ENOENT')
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
// Create the symlink
|
|
44
|
+
await fs.symlink(targetPath, symlinkPath);
|
|
45
|
+
return NextResponse.json({
|
|
46
|
+
success: true,
|
|
47
|
+
message: 'Symlink created successfully',
|
|
48
|
+
active: true,
|
|
49
|
+
symlinkPath,
|
|
50
|
+
targetPath
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to create symlink: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Remove symlink
|
|
59
|
+
try {
|
|
60
|
+
const stats = await fs.lstat(symlinkPath);
|
|
61
|
+
if (stats.isSymbolicLink()) {
|
|
62
|
+
await fs.unlink(symlinkPath);
|
|
63
|
+
}
|
|
64
|
+
return NextResponse.json({
|
|
65
|
+
success: true,
|
|
66
|
+
message: 'Symlink removed successfully',
|
|
67
|
+
active: false,
|
|
68
|
+
symlinkPath
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error.code === 'ENOENT') {
|
|
73
|
+
return NextResponse.json({
|
|
74
|
+
success: true,
|
|
75
|
+
message: 'No symlink to remove',
|
|
76
|
+
active: false,
|
|
77
|
+
symlinkPath
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
throw new Error(`Failed to remove symlink: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('Error toggling symlink:', error);
|
|
86
|
+
return NextResponse.json({
|
|
87
|
+
success: false,
|
|
88
|
+
error: {
|
|
89
|
+
code: 'TOGGLE_SYMLINK_ERROR',
|
|
90
|
+
message: error.message
|
|
91
|
+
}
|
|
92
|
+
}, { status: 500 });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import matter from 'gray-matter';
|
|
5
|
+
const app = new Hono();
|
|
6
|
+
function getAgentsPath() {
|
|
7
|
+
const basePath = process.env.GAIT_DATA_PATH ?
|
|
8
|
+
path.resolve(process.env.GAIT_DATA_PATH, '.gait') :
|
|
9
|
+
path.resolve(process.cwd(), '.gait');
|
|
10
|
+
return path.join(basePath, 'agents');
|
|
11
|
+
}
|
|
12
|
+
function generateFilename(name) {
|
|
13
|
+
// Convert name to filename-safe format
|
|
14
|
+
return name
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
|
|
17
|
+
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
|
18
|
+
.replace(/--+/g, '-') // Replace multiple hyphens with single
|
|
19
|
+
.replace(/^-|-$/g, '') // Remove leading/trailing hyphens
|
|
20
|
+
+ '.md';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* GET /api/v1/agents/:id
|
|
24
|
+
* Load a specific agent document
|
|
25
|
+
*/
|
|
26
|
+
app.get('/:id', async (c) => {
|
|
27
|
+
try {
|
|
28
|
+
const id = c.req.param('id');
|
|
29
|
+
const agentsPath = getAgentsPath();
|
|
30
|
+
const filename = id.endsWith('.md') ? id : `${id}.md`;
|
|
31
|
+
const filePath = path.join(agentsPath, filename);
|
|
32
|
+
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
33
|
+
const { data, content } = matter(fileContent);
|
|
34
|
+
// Extract title from name in frontmatter or use filename
|
|
35
|
+
const title = data.name ||
|
|
36
|
+
filename.replace('.md', '').replace(/[_-]/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase());
|
|
37
|
+
const document = {
|
|
38
|
+
filename,
|
|
39
|
+
metadata: {
|
|
40
|
+
name: data.name || title,
|
|
41
|
+
description: data.description || '',
|
|
42
|
+
color: data.color,
|
|
43
|
+
tools: data.tools,
|
|
44
|
+
...data
|
|
45
|
+
},
|
|
46
|
+
content,
|
|
47
|
+
title
|
|
48
|
+
};
|
|
49
|
+
return c.json({
|
|
50
|
+
success: true,
|
|
51
|
+
document
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error.code === 'ENOENT') {
|
|
56
|
+
return c.json({ success: false, error: 'Agent document not found' }, 404);
|
|
57
|
+
}
|
|
58
|
+
console.error('Error loading agent document:', error);
|
|
59
|
+
return c.json({ success: false, error: 'Failed to load agent document' }, 500);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* PUT /api/v1/agents/:id
|
|
64
|
+
* Update a specific agent document
|
|
65
|
+
*/
|
|
66
|
+
app.put('/:id', async (c) => {
|
|
67
|
+
try {
|
|
68
|
+
const id = c.req.param('id');
|
|
69
|
+
const body = await c.req.json();
|
|
70
|
+
const agentsPath = getAgentsPath();
|
|
71
|
+
const filename = id.endsWith('.md') ? id : `${id}.md`;
|
|
72
|
+
const filePath = path.join(agentsPath, filename);
|
|
73
|
+
// Check if file exists
|
|
74
|
+
try {
|
|
75
|
+
await fs.access(filePath);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return c.json({ success: false, error: 'Agent document not found' }, 404);
|
|
79
|
+
}
|
|
80
|
+
// Read current content
|
|
81
|
+
const currentContent = await fs.readFile(filePath, 'utf-8');
|
|
82
|
+
const { data: currentData, content: currentMarkdown } = matter(currentContent);
|
|
83
|
+
// Prepare updated content
|
|
84
|
+
const updatedContent = body.content !== undefined ? body.content : currentMarkdown;
|
|
85
|
+
const updatedMetadata = {
|
|
86
|
+
...currentData,
|
|
87
|
+
...body.metadata,
|
|
88
|
+
name: body.name !== undefined ? body.name : currentData.name,
|
|
89
|
+
description: body.description !== undefined ? body.description : currentData.description
|
|
90
|
+
};
|
|
91
|
+
// Handle name change - might need to rename file
|
|
92
|
+
let newFilename = filename;
|
|
93
|
+
let newFilePath = filePath;
|
|
94
|
+
if (body.name && body.name !== currentData.name) {
|
|
95
|
+
newFilename = generateFilename(body.name);
|
|
96
|
+
newFilePath = path.join(agentsPath, newFilename);
|
|
97
|
+
// Check if new filename conflicts with existing file (unless it's the same file)
|
|
98
|
+
if (newFilename !== filename) {
|
|
99
|
+
try {
|
|
100
|
+
await fs.access(newFilePath);
|
|
101
|
+
return c.json({ success: false, error: 'An agent with this name already exists' }, 409);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// File doesn't exist, which is what we want
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Create the updated markdown content with frontmatter
|
|
109
|
+
const fileContent = matter.stringify(updatedContent, updatedMetadata);
|
|
110
|
+
// Write to new location (or same location if filename unchanged)
|
|
111
|
+
await fs.writeFile(newFilePath, fileContent, 'utf-8');
|
|
112
|
+
// If filename changed, delete old file
|
|
113
|
+
if (newFilename !== filename) {
|
|
114
|
+
await fs.unlink(filePath);
|
|
115
|
+
}
|
|
116
|
+
// Extract updated title
|
|
117
|
+
const title = updatedMetadata.name ||
|
|
118
|
+
newFilename.replace('.md', '').replace(/[_-]/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase());
|
|
119
|
+
return c.json({
|
|
120
|
+
success: true,
|
|
121
|
+
document: {
|
|
122
|
+
filename: newFilename,
|
|
123
|
+
title,
|
|
124
|
+
metadata: updatedMetadata,
|
|
125
|
+
content: updatedContent
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error('Error updating agent document:', error);
|
|
131
|
+
return c.json({ success: false, error: 'Failed to update agent document' }, 500);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* DELETE /api/v1/agents/:id
|
|
136
|
+
* Delete a specific agent document
|
|
137
|
+
*/
|
|
138
|
+
app.delete('/:id', async (c) => {
|
|
139
|
+
try {
|
|
140
|
+
const id = c.req.param('id');
|
|
141
|
+
const agentsPath = getAgentsPath();
|
|
142
|
+
const filename = id.endsWith('.md') ? id : `${id}.md`;
|
|
143
|
+
const filePath = path.join(agentsPath, filename);
|
|
144
|
+
// Check if file exists
|
|
145
|
+
try {
|
|
146
|
+
await fs.access(filePath);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return c.json({ success: false, error: 'Agent document not found' }, 404);
|
|
150
|
+
}
|
|
151
|
+
// Delete the file
|
|
152
|
+
await fs.unlink(filePath);
|
|
153
|
+
return c.json({
|
|
154
|
+
success: true,
|
|
155
|
+
message: 'Agent document deleted successfully'
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error('Error deleting agent document:', error);
|
|
160
|
+
return c.json({ success: false, error: 'Failed to delete agent document' }, 500);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
export default app;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|