@lovelybunch/api 1.0.75-alpha.5 → 1.0.75-alpha.6
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/routes/api/v1/ai/route.js +4 -3
- package/dist/routes/api/v1/events/status/route.d.ts +1 -1
- package/dist/routes/api/v1/jobs/[id]/run/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/[id]/runs/[runId]/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/status/route.d.ts +1 -1
- package/dist/routes/api/v1/proposals/[id]/route.d.ts +8 -8
- package/dist/routes/api/v1/skills/[id]/index.d.ts +1 -0
- package/dist/routes/api/v1/skills/[id]/index.js +1 -0
- package/dist/routes/api/v1/skills/[id]/route.d.ts +3 -0
- package/dist/routes/api/v1/skills/[id]/route.js +199 -0
- package/dist/routes/api/v1/skills/index.d.ts +1 -0
- package/dist/routes/api/v1/skills/index.js +1 -0
- package/dist/routes/api/v1/skills/route.d.ts +3 -0
- package/dist/routes/api/v1/skills/route.js +329 -0
- package/dist/server-with-static.js +4 -4
- package/dist/server.js +4 -4
- package/package.json +6 -4
- package/static/assets/{ActivityPage-6xf2Jxp0.js → ActivityPage-QmXUVEPm.js} +1 -1
- package/static/assets/{ApiKeysSettingsPage-DlWMBuQb.js → ApiKeysSettingsPage-qie8F6gb.js} +1 -1
- package/static/assets/{ArchitectureEditPage-C6MWFHCp.js → ArchitectureEditPage-CPQnvHk4.js} +1 -1
- package/static/assets/{ArchitecturePage-CxQtPG4d.js → ArchitecturePage-CJNygJU2.js} +1 -1
- package/static/assets/{AuthSettingsPage-w0blkw8Q.js → AuthSettingsPage-B204F8bT.js} +1 -1
- package/static/assets/{CallbackPage-ByjWTMuG.js → CallbackPage-MGCRI7r_.js} +1 -1
- package/static/assets/CodePage-BxEsUJP-.js +2 -0
- package/static/assets/{CollapsibleSection-B1AU3exJ.js → CollapsibleSection-CtALgJpu.js} +1 -1
- package/static/assets/{DashboardPage-CAToLPqr.js → DashboardPage-DbvVqN24.js} +1 -1
- package/static/assets/{GitPage-DGjEzIUs.js → GitPage-D2bnwXyJ.js} +1 -1
- package/static/assets/{GitSettingsPage-X1GEO1Ti.js → GitSettingsPage-ZDdKMZl1.js} +1 -1
- package/static/assets/{IdentityPage-L0foq6qN.js → IdentityPage-Bu-duoN6.js} +1 -1
- package/static/assets/{ImplementationStepsEditor-Dn88eiVP.js → ImplementationStepsEditor-PDSNPMod.js} +1 -1
- package/static/assets/{IntegrationsSettingsPage-WX1lSaWr.js → IntegrationsSettingsPage-DsM2vBgQ.js} +1 -1
- package/static/assets/{JobDetailPage-CvNs3cEP.js → JobDetailPage-BBCASAAb.js} +1 -1
- package/static/assets/{KnowledgeDetailPage-DXjmZdQl.js → KnowledgeDetailPage-D1EptY9f.js} +1 -1
- package/static/assets/{KnowledgeEditPage-C70yoVFM.js → KnowledgeEditPage-Dd4B0Zol.js} +1 -1
- package/static/assets/{KnowledgePage-EUJ9c9By.js → KnowledgePage-ibFc3y1K.js} +1 -1
- package/static/assets/{LoginPage-Df_q-ACP.js → LoginPage-v8StIMKr.js} +1 -1
- package/static/assets/{McpSettingsPage-4b5M8tpH.js → McpSettingsPage-m5Wzim08.js} +1 -1
- package/static/assets/{NewKnowledgePage-CqKz6_K-.js → NewKnowledgePage-rmXqT_ay.js} +1 -1
- package/static/assets/{NewProposalPage-DR9UZich.js → NewProposalPage-CmMTQLo5.js} +1 -1
- package/static/assets/NewSkillPage-D3Fffhkj.js +1 -0
- package/static/assets/{ProjectEditPage-5YxG7Xxd.js → ProjectEditPage-C37nAWFP.js} +1 -1
- package/static/assets/{ProjectPage-BBhGv2fS.js → ProjectPage--_Q_QLC1.js} +1 -1
- package/static/assets/{PromptsSettingsPage-DLrpZcDA.js → PromptsSettingsPage-CGXj9CAs.js} +1 -1
- package/static/assets/{ProposalDetailPage-C4tagoNE.js → ProposalDetailPage-BUHhxZ3l.js} +1 -1
- package/static/assets/{ProposalEditPage-Bz-oEsLL.js → ProposalEditPage-C0eEdxJc.js} +1 -1
- package/static/assets/{ProposalsPage-BKRjNF4y.js → ProposalsPage-DyQC5FFd.js} +1 -1
- package/static/assets/{ResourcesPage-BZrToY-V.js → ResourcesPage-IrMHiK53.js} +1 -1
- package/static/assets/{RoleEditPage-C2vWadxy.js → RoleEditPage-Bw35Wz-d.js} +1 -1
- package/static/assets/{RolePage-CE9y3rMd.js → RolePage-BOjMgEYI.js} +1 -1
- package/static/assets/{RulesSettingsPage-BidnZaAT.js → RulesSettingsPage-B0eW6OmX.js} +1 -1
- package/static/assets/{SchedulePage-DU7ng6Gq.js → SchedulePage-CrfWjM5k.js} +1 -1
- package/static/assets/SkillDetailPage-CKDNJYXm.js +1 -0
- package/static/assets/SkillEditPage-DnBv-wu9.js +1 -0
- package/static/assets/SkillsPage-C5VD2DNt.js +8 -0
- package/static/assets/SkillsSettingsPage-D3M6mo3a.js +1 -0
- package/static/assets/{SourceInput-CCa7okhU.js → SourceInput-BN8ZVkqs.js} +1 -1
- package/static/assets/{TagInput-Chn207ze.js → TagInput-CICgcKUW.js} +1 -1
- package/static/assets/{TerminalPage-CEYgdKT2.js → TerminalPage-PJ6jkMN5.js} +1 -1
- package/static/assets/TerminalSessionPage-DuJ2n3mT.js +13 -0
- package/static/assets/{UserPreferencesPage-lPgr1ngr.js → UserPreferencesPage-CyNuAJru.js} +1 -1
- package/static/assets/{UserSettingsPage-ctHFqz6e.js → UserSettingsPage-Bq2TlR-8.js} +1 -1
- package/static/assets/{UtilitiesPage-BVxyh0Ce.js → UtilitiesPage-mZb2CtxF.js} +1 -1
- package/static/assets/{alert-D5jzRTa5.js → alert-CrqaDLRU.js} +1 -1
- package/static/assets/{arrow-down-4I_8gyhd.js → arrow-down-CfqDgiIx.js} +1 -1
- package/static/assets/{arrow-left-DZzHrGWA.js → arrow-left-CIkDScAO.js} +1 -1
- package/static/assets/{arrow-up-B4VxSS3_.js → arrow-up-DoOW0Uek.js} +1 -1
- package/static/assets/{badge-DvLOhob-.js → badge-ikmjXCY_.js} +1 -1
- package/static/assets/{browser-modal-DzaD2oDW.js → browser-modal-BJ16icY9.js} +1 -1
- package/static/assets/{calendar-BNe2rz1T.js → calendar-B3EFURS-.js} +1 -1
- package/static/assets/{card-BguljVtN.js → card-C0a11V0T.js} +1 -1
- package/static/assets/{chevron-left-DZQ_tMvU.js → chevron-left-Cbq2vuK_.js} +1 -1
- package/static/assets/{chevrons-up-BCenbxtV.js → chevrons-up-C3zGaueJ.js} +1 -1
- package/static/assets/{circle-alert-CZtpB74t.js → circle-alert-BZyc7kNR.js} +1 -1
- package/static/assets/{circle-check-hWIEYAMH.js → circle-check-CC67C1b-.js} +1 -1
- package/static/assets/{circle-check-big-CTApxALS.js → circle-check-big-tNM4uoO8.js} +1 -1
- package/static/assets/{circle-play-BF3gDlvZ.js → circle-play-DgDKRctX.js} +1 -1
- package/static/assets/{circle-x-BtYTEkcT.js → circle-x-CbIXbCmI.js} +1 -1
- package/static/assets/{clipboard-B8Tnfm3W.js → clipboard-Bhg2iYmV.js} +1 -1
- package/static/assets/{clock-_sj3uVNp.js → clock-DUwjJehj.js} +1 -1
- package/static/assets/{download-CPGv4d5Q.js → download-CAr6POG8.js} +1 -1
- package/static/assets/{droid-BWtMgfPD.js → droid-DqWsM2dp.js} +5 -5
- package/static/assets/{external-link-CtxWkvSs.js → external-link-C552Tasx.js} +1 -1
- package/static/assets/{eye-_nXnan_b.js → eye-F-BxEo2B.js} +1 -1
- package/static/assets/{folder-git-2-C_Zkp5wq.js → folder-git-2-BCO-gmji.js} +1 -1
- package/static/assets/{index-BlLRLvWP.js → index-Cb4mP03_.js} +9 -9
- package/static/assets/{info-fJ-d5-p-.js → info-DZ6rfcGz.js} +1 -1
- package/static/assets/{label-PINvlQb-.js → label-VXwOLYGm.js} +1 -1
- package/static/assets/{markdown-editor-B7Zxgu1u.js → markdown-editor-DKBU3Sgf.js} +1 -1
- package/static/assets/{pause-C9zNWRax.js → pause-CJhh_zgy.js} +1 -1
- package/static/assets/{play-BpXD0Ub0.js → play-DqF_TESp.js} +1 -1
- package/static/assets/{plus-DBJTL6qk.js → plus-B-nP-2Bc.js} +1 -1
- package/static/assets/{radio-group-DBaY5DVP.js → radio-group-CkXoX9re.js} +1 -1
- package/static/assets/{refresh-cw-SQsUc3_C.js → refresh-cw-DNCHo2vd.js} +1 -1
- package/static/assets/{search-CBNlhD-8.js → search-pT3zGN1p.js} +1 -1
- package/static/assets/{switch-C3ys7mIF.js → switch-DKgMJKx9.js} +1 -1
- package/static/assets/{tabs-BpxOu6UL.js → tabs-LRqYZP6q.js} +1 -1
- package/static/assets/{tag-Cu4oj34X.js → tag-CNJNVCjj.js} +1 -1
- package/static/assets/{terminal-preview-B5-BekLC.js → terminal-preview-C_hF2vLs.js} +1 -1
- package/static/assets/{use-terminal-CDMgbskg.js → use-terminal-B3kcgG1Q.js} +1 -1
- package/static/assets/{zap-LrtVPxxV.js → zap-DeMKwLsi.js} +1 -1
- package/static/index.html +1 -1
- package/static/assets/AgentDetailPage-1hbFBTeB.js +0 -1
- package/static/assets/AgentEditPage-qMmg057j.js +0 -1
- package/static/assets/AgentsPage-DyyJrXqo.js +0 -3
- package/static/assets/AgentsSettingsPage-Bf61k6i0.js +0 -6
- package/static/assets/CodePage-aWl0jKwx.js +0 -2
- package/static/assets/NewAgentPage-BqvZZJmC.js +0 -1
- package/static/assets/TerminalSessionPage-C8YA0AmM.js +0 -13
|
@@ -39,7 +39,7 @@ function getGlobalApiKey(provider) {
|
|
|
39
39
|
}
|
|
40
40
|
export async function POST(c) {
|
|
41
41
|
try {
|
|
42
|
-
const { message: userMessage, history, context, contextContent, agentPersona, systemPrompt: systemOverride, attachedContextFiles } = await c.req.json();
|
|
42
|
+
const { message: userMessage, history, context, contextContent, skillPersona, agentPersona, systemPrompt: systemOverride, attachedContextFiles } = await c.req.json();
|
|
43
43
|
if (!userMessage) {
|
|
44
44
|
return c.json({ error: "Message is required" }, 400);
|
|
45
45
|
}
|
|
@@ -55,8 +55,9 @@ export async function POST(c) {
|
|
|
55
55
|
const anthropicClient = createAnthropic({ apiKey });
|
|
56
56
|
const model = anthropicClient('claude-sonnet-4-5-20250929');
|
|
57
57
|
const baseSystem = systemOverride || getSystemPrompt();
|
|
58
|
-
const
|
|
59
|
-
|
|
58
|
+
const persona = skillPersona || agentPersona; // Support both new and legacy field names
|
|
59
|
+
const systemPrompt = persona
|
|
60
|
+
? `${baseSystem}\n\nThe following persona is authoritative and overrides general guidance above. You must strictly follow it.\n\n${persona}`
|
|
60
61
|
: baseSystem;
|
|
61
62
|
// Build context messages from attached files
|
|
62
63
|
const contextMessages = [];
|
|
@@ -7,9 +7,9 @@ import { Context } from "hono";
|
|
|
7
7
|
* Get logging system status and configuration
|
|
8
8
|
*/
|
|
9
9
|
export declare function GET(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
10
|
-
[x: string]: any;
|
|
11
10
|
currentFile: string;
|
|
12
11
|
sizeBytes: number;
|
|
12
|
+
lastSeq: number;
|
|
13
13
|
rotateBytes: number;
|
|
14
14
|
logsDir: string;
|
|
15
15
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
@@ -12,8 +12,8 @@ export declare function POST(c: Context): Promise<(Response & import("hono").Typ
|
|
|
12
12
|
run: {
|
|
13
13
|
id: string;
|
|
14
14
|
jobId: string;
|
|
15
|
-
trigger: import("@lovelybunch/
|
|
16
|
-
status: import("@lovelybunch/
|
|
15
|
+
trigger: import("@lovelybunch/core").ScheduledJobTrigger;
|
|
16
|
+
status: import("@lovelybunch/core").ScheduledJobRunStatus;
|
|
17
17
|
startedAt: string;
|
|
18
18
|
finishedAt?: string;
|
|
19
19
|
outputPath?: string;
|
|
@@ -10,8 +10,8 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
10
10
|
data: {
|
|
11
11
|
id: string;
|
|
12
12
|
jobId: string;
|
|
13
|
-
trigger: import("@lovelybunch/
|
|
14
|
-
status: import("@lovelybunch/
|
|
13
|
+
trigger: import("@lovelybunch/core").ScheduledJobTrigger;
|
|
14
|
+
status: import("@lovelybunch/core").ScheduledJobRunStatus;
|
|
15
15
|
startedAt: string;
|
|
16
16
|
finishedAt?: string;
|
|
17
17
|
outputPath?: string;
|
|
@@ -7,7 +7,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
7
7
|
runningCount: number;
|
|
8
8
|
jobs: {
|
|
9
9
|
id: string;
|
|
10
|
-
status: import("@lovelybunch/
|
|
10
|
+
status: import("@lovelybunch/core").ScheduledJobStatus;
|
|
11
11
|
nextRunAt?: string;
|
|
12
12
|
lastRunAt?: string;
|
|
13
13
|
timerActive: boolean;
|
|
@@ -13,7 +13,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
13
13
|
intent?: string;
|
|
14
14
|
content?: string;
|
|
15
15
|
author: {
|
|
16
|
-
type: import("@lovelybunch/
|
|
16
|
+
type: import("@lovelybunch/core").AuthorType;
|
|
17
17
|
id: string;
|
|
18
18
|
name: string;
|
|
19
19
|
email?: string;
|
|
@@ -48,7 +48,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
48
48
|
version: string;
|
|
49
49
|
name: string;
|
|
50
50
|
description: string;
|
|
51
|
-
type: import("@lovelybunch/
|
|
51
|
+
type: import("@lovelybunch/core").FeatureFlagType;
|
|
52
52
|
defaultValue: any;
|
|
53
53
|
scopes: string[];
|
|
54
54
|
targets: {
|
|
@@ -96,7 +96,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
96
96
|
minimumSampleSize: number;
|
|
97
97
|
testType: "two-tailed" | "one-tailed";
|
|
98
98
|
};
|
|
99
|
-
status: import("@lovelybunch/
|
|
99
|
+
status: import("@lovelybunch/core").ExperimentStatus;
|
|
100
100
|
startedAt?: string;
|
|
101
101
|
endedAt?: string;
|
|
102
102
|
}[];
|
|
@@ -134,7 +134,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
134
134
|
schedule?: string;
|
|
135
135
|
rollbackPlan?: string;
|
|
136
136
|
};
|
|
137
|
-
status: import("@lovelybunch/
|
|
137
|
+
status: import("@lovelybunch/core").CPStatus;
|
|
138
138
|
comments?: {
|
|
139
139
|
id: string;
|
|
140
140
|
author: string;
|
|
@@ -177,7 +177,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
177
177
|
intent?: string;
|
|
178
178
|
content?: string;
|
|
179
179
|
author: {
|
|
180
|
-
type: import("@lovelybunch/
|
|
180
|
+
type: import("@lovelybunch/core").AuthorType;
|
|
181
181
|
id: string;
|
|
182
182
|
name: string;
|
|
183
183
|
email?: string;
|
|
@@ -212,7 +212,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
212
212
|
version: string;
|
|
213
213
|
name: string;
|
|
214
214
|
description: string;
|
|
215
|
-
type: import("@lovelybunch/
|
|
215
|
+
type: import("@lovelybunch/core").FeatureFlagType;
|
|
216
216
|
defaultValue: any;
|
|
217
217
|
scopes: string[];
|
|
218
218
|
targets: {
|
|
@@ -260,7 +260,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
260
260
|
minimumSampleSize: number;
|
|
261
261
|
testType: "two-tailed" | "one-tailed";
|
|
262
262
|
};
|
|
263
|
-
status: import("@lovelybunch/
|
|
263
|
+
status: import("@lovelybunch/core").ExperimentStatus;
|
|
264
264
|
startedAt?: string;
|
|
265
265
|
endedAt?: string;
|
|
266
266
|
}[];
|
|
@@ -298,7 +298,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
298
298
|
schedule?: string;
|
|
299
299
|
rollbackPlan?: string;
|
|
300
300
|
};
|
|
301
|
-
status: import("@lovelybunch/
|
|
301
|
+
status: import("@lovelybunch/core").CPStatus;
|
|
302
302
|
comments?: {
|
|
303
303
|
id: string;
|
|
304
304
|
author: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1,199 @@
|
|
|
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 generateSkillId(name) {
|
|
7
|
+
return name
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
10
|
+
.replace(/\s+/g, '-')
|
|
11
|
+
.replace(/--+/g, '-')
|
|
12
|
+
.replace(/^-|-$/g, '');
|
|
13
|
+
}
|
|
14
|
+
function getSkillsPath() {
|
|
15
|
+
let basePath;
|
|
16
|
+
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
|
17
|
+
basePath = process.env.GAIT_DEV_ROOT;
|
|
18
|
+
}
|
|
19
|
+
else if (process.env.GAIT_DATA_PATH) {
|
|
20
|
+
basePath = path.resolve(process.env.GAIT_DATA_PATH, '.nut');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
basePath = path.resolve(process.cwd(), '.nut');
|
|
24
|
+
}
|
|
25
|
+
return path.join(basePath, 'skills');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* GET /api/v1/skills/:id
|
|
29
|
+
* Load a specific skill document
|
|
30
|
+
*/
|
|
31
|
+
app.get('/', async (c) => {
|
|
32
|
+
try {
|
|
33
|
+
const id = c.req.param('id');
|
|
34
|
+
const skillsPath = getSkillsPath();
|
|
35
|
+
const skillFile = path.join(skillsPath, id, 'SKILL.md');
|
|
36
|
+
const fileContent = await fs.readFile(skillFile, 'utf-8');
|
|
37
|
+
const { data, content } = matter(fileContent);
|
|
38
|
+
const nestedMeta = typeof data.metadata === 'object' ? data.metadata : undefined;
|
|
39
|
+
const document = {
|
|
40
|
+
id,
|
|
41
|
+
name: data.name || id,
|
|
42
|
+
description: data.description || '',
|
|
43
|
+
license: data.license,
|
|
44
|
+
compatibility: data.compatibility,
|
|
45
|
+
allowedTools: data['allowed-tools'] || data.allowedTools,
|
|
46
|
+
metadata: {
|
|
47
|
+
name: data.name || id,
|
|
48
|
+
description: data.description || '',
|
|
49
|
+
license: data.license,
|
|
50
|
+
compatibility: data.compatibility,
|
|
51
|
+
allowedTools: data['allowed-tools'] || data.allowedTools,
|
|
52
|
+
...(nestedMeta || {}),
|
|
53
|
+
metadata: nestedMeta,
|
|
54
|
+
},
|
|
55
|
+
content,
|
|
56
|
+
};
|
|
57
|
+
return c.json({
|
|
58
|
+
success: true,
|
|
59
|
+
document
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error.code === 'ENOENT') {
|
|
64
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
65
|
+
}
|
|
66
|
+
console.error('Error loading skill document:', error);
|
|
67
|
+
return c.json({ success: false, error: 'Failed to load skill document' }, 500);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* PUT /api/v1/skills/:id
|
|
72
|
+
* Update a specific skill document
|
|
73
|
+
*/
|
|
74
|
+
app.put('/', async (c) => {
|
|
75
|
+
try {
|
|
76
|
+
const id = c.req.param('id');
|
|
77
|
+
const body = await c.req.json();
|
|
78
|
+
const skillsPath = getSkillsPath();
|
|
79
|
+
const skillDir = path.join(skillsPath, id);
|
|
80
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
81
|
+
// Check if skill exists
|
|
82
|
+
try {
|
|
83
|
+
await fs.access(skillFile);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
87
|
+
}
|
|
88
|
+
// Read current content
|
|
89
|
+
const currentContent = await fs.readFile(skillFile, 'utf-8');
|
|
90
|
+
const { data: currentData, content: currentMarkdown } = matter(currentContent);
|
|
91
|
+
// Merge updates
|
|
92
|
+
const updatedContent = body.content !== undefined ? body.content : currentMarkdown;
|
|
93
|
+
const updatedDescription = body.description !== undefined ? body.description : (currentData.description || '');
|
|
94
|
+
const updatedLicense = body.license !== undefined ? body.license : currentData.license;
|
|
95
|
+
const updatedCompatibility = body.compatibility !== undefined ? body.compatibility : currentData.compatibility;
|
|
96
|
+
const updatedAllowedTools = body.allowedTools !== undefined ? body.allowedTools : (currentData['allowed-tools'] || currentData.allowedTools);
|
|
97
|
+
// Merge metadata
|
|
98
|
+
const currentMeta = typeof currentData.metadata === 'object' && currentData.metadata !== null ? currentData.metadata : {};
|
|
99
|
+
const updatedMeta = body.metadata
|
|
100
|
+
? { ...currentMeta, ...body.metadata }
|
|
101
|
+
: currentMeta;
|
|
102
|
+
// Handle name change (directory rename)
|
|
103
|
+
let newId = id;
|
|
104
|
+
let newDir = skillDir;
|
|
105
|
+
if (body.name && body.name !== currentData.name) {
|
|
106
|
+
newId = generateSkillId(body.name);
|
|
107
|
+
newDir = path.join(skillsPath, newId);
|
|
108
|
+
if (newId !== id) {
|
|
109
|
+
try {
|
|
110
|
+
await fs.access(path.join(newDir, 'SKILL.md'));
|
|
111
|
+
return c.json({ success: false, error: 'A skill with this name already exists' }, 409);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Doesn't exist, proceed with rename
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Build updated frontmatter
|
|
119
|
+
const frontmatter = {
|
|
120
|
+
name: newId,
|
|
121
|
+
description: updatedDescription,
|
|
122
|
+
};
|
|
123
|
+
if (updatedLicense)
|
|
124
|
+
frontmatter.license = updatedLicense;
|
|
125
|
+
if (updatedCompatibility)
|
|
126
|
+
frontmatter.compatibility = updatedCompatibility;
|
|
127
|
+
if (updatedAllowedTools)
|
|
128
|
+
frontmatter['allowed-tools'] = updatedAllowedTools;
|
|
129
|
+
// Clean metadata
|
|
130
|
+
const cleanMeta = {};
|
|
131
|
+
for (const [key, value] of Object.entries(updatedMeta)) {
|
|
132
|
+
if (value !== undefined && value !== null) {
|
|
133
|
+
cleanMeta[key] = value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (Object.keys(cleanMeta).length > 0) {
|
|
137
|
+
frontmatter.metadata = cleanMeta;
|
|
138
|
+
}
|
|
139
|
+
const fileContent = matter.stringify(updatedContent, frontmatter);
|
|
140
|
+
if (newId !== id) {
|
|
141
|
+
// Create new directory and write file
|
|
142
|
+
await fs.mkdir(newDir, { recursive: true });
|
|
143
|
+
await fs.writeFile(path.join(newDir, 'SKILL.md'), fileContent, 'utf-8');
|
|
144
|
+
// Remove old directory
|
|
145
|
+
await fs.rm(skillDir, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
await fs.writeFile(skillFile, fileContent, 'utf-8');
|
|
149
|
+
}
|
|
150
|
+
return c.json({
|
|
151
|
+
success: true,
|
|
152
|
+
document: {
|
|
153
|
+
id: newId,
|
|
154
|
+
name: newId,
|
|
155
|
+
description: updatedDescription,
|
|
156
|
+
metadata: {
|
|
157
|
+
name: newId,
|
|
158
|
+
description: updatedDescription,
|
|
159
|
+
...frontmatter,
|
|
160
|
+
...(typeof cleanMeta === 'object' ? cleanMeta : {}),
|
|
161
|
+
},
|
|
162
|
+
content: updatedContent
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error('Error updating skill document:', error);
|
|
168
|
+
return c.json({ success: false, error: 'Failed to update skill document' }, 500);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
* DELETE /api/v1/skills/:id
|
|
173
|
+
* Delete a specific skill document (removes entire skill directory)
|
|
174
|
+
*/
|
|
175
|
+
app.delete('/', async (c) => {
|
|
176
|
+
try {
|
|
177
|
+
const id = c.req.param('id');
|
|
178
|
+
const skillsPath = getSkillsPath();
|
|
179
|
+
const skillDir = path.join(skillsPath, id);
|
|
180
|
+
// Check if skill exists
|
|
181
|
+
try {
|
|
182
|
+
await fs.access(path.join(skillDir, 'SKILL.md'));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return c.json({ success: false, error: 'Skill document not found' }, 404);
|
|
186
|
+
}
|
|
187
|
+
// Remove entire skill directory
|
|
188
|
+
await fs.rm(skillDir, { recursive: true, force: true });
|
|
189
|
+
return c.json({
|
|
190
|
+
success: true,
|
|
191
|
+
message: 'Skill document deleted successfully'
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
console.error('Error deleting skill document:', error);
|
|
196
|
+
return c.json({ success: false, error: 'Failed to delete skill document' }, 500);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
export default app;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './route.js';
|