@lovelybunch/api 1.0.76-alpha.9 → 1.0.76
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/git.d.ts +3 -0
- package/dist/lib/git.js +35 -0
- package/dist/routes/api/v1/ai/route.js +214 -152
- package/dist/routes/api/v1/config/route.js +13 -9
- package/dist/routes/api/v1/context/agents/route.d.ts +3 -0
- package/dist/routes/api/v1/context/agents/route.js +159 -0
- package/dist/routes/api/v1/context/index.js +6 -4
- package/dist/routes/api/v1/context/memory/route.d.ts +3 -0
- package/dist/routes/api/v1/context/memory/route.js +163 -0
- package/dist/routes/api/v1/context/team/route.d.ts +3 -0
- package/dist/routes/api/v1/context/team/route.js +159 -0
- package/dist/routes/api/v1/git/index.js +27 -1
- package/dist/routes/api/v1/jobs/[id]/route.d.ts +26 -32
- package/dist/routes/api/v1/jobs/[id]/route.js +3 -3
- package/dist/routes/api/v1/jobs/route.d.ts +33 -33
- package/dist/routes/api/v1/jobs/route.js +17 -2
- package/dist/routes/api/v1/mcp/index.js +194 -21
- package/dist/routes/api/v1/resources/generate/route.js +10 -3
- package/package.json +4 -4
- package/static/assets/ActivityPage-sJEQn6DK.js +1 -0
- package/static/assets/AgentsContextEditPage-DU3qIXk9.js +9 -0
- package/static/assets/AgentsContextPage-tJ-LhFYb.js +1 -0
- package/static/assets/{ApiKeysSettingsPage-CjrCuHHE.js → ApiKeysSettingsPage-Bg84BQHV.js} +2 -2
- package/static/assets/{AuthSettingsPage-elJX4TCV.js → AuthSettingsPage-Bwr7uP3z.js} +1 -1
- package/static/assets/{CallbackPage-CUuZYgBL.js → CallbackPage-BFn0Np2S.js} +1 -1
- package/static/assets/CodePage-kp4s3wCJ.js +2 -0
- package/static/assets/{CollapsibleSection-DfTxWX0X.js → CollapsibleSection-CNs1mvsZ.js} +1 -1
- package/static/assets/{DashboardPage-CmS8UPSm.js → DashboardPage-DMJSzzgD.js} +9 -19
- package/static/assets/{GitPage-DSfn76oO.js → GitPage-uqene8zj.js} +3 -3
- package/static/assets/{GitSettingsPage-Bu8h7hcr.js → GitSettingsPage-CLswbZsT.js} +2 -2
- package/static/assets/{IdentityPage-NFKq2FHi.js → IdentityPage-BDTPXEo7.js} +2 -2
- package/static/assets/{ImplementationStepsEditor-Cn-MshnR.js → ImplementationStepsEditor-D4cvhPhz.js} +2 -2
- package/static/assets/IntegrationsSettingsPage-o7NXZGt9.js +1 -0
- package/static/assets/JobDetailPage-DuEiPz6X.js +1 -0
- package/static/assets/KnowledgeDetailPage-DFVud_VC.js +1 -0
- package/static/assets/{KnowledgeEditPage-B28N-7vM.js → KnowledgeEditPage-XG6HKK7E.js} +1 -1
- package/static/assets/{KnowledgePage-C3zoPEcH.js → KnowledgePage-B2zI3xwW.js} +2 -2
- package/static/assets/{LoginPage-BYNLGEnz.js → LoginPage-CUJRxwXy.js} +1 -1
- package/static/assets/MailInboxPage-BlCG-tba.js +1 -0
- package/static/assets/MailProcessingModal-BJIdHOqK.js +1 -0
- package/static/assets/MailReadPage-MoNo_gmW.js +1 -0
- package/static/assets/{MailSentPage-ClaVWZCR.js → MailSentPage-QzpuIJmT.js} +1 -1
- package/static/assets/{McpSettingsPage-CfhBioEH.js → McpSettingsPage-BZcCGkGM.js} +1 -1
- package/static/assets/MemoryEditPage-DXSQoCT4.js +13 -0
- package/static/assets/MemoryPage-oBnyuvSf.js +1 -0
- package/static/assets/{NewKnowledgePage-BUwh_DFd.js → NewKnowledgePage-deMsezK8.js} +1 -1
- package/static/assets/{NewSkillPage-B2rztwzD.js → NewSkillPage-DRYWdrlV.js} +1 -1
- package/static/assets/{NewTaskPage-Cvw20nug.js → NewTaskPage-B6xdic5_.js} +2 -2
- package/static/assets/{NotFoundPage-CXvLVHsT.js → NotFoundPage-Bxu9uKFO.js} +1 -1
- package/static/assets/{NotificationsSettingsPage-Df_GZ7_p.js → NotificationsSettingsPage-CLgtsCVM.js} +1 -1
- package/static/assets/{PromptsSettingsPage-QTxJgO5-.js → PromptsSettingsPage-BWaELCjG.js} +1 -1
- package/static/assets/{ResourceDetailPage-C9RHHVKu.js → ResourceDetailPage-CMPDRdVM.js} +1 -1
- package/static/assets/ResourcesPage-DspYILfG.js +41 -0
- package/static/assets/{RoleEditPage-N2-v2MXN.js → RoleEditPage-DXtzicVZ.js} +1 -1
- package/static/assets/{RolePage-Da0kZMUH.js → RolePage-DafGURGp.js} +1 -1
- package/static/assets/{RulesSettingsPage-CSd5iz22.js → RulesSettingsPage-E8V9cexV.js} +1 -1
- package/static/assets/RunDetailPage-DsxkqFst.js +1 -0
- package/static/assets/SchedulePage-B2YvNDHr.js +4 -0
- package/static/assets/{SkillDetailPage-QjqBAuFU.js → SkillDetailPage-CWkqSfuT.js} +1 -1
- package/static/assets/{SkillEditPage-BB0x4VVH.js → SkillEditPage-DwyebzFV.js} +1 -1
- package/static/assets/{SkillsPage-BMDNxMmZ.js → SkillsPage-CauK65X_.js} +2 -2
- package/static/assets/{SkillsSettingsPage-DcdeOlAl.js → SkillsSettingsPage-DXMRv3jR.js} +1 -1
- package/static/assets/{SourceInput-rc4KSqcv.js → SourceInput-C0iKqbQ1.js} +1 -1
- package/static/assets/{TagInput-bxFcAknC.js → TagInput-Ct-WRvTs.js} +1 -1
- package/static/assets/{TaskDetailPage-CAmREdfh.js → TaskDetailPage-CApk2iBh.js} +1 -1
- package/static/assets/{TaskEditPage-BDgZtG36.js → TaskEditPage-NgOVShfK.js} +1 -1
- package/static/assets/{TasksPage-BQ6eLw0T.js → TasksPage-BoPrP_Rl.js} +3 -3
- package/static/assets/TeamEditPage-ChY6mYm8.js +9 -0
- package/static/assets/TeamPage-DH-dJhFG.js +1 -0
- package/static/assets/{TerminalPage-BhWGRGf1.js → TerminalPage-CRhcscF2.js} +1 -1
- package/static/assets/{TerminalSessionPage-Bu-WiE0d.js → TerminalSessionPage-CSCQg2sn.js} +2 -2
- package/static/assets/{UserPreferencesPage-B_Tu1a8h.js → UserPreferencesPage-DxCSWJnS.js} +1 -1
- package/static/assets/{UserSettingsPage-BnEGtrGo.js → UserSettingsPage-DKkOLNPV.js} +1 -1
- package/static/assets/UtilitiesPage-CBNSvixW.js +1 -0
- package/static/assets/{alert-C42EBWiI.js → alert-Dw_RSroN.js} +1 -1
- package/static/assets/{arrow-down-CuFFg288.js → arrow-down-UClxXzT-.js} +1 -1
- package/static/assets/{arrow-left-C8VbyW3d.js → arrow-left-DWmf9YJp.js} +1 -1
- package/static/assets/{arrow-up-down-GN3qK2mU.js → arrow-up-down-Btc3okb3.js} +1 -1
- package/static/assets/{arrow-up-vC1c-5gW.js → arrow-up-fLCh7Hvh.js} +1 -1
- package/static/assets/{badge-CKwUSKzT.js → badge-vIqE5SOP.js} +1 -1
- package/static/assets/{browser-modal-C9VBJ_El.js → browser-modal-DgMJTsMd.js} +2 -2
- package/static/assets/{card-DRBgMGuU.js → card-DPLdBoa5.js} +1 -1
- package/static/assets/{chevron-left-2sP4ienq.js → chevron-left-CiNaLX-v.js} +1 -1
- package/static/assets/{chevron-up-DJfyvHso.js → chevron-up-DFd-7wxW.js} +1 -1
- package/static/assets/{chevrons-up-DfFpzHXf.js → chevrons-up-BfU70OcQ.js} +1 -1
- package/static/assets/{circle-alert-DP4rtmEK.js → circle-alert-Mv00T-P2.js} +1 -1
- package/static/assets/{circle-check-big-3mrGMFVn.js → circle-check-big-BEY1IoIP.js} +1 -1
- package/static/assets/{circle-check-Cnp-EoKX.js → circle-check-xMiP6SLO.js} +1 -1
- package/static/assets/{circle-play-7F5AVehH.js → circle-play-iZZwaGbV.js} +1 -1
- package/static/assets/{circle-x-DxbiyJ6w.js → circle-x-z3iynaE7.js} +1 -1
- package/static/assets/{clipboard-CQNR4_yT.js → clipboard-C8wZRPDH.js} +1 -1
- package/static/assets/{clock-DGw3R_UL.js → clock-C_9shc08.js} +1 -1
- package/static/assets/{code-DSNMK8tD.js → code-DH-sRhus.js} +1 -1
- package/static/assets/{download-BWL6PFiw.js → download-CE8b59ER.js} +1 -1
- package/static/assets/{external-link-BqUE-DMN.js → external-link-DPyKt8NE.js} +1 -1
- package/static/assets/{eye-BD57N1qQ.js → eye-BpGD-yoS.js} +1 -1
- package/static/assets/{folder-git-2-CW5Zi8Bm.js → folder-git-2-BIw4zbmy.js} +1 -1
- package/static/assets/globe-CUo7eHKN.js +6 -0
- package/static/assets/{index-CheR43vH.js → index-B07hel4U.js} +1 -1
- package/static/assets/{index-B0fLM-4F.js → index-BCwmQxLC.js} +1 -1
- package/static/assets/{index-DO47L-WG.js → index-BOKaM9K-.js} +1 -1
- package/static/assets/{index-EpelXypg.js → index-BaR4iUzg.js} +1 -1
- package/static/assets/index-BcCuKdbf.css +1 -0
- package/static/assets/{index-BG5vEV31.js → index-Bfb3OTwj.js} +1 -1
- package/static/assets/{index-CMQcknsg.js → index-Bkt1rQVV.js} +1 -1
- package/static/assets/{index-BmTTXfmk.js → index-C65b3D5_.js} +1 -1
- package/static/assets/{index-CXWGFCS-.js → index-CGbmjmEy.js} +1 -1
- package/static/assets/{index-BArpuuuE.js → index-CTouvf2d.js} +1 -1
- package/static/assets/{index-D4awulBm.js → index-Cdwx6Zps.js} +1 -1
- package/static/assets/{index-CMt1ExW-.js → index-ClO9-JVh.js} +1 -1
- package/static/assets/{index-CVVL2h9f.js → index-CpJ0uBf3.js} +1 -1
- package/static/assets/{index-B9OOTqx4.js → index-CsBxEWw5.js} +1 -1
- package/static/assets/{index-stPObw-o.js → index-DZAYfTI2.js} +1 -1
- package/static/assets/{index-X4fPPLHI.js → index-Dkr9CBL7.js} +1 -1
- package/static/assets/{index-Bedu89qc.js → index-DnZKG-_7.js} +1 -1
- package/static/assets/index-UXL5-kaP.js +497 -0
- package/static/assets/{index-uxv5vQZF.js → index-iB8oed57.js} +1 -1
- package/static/assets/{index-BWktaW8U.js → index-jaRIZ6SY.js} +1 -1
- package/static/assets/{info-DMJxIp7i.js → info-D-UNBNx2.js} +1 -1
- package/static/assets/{label-DxDedS8x.js → label-8VKluf9w.js} +1 -1
- package/static/assets/{markdown-editor-DJ2CscSp.js → markdown-editor-DBdRsbP2.js} +3 -3
- package/static/assets/{message-square-DF58cqKJ.js → message-square-CO8kDUed.js} +1 -1
- package/static/assets/{paperclip-CHyfSVll.js → paperclip-DlLXZbru.js} +1 -1
- package/static/assets/{pause-B-ouFhaQ.js → pause-zSiaxJBu.js} +1 -1
- package/static/assets/{play-B0y1weCV.js → play-DVBhRokt.js} +1 -1
- package/static/assets/{radio-group-DFNQiPDU.js → radio-group-CThYUcA4.js} +1 -1
- package/static/assets/{refresh-cw-5y5jTc6x.js → refresh-cw-tXYl1ePu.js} +1 -1
- package/static/assets/{search-B5deRThk.js → search-BxF7Wwex.js} +1 -1
- package/static/assets/{select-BzOa_wZx.js → select-CyHFRA1Y.js} +1 -1
- package/static/assets/server-lRxThHjr.js +6 -0
- package/static/assets/{switch-Bf2z8aaj.js → switch-BUpDbrux.js} +1 -1
- package/static/assets/{tabs-DkdBSep3.js → tabs-DkvCmQEX.js} +1 -1
- package/static/assets/{tag-gRsTk0jY.js → tag-CkcZNLnh.js} +1 -1
- package/static/assets/{terminal-preview-BfrUN2ok.js → terminal-preview-CLWDhoOZ.js} +1 -1
- package/static/assets/triangle-alert-CmjG_mbF.js +6 -0
- package/static/assets/{use-terminal-D6Qe1nwM.js → use-terminal-D3iV7-iC.js} +1 -1
- package/static/assets/{video-DXo9sCfT.js → video-CY_dOujm.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/ActivityPage-BaSoKgwZ.js +0 -1
- package/static/assets/ArchitectureEditPage-MYU7btLs.js +0 -21
- package/static/assets/ArchitecturePage-CGqWy8b1.js +0 -1
- package/static/assets/CodePage-C_bzfOnI.js +0 -2
- package/static/assets/IntegrationsSettingsPage-Cw6ItrNf.js +0 -1
- package/static/assets/JobDetailPage-DLSD4HiU.js +0 -1
- package/static/assets/KnowledgeDetailPage-DY8PpD9X.js +0 -1
- package/static/assets/MailInboxPage-DDYg0W70.js +0 -1
- package/static/assets/MailProcessingModal-CXIrtSz0.js +0 -6
- package/static/assets/MailReadPage-CVz6oD-y.js +0 -1
- package/static/assets/ProjectEditPage-DKf6ZoiG.js +0 -11
- package/static/assets/ProjectPage-CHhx9s1k.js +0 -1
- package/static/assets/ResourcesPage-BI8tfYZ2.js +0 -41
- package/static/assets/SchedulePage-CS8g2Db-.js +0 -4
- package/static/assets/UtilitiesPage-k7ABCAig.js +0 -1
- package/static/assets/index-Cht-fo9a.css +0 -1
- package/static/assets/index-DB2Tq9wz.js +0 -487
package/dist/lib/git.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InstructionFileKind, InstructionFiles } from '@lovelybunch/types';
|
|
1
2
|
export declare function getRepoRoot(): Promise<string>;
|
|
2
3
|
export declare function getWorktreesBase(): Promise<string>;
|
|
3
4
|
export declare function sanitizeBranchName(name: string): string;
|
|
@@ -9,6 +10,8 @@ export declare function runGit(args: string[], opts?: {
|
|
|
9
10
|
stdout: string;
|
|
10
11
|
stderr: string;
|
|
11
12
|
}>;
|
|
13
|
+
export declare function lsTree(ref?: string): Promise<string[]>;
|
|
14
|
+
export declare function getInstructionFiles(filter?: InstructionFileKind | 'all'): Promise<InstructionFiles>;
|
|
12
15
|
export declare function getRepoStatus(): Promise<{
|
|
13
16
|
branch: string;
|
|
14
17
|
ahead: number;
|
package/dist/lib/git.js
CHANGED
|
@@ -5,6 +5,7 @@ import { promises as fs } from 'fs';
|
|
|
5
5
|
import { readGithubToken, isGithubTokenValid } from './github-token.js';
|
|
6
6
|
import { findGaitDirectory } from './gait-path.js';
|
|
7
7
|
import { loadGitSettings } from './git-settings.js';
|
|
8
|
+
import { INSTRUCTION_FILE_KINDS } from '@lovelybunch/types';
|
|
8
9
|
const execFile = promisify(_execFile);
|
|
9
10
|
// Base directory for worktrees under the repository root
|
|
10
11
|
export async function getRepoRoot() {
|
|
@@ -52,6 +53,40 @@ export async function runGit(args, opts) {
|
|
|
52
53
|
};
|
|
53
54
|
return execFile('git', args, { cwd, maxBuffer: 10 * 1024 * 1024, timeout, env });
|
|
54
55
|
}
|
|
56
|
+
// --- ls-tree ---
|
|
57
|
+
export async function lsTree(ref = 'HEAD') {
|
|
58
|
+
const { stdout } = await runGit(['ls-tree', '-r', '--name-only', ref]);
|
|
59
|
+
return stdout.trim().split('\n').filter(l => l && !l.startsWith('.nut/'));
|
|
60
|
+
}
|
|
61
|
+
// --- Instruction files ---
|
|
62
|
+
const FILENAME_TO_KIND = new Map(INSTRUCTION_FILE_KINDS.map(k => [`${k}.md`, k]));
|
|
63
|
+
const KIND_TO_FILENAME = new Map(INSTRUCTION_FILE_KINDS.map(k => [k, `${k}.md`]));
|
|
64
|
+
export async function getInstructionFiles(filter) {
|
|
65
|
+
const filterFilename = filter && filter !== 'all' ? KIND_TO_FILENAME.get(filter) : undefined;
|
|
66
|
+
const allPaths = await lsTree();
|
|
67
|
+
const wanted = allPaths.filter(p => {
|
|
68
|
+
const name = path.basename(p);
|
|
69
|
+
if (!FILENAME_TO_KIND.has(name))
|
|
70
|
+
return false;
|
|
71
|
+
if (filterFilename)
|
|
72
|
+
return name === filterFilename;
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
const entries = await Promise.all(wanted.map(async (filePath) => {
|
|
76
|
+
const { stdout } = await runGit(['show', `HEAD:${filePath}`]);
|
|
77
|
+
return { filePath, content: stdout };
|
|
78
|
+
}));
|
|
79
|
+
const result = {};
|
|
80
|
+
for (const { filePath, content } of entries) {
|
|
81
|
+
const dir = path.dirname(filePath);
|
|
82
|
+
const key = dir === '.' ? '.' : dir;
|
|
83
|
+
const kind = FILENAME_TO_KIND.get(path.basename(filePath));
|
|
84
|
+
if (!result[key])
|
|
85
|
+
result[key] = {};
|
|
86
|
+
result[key][kind] = content;
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
55
90
|
// --- Status ---
|
|
56
91
|
export async function getRepoStatus() {
|
|
57
92
|
const { stdout } = await runGit(['status', '--porcelain=v1', '-b']);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { homedir } from 'os';
|
|
2
3
|
import { join, resolve as pathResolve, basename } from 'path';
|
|
3
4
|
import { existsSync, readFileSync, promises as fs, createReadStream } from 'fs';
|
|
@@ -7,7 +8,7 @@ import { ZodError } from 'zod';
|
|
|
7
8
|
import { streamText, tool, jsonSchema, stepCountIs } from 'ai';
|
|
8
9
|
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
9
10
|
import { getLogsDir, listTasks, getTask, createTask, updateTask, deleteTask, } from '@lovelybunch/core';
|
|
10
|
-
import { tasksFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool,
|
|
11
|
+
import { tasksFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, roleContextTool, agentsContextTool, teamContextTool, memoryContextTool, resourcesTool, listConnectorsTool, connectorRequestTool, resolveConnectorUrl } from '@lovelybunch/mcp';
|
|
11
12
|
import matter from 'gray-matter';
|
|
12
13
|
import Fuse from 'fuse.js';
|
|
13
14
|
import { FileStorageAdapter } from '../../../../lib/storage/file-storage.js';
|
|
@@ -59,6 +60,10 @@ export async function POST(c) {
|
|
|
59
60
|
const systemPrompt = persona
|
|
60
61
|
? `${baseSystem}\n\nThe following persona is authoritative and overrides general guidance above. You must strictly follow it.\n\n${persona}`
|
|
61
62
|
: baseSystem;
|
|
63
|
+
if (process.env.NODE_ENV === 'development') {
|
|
64
|
+
const sha256Prefix = createHash('sha256').update(systemPrompt).digest('hex').slice(0, 16);
|
|
65
|
+
console.log('AI system prompt debug:', { length: systemPrompt.length, sha256Prefix });
|
|
66
|
+
}
|
|
62
67
|
// Build context messages from attached files
|
|
63
68
|
const contextMessages = [];
|
|
64
69
|
if (Array.isArray(attachedContextFiles)) {
|
|
@@ -120,27 +125,35 @@ export async function POST(c) {
|
|
|
120
125
|
return JSON.stringify(result);
|
|
121
126
|
},
|
|
122
127
|
}),
|
|
123
|
-
|
|
124
|
-
description:
|
|
125
|
-
inputSchema: jsonSchema(
|
|
128
|
+
role_context: tool({
|
|
129
|
+
description: roleContextTool.description,
|
|
130
|
+
inputSchema: jsonSchema(roleContextTool.parameters),
|
|
126
131
|
execute: async (args) => {
|
|
127
|
-
const result = await
|
|
132
|
+
const result = await executeRoleContextToolDirect(args);
|
|
128
133
|
return JSON.stringify(result);
|
|
129
134
|
},
|
|
130
135
|
}),
|
|
131
|
-
|
|
132
|
-
description:
|
|
133
|
-
inputSchema: jsonSchema(
|
|
136
|
+
agents_context: tool({
|
|
137
|
+
description: agentsContextTool.description,
|
|
138
|
+
inputSchema: jsonSchema(agentsContextTool.parameters),
|
|
134
139
|
execute: async (args) => {
|
|
135
|
-
const result = await
|
|
140
|
+
const result = await executeAgentsContextToolDirect(args);
|
|
136
141
|
return JSON.stringify(result);
|
|
137
142
|
},
|
|
138
143
|
}),
|
|
139
|
-
|
|
140
|
-
description:
|
|
141
|
-
inputSchema: jsonSchema(
|
|
144
|
+
team_context: tool({
|
|
145
|
+
description: teamContextTool.description,
|
|
146
|
+
inputSchema: jsonSchema(teamContextTool.parameters),
|
|
142
147
|
execute: async (args) => {
|
|
143
|
-
const result = await
|
|
148
|
+
const result = await executeTeamContextToolDirect(args);
|
|
149
|
+
return JSON.stringify(result);
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
memory_context: tool({
|
|
153
|
+
description: memoryContextTool.description,
|
|
154
|
+
inputSchema: jsonSchema(memoryContextTool.parameters),
|
|
155
|
+
execute: async (args) => {
|
|
156
|
+
const result = await executeMemoryContextToolDirect(args);
|
|
144
157
|
return JSON.stringify(result);
|
|
145
158
|
},
|
|
146
159
|
}),
|
|
@@ -152,6 +165,22 @@ export async function POST(c) {
|
|
|
152
165
|
return JSON.stringify(result);
|
|
153
166
|
},
|
|
154
167
|
}),
|
|
168
|
+
list_connectors: tool({
|
|
169
|
+
description: listConnectorsTool.description,
|
|
170
|
+
inputSchema: jsonSchema(listConnectorsTool.parameters),
|
|
171
|
+
execute: async () => {
|
|
172
|
+
const result = await executeListConnectorsToolDirect();
|
|
173
|
+
return JSON.stringify(result);
|
|
174
|
+
},
|
|
175
|
+
}),
|
|
176
|
+
connector_request: tool({
|
|
177
|
+
description: connectorRequestTool.description,
|
|
178
|
+
inputSchema: jsonSchema(connectorRequestTool.parameters),
|
|
179
|
+
execute: async (args) => {
|
|
180
|
+
const result = await executeConnectorRequestToolDirect(args);
|
|
181
|
+
return JSON.stringify(result);
|
|
182
|
+
},
|
|
183
|
+
}),
|
|
155
184
|
};
|
|
156
185
|
// Debug logging
|
|
157
186
|
console.log('AI Request Debug:', {
|
|
@@ -521,12 +550,12 @@ async function executeEventsToolDirect(args) {
|
|
|
521
550
|
return { success: false, error: error.message || 'Events tool execution failed' };
|
|
522
551
|
}
|
|
523
552
|
}
|
|
524
|
-
//
|
|
525
|
-
async function
|
|
553
|
+
// Role context tool - read/write the role definition document
|
|
554
|
+
async function executeRoleContextToolDirect(args) {
|
|
526
555
|
const { operation, content, old_text, new_text } = args;
|
|
527
556
|
try {
|
|
528
557
|
const contextPath = getContextBasePath();
|
|
529
|
-
const filePath = join(contextPath, '
|
|
558
|
+
const filePath = join(contextPath, 'role.md');
|
|
530
559
|
switch (operation) {
|
|
531
560
|
case 'get': {
|
|
532
561
|
try {
|
|
@@ -539,7 +568,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
539
568
|
frontmatter: parsed.data,
|
|
540
569
|
raw: fileContent
|
|
541
570
|
},
|
|
542
|
-
message: 'Retrieved
|
|
571
|
+
message: 'Retrieved role context'
|
|
543
572
|
};
|
|
544
573
|
}
|
|
545
574
|
catch (err) {
|
|
@@ -547,7 +576,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
547
576
|
return {
|
|
548
577
|
success: true,
|
|
549
578
|
data: { content: '', frontmatter: {}, raw: '' },
|
|
550
|
-
message: '
|
|
579
|
+
message: 'Role context document does not exist yet. You can create it with an update operation.'
|
|
551
580
|
};
|
|
552
581
|
}
|
|
553
582
|
throw err;
|
|
@@ -574,7 +603,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
574
603
|
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
575
604
|
return {
|
|
576
605
|
success: true,
|
|
577
|
-
message: 'Appended content to
|
|
606
|
+
message: 'Appended content to role context document'
|
|
578
607
|
};
|
|
579
608
|
}
|
|
580
609
|
case 'replace_section': {
|
|
@@ -588,7 +617,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
588
617
|
}
|
|
589
618
|
catch (err) {
|
|
590
619
|
if (err.code === 'ENOENT') {
|
|
591
|
-
return { success: false, error: '
|
|
620
|
+
return { success: false, error: 'Role context document does not exist. Use append or update to create it first.' };
|
|
592
621
|
}
|
|
593
622
|
throw err;
|
|
594
623
|
}
|
|
@@ -598,7 +627,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
598
627
|
success: false,
|
|
599
628
|
error: 'Could not find the specified text in the document. The text may have been paraphrased or changed.',
|
|
600
629
|
fallback_markdown: new_text,
|
|
601
|
-
suggestion: 'Here is the replacement text. You can copy it and manually edit the document at /context/
|
|
630
|
+
suggestion: 'Here is the replacement text. You can copy it and manually edit the document at /context/role'
|
|
602
631
|
};
|
|
603
632
|
}
|
|
604
633
|
// Replace the text
|
|
@@ -606,7 +635,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
606
635
|
await fs.writeFile(filePath, updatedContent, 'utf-8');
|
|
607
636
|
return {
|
|
608
637
|
success: true,
|
|
609
|
-
message: 'Replaced section in
|
|
638
|
+
message: 'Replaced section in role context document'
|
|
610
639
|
};
|
|
611
640
|
}
|
|
612
641
|
case 'update': {
|
|
@@ -617,7 +646,7 @@ async function executeProjectContextToolDirect(args) {
|
|
|
617
646
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
618
647
|
return {
|
|
619
648
|
success: true,
|
|
620
|
-
message: 'Updated
|
|
649
|
+
message: 'Updated role context document'
|
|
621
650
|
};
|
|
622
651
|
}
|
|
623
652
|
default:
|
|
@@ -625,124 +654,28 @@ async function executeProjectContextToolDirect(args) {
|
|
|
625
654
|
}
|
|
626
655
|
}
|
|
627
656
|
catch (error) {
|
|
628
|
-
console.error('Error executing
|
|
629
|
-
return { success: false, error: error.message || '
|
|
657
|
+
console.error('Error executing role context tool:', error);
|
|
658
|
+
return { success: false, error: error.message || 'Role context tool execution failed' };
|
|
630
659
|
}
|
|
631
660
|
}
|
|
632
|
-
//
|
|
633
|
-
async function
|
|
634
|
-
|
|
635
|
-
try {
|
|
636
|
-
const contextPath = getContextBasePath();
|
|
637
|
-
const filePath = join(contextPath, 'architecture.md');
|
|
638
|
-
switch (operation) {
|
|
639
|
-
case 'get': {
|
|
640
|
-
try {
|
|
641
|
-
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
642
|
-
const parsed = matter(fileContent);
|
|
643
|
-
return {
|
|
644
|
-
success: true,
|
|
645
|
-
data: {
|
|
646
|
-
content: parsed.content,
|
|
647
|
-
frontmatter: parsed.data,
|
|
648
|
-
raw: fileContent
|
|
649
|
-
},
|
|
650
|
-
message: 'Retrieved architecture context'
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
catch (err) {
|
|
654
|
-
if (err.code === 'ENOENT') {
|
|
655
|
-
return {
|
|
656
|
-
success: true,
|
|
657
|
-
data: { content: '', frontmatter: {}, raw: '' },
|
|
658
|
-
message: 'Architecture context document does not exist yet. You can create it with an update operation.'
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
throw err;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
case 'append': {
|
|
665
|
-
if (!content) {
|
|
666
|
-
return { success: false, error: 'Content is required for append operation' };
|
|
667
|
-
}
|
|
668
|
-
await fs.mkdir(contextPath, { recursive: true });
|
|
669
|
-
// Read existing content if file exists
|
|
670
|
-
let existingContent = '';
|
|
671
|
-
try {
|
|
672
|
-
existingContent = await fs.readFile(filePath, 'utf-8');
|
|
673
|
-
}
|
|
674
|
-
catch (err) {
|
|
675
|
-
if (err.code !== 'ENOENT')
|
|
676
|
-
throw err;
|
|
677
|
-
}
|
|
678
|
-
// Append new content with a newline separator
|
|
679
|
-
const newContent = existingContent
|
|
680
|
-
? existingContent.trimEnd() + '\n\n' + content
|
|
681
|
-
: content;
|
|
682
|
-
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
683
|
-
return {
|
|
684
|
-
success: true,
|
|
685
|
-
message: 'Appended content to architecture context document'
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
case 'replace_section': {
|
|
689
|
-
if (!old_text || !new_text) {
|
|
690
|
-
return { success: false, error: 'Both old_text and new_text are required for replace_section operation' };
|
|
691
|
-
}
|
|
692
|
-
// Read existing content
|
|
693
|
-
let existingContent = '';
|
|
694
|
-
try {
|
|
695
|
-
existingContent = await fs.readFile(filePath, 'utf-8');
|
|
696
|
-
}
|
|
697
|
-
catch (err) {
|
|
698
|
-
if (err.code === 'ENOENT') {
|
|
699
|
-
return { success: false, error: 'Architecture context document does not exist. Use append or update to create it first.' };
|
|
700
|
-
}
|
|
701
|
-
throw err;
|
|
702
|
-
}
|
|
703
|
-
// Check if old_text exists in the document
|
|
704
|
-
if (!existingContent.includes(old_text)) {
|
|
705
|
-
return {
|
|
706
|
-
success: false,
|
|
707
|
-
error: 'Could not find the specified text in the document. The text may have been paraphrased or changed.',
|
|
708
|
-
fallback_markdown: new_text,
|
|
709
|
-
suggestion: 'Here is the replacement text. You can copy it and manually edit the document at /context/architecture'
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
// Replace the text
|
|
713
|
-
const updatedContent = existingContent.replace(old_text, new_text);
|
|
714
|
-
await fs.writeFile(filePath, updatedContent, 'utf-8');
|
|
715
|
-
return {
|
|
716
|
-
success: true,
|
|
717
|
-
message: 'Replaced section in architecture context document'
|
|
718
|
-
};
|
|
719
|
-
}
|
|
720
|
-
case 'update': {
|
|
721
|
-
if (!content) {
|
|
722
|
-
return { success: false, error: 'Content is required for update operation' };
|
|
723
|
-
}
|
|
724
|
-
await fs.mkdir(contextPath, { recursive: true });
|
|
725
|
-
await fs.writeFile(filePath, content, 'utf-8');
|
|
726
|
-
return {
|
|
727
|
-
success: true,
|
|
728
|
-
message: 'Updated architecture context document'
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
default:
|
|
732
|
-
return { success: false, error: `Unknown operation: ${operation}. Use 'get', 'append', 'replace_section', or 'update'.` };
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
catch (error) {
|
|
736
|
-
console.error('Error executing architecture context tool:', error);
|
|
737
|
-
return { success: false, error: error.message || 'Architecture context tool execution failed' };
|
|
738
|
-
}
|
|
661
|
+
// Agents context tool - read/write the agents definition document
|
|
662
|
+
async function executeAgentsContextToolDirect(args) {
|
|
663
|
+
return executeGenericContextToolDirect('agents', args);
|
|
739
664
|
}
|
|
740
|
-
//
|
|
741
|
-
async function
|
|
665
|
+
// Team context tool - read/write the team definition document
|
|
666
|
+
async function executeTeamContextToolDirect(args) {
|
|
667
|
+
return executeGenericContextToolDirect('team', args);
|
|
668
|
+
}
|
|
669
|
+
// Memory context tool - read/write the memory document
|
|
670
|
+
async function executeMemoryContextToolDirect(args) {
|
|
671
|
+
return executeGenericContextToolDirect('memory', args);
|
|
672
|
+
}
|
|
673
|
+
async function executeGenericContextToolDirect(contextType, args) {
|
|
742
674
|
const { operation, content, old_text, new_text } = args;
|
|
675
|
+
const label = contextType.charAt(0).toUpperCase() + contextType.slice(1);
|
|
743
676
|
try {
|
|
744
677
|
const contextPath = getContextBasePath();
|
|
745
|
-
const filePath = join(contextPath,
|
|
678
|
+
const filePath = join(contextPath, `${contextType}.md`);
|
|
746
679
|
switch (operation) {
|
|
747
680
|
case 'get': {
|
|
748
681
|
try {
|
|
@@ -755,7 +688,7 @@ async function executeRoleContextToolDirect(args) {
|
|
|
755
688
|
frontmatter: parsed.data,
|
|
756
689
|
raw: fileContent
|
|
757
690
|
},
|
|
758
|
-
message:
|
|
691
|
+
message: `Retrieved ${contextType} context`
|
|
759
692
|
};
|
|
760
693
|
}
|
|
761
694
|
catch (err) {
|
|
@@ -763,7 +696,7 @@ async function executeRoleContextToolDirect(args) {
|
|
|
763
696
|
return {
|
|
764
697
|
success: true,
|
|
765
698
|
data: { content: '', frontmatter: {}, raw: '' },
|
|
766
|
-
message:
|
|
699
|
+
message: `${label} context document does not exist yet. You can create it with an update operation.`
|
|
767
700
|
};
|
|
768
701
|
}
|
|
769
702
|
throw err;
|
|
@@ -774,7 +707,6 @@ async function executeRoleContextToolDirect(args) {
|
|
|
774
707
|
return { success: false, error: 'Content is required for append operation' };
|
|
775
708
|
}
|
|
776
709
|
await fs.mkdir(contextPath, { recursive: true });
|
|
777
|
-
// Read existing content if file exists
|
|
778
710
|
let existingContent = '';
|
|
779
711
|
try {
|
|
780
712
|
existingContent = await fs.readFile(filePath, 'utf-8');
|
|
@@ -783,46 +715,42 @@ async function executeRoleContextToolDirect(args) {
|
|
|
783
715
|
if (err.code !== 'ENOENT')
|
|
784
716
|
throw err;
|
|
785
717
|
}
|
|
786
|
-
// Append new content with a newline separator
|
|
787
718
|
const newContent = existingContent
|
|
788
719
|
? existingContent.trimEnd() + '\n\n' + content
|
|
789
720
|
: content;
|
|
790
721
|
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
791
722
|
return {
|
|
792
723
|
success: true,
|
|
793
|
-
message:
|
|
724
|
+
message: `Appended content to ${contextType} context document`
|
|
794
725
|
};
|
|
795
726
|
}
|
|
796
727
|
case 'replace_section': {
|
|
797
728
|
if (!old_text || !new_text) {
|
|
798
729
|
return { success: false, error: 'Both old_text and new_text are required for replace_section operation' };
|
|
799
730
|
}
|
|
800
|
-
// Read existing content
|
|
801
731
|
let existingContent = '';
|
|
802
732
|
try {
|
|
803
733
|
existingContent = await fs.readFile(filePath, 'utf-8');
|
|
804
734
|
}
|
|
805
735
|
catch (err) {
|
|
806
736
|
if (err.code === 'ENOENT') {
|
|
807
|
-
return { success: false, error:
|
|
737
|
+
return { success: false, error: `${label} context document does not exist. Use append or update to create it first.` };
|
|
808
738
|
}
|
|
809
739
|
throw err;
|
|
810
740
|
}
|
|
811
|
-
// Check if old_text exists in the document
|
|
812
741
|
if (!existingContent.includes(old_text)) {
|
|
813
742
|
return {
|
|
814
743
|
success: false,
|
|
815
744
|
error: 'Could not find the specified text in the document. The text may have been paraphrased or changed.',
|
|
816
745
|
fallback_markdown: new_text,
|
|
817
|
-
suggestion:
|
|
746
|
+
suggestion: `Here is the replacement text. You can copy it and manually edit the document at /context/${contextType}`
|
|
818
747
|
};
|
|
819
748
|
}
|
|
820
|
-
// Replace the text
|
|
821
749
|
const updatedContent = existingContent.replace(old_text, new_text);
|
|
822
750
|
await fs.writeFile(filePath, updatedContent, 'utf-8');
|
|
823
751
|
return {
|
|
824
752
|
success: true,
|
|
825
|
-
message:
|
|
753
|
+
message: `Replaced section in ${contextType} context document`
|
|
826
754
|
};
|
|
827
755
|
}
|
|
828
756
|
case 'update': {
|
|
@@ -833,7 +761,7 @@ async function executeRoleContextToolDirect(args) {
|
|
|
833
761
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
834
762
|
return {
|
|
835
763
|
success: true,
|
|
836
|
-
message:
|
|
764
|
+
message: `Updated ${contextType} context document`
|
|
837
765
|
};
|
|
838
766
|
}
|
|
839
767
|
default:
|
|
@@ -841,8 +769,8 @@ async function executeRoleContextToolDirect(args) {
|
|
|
841
769
|
}
|
|
842
770
|
}
|
|
843
771
|
catch (error) {
|
|
844
|
-
console.error(
|
|
845
|
-
return { success: false, error: error.message ||
|
|
772
|
+
console.error(`Error executing ${contextType} context tool:`, error);
|
|
773
|
+
return { success: false, error: error.message || `${label} context tool execution failed` };
|
|
846
774
|
}
|
|
847
775
|
}
|
|
848
776
|
// ─── Resources Tool ─────────────────────────────────────────────────────────
|
|
@@ -1352,13 +1280,147 @@ function readRoleContext() {
|
|
|
1352
1280
|
catch { }
|
|
1353
1281
|
return null;
|
|
1354
1282
|
}
|
|
1283
|
+
function readMemoryContext() {
|
|
1284
|
+
try {
|
|
1285
|
+
const contextPath = getContextBasePath();
|
|
1286
|
+
const memoryPath = join(contextPath, 'memory.md');
|
|
1287
|
+
if (existsSync(memoryPath)) {
|
|
1288
|
+
return readFileSync(memoryPath, 'utf-8');
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
catch { }
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1355
1294
|
function getSystemPrompt() {
|
|
1356
1295
|
const basePrompt = readSharedPrompt('coconut-assistant') ||
|
|
1357
1296
|
`You are the Coconut 🥥 AI assistant for agent-native development workflows. You help developers with proposals, architecture decisions, planning, and execution.`;
|
|
1358
|
-
// Add role context if it exists
|
|
1359
1297
|
const roleContent = readRoleContext();
|
|
1298
|
+
const memoryContent = readMemoryContext();
|
|
1299
|
+
let result = basePrompt;
|
|
1360
1300
|
if (roleContent) {
|
|
1361
|
-
|
|
1301
|
+
result = `${result}\n\n## Your Role for This Instance\n\n${roleContent}`;
|
|
1302
|
+
}
|
|
1303
|
+
if (memoryContent) {
|
|
1304
|
+
result = `${result}\n\n## Memory for This Instance\n\n${memoryContent}`;
|
|
1305
|
+
}
|
|
1306
|
+
return result;
|
|
1307
|
+
}
|
|
1308
|
+
const COCONUT_HOST = 'https://app.coconut.dev';
|
|
1309
|
+
async function executeListConnectorsToolDirect() {
|
|
1310
|
+
const token = getGlobalApiKey('callbackToken');
|
|
1311
|
+
if (!token) {
|
|
1312
|
+
return {
|
|
1313
|
+
success: false,
|
|
1314
|
+
error: 'Callback token not configured. Set it via Settings > API Keys or PUT /api/v1/config?type=global with { "apiKeys": { "callbackToken": "cpt_xxx" } }'
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
try {
|
|
1318
|
+
const res = await fetch(`${COCONUT_HOST}/api/connectors/accounts`, {
|
|
1319
|
+
headers: { 'X-Callback-Token': token }
|
|
1320
|
+
});
|
|
1321
|
+
if (!res.ok) {
|
|
1322
|
+
const body = await res.text().catch(() => '');
|
|
1323
|
+
return { success: false, error: `Control plane returned ${res.status}: ${body || res.statusText}` };
|
|
1324
|
+
}
|
|
1325
|
+
const data = await res.json();
|
|
1326
|
+
const accounts = Array.isArray(data) ? data : (data.accounts ?? data.data ?? []);
|
|
1327
|
+
return {
|
|
1328
|
+
success: true,
|
|
1329
|
+
data: accounts,
|
|
1330
|
+
count: accounts.length,
|
|
1331
|
+
message: `Found ${accounts.length} connected service${accounts.length === 1 ? '' : 's'}`
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
catch (error) {
|
|
1335
|
+
return { success: false, error: error.message || 'Failed to list connectors' };
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
async function executeConnectorRequestToolDirect(args) {
|
|
1339
|
+
const { app: appSlug, method, path: apiPath, body, headers: extraHeaders } = args;
|
|
1340
|
+
if (!appSlug || !method || !apiPath) {
|
|
1341
|
+
return { success: false, error: 'app, method, and path are required' };
|
|
1342
|
+
}
|
|
1343
|
+
const token = getGlobalApiKey('callbackToken');
|
|
1344
|
+
if (!token) {
|
|
1345
|
+
return {
|
|
1346
|
+
success: false,
|
|
1347
|
+
error: 'Callback token not configured. Set it via Settings > API Keys or PUT /api/v1/config?type=global with { "apiKeys": { "callbackToken": "cpt_xxx" } }'
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
try {
|
|
1351
|
+
const accountsRes = await fetch(`${COCONUT_HOST}/api/connectors/accounts`, {
|
|
1352
|
+
headers: { 'X-Callback-Token': token }
|
|
1353
|
+
});
|
|
1354
|
+
if (!accountsRes.ok) {
|
|
1355
|
+
const errBody = await accountsRes.text().catch(() => '');
|
|
1356
|
+
return { success: false, error: `Failed to fetch accounts (${accountsRes.status}): ${errBody || accountsRes.statusText}` };
|
|
1357
|
+
}
|
|
1358
|
+
const accountsData = await accountsRes.json();
|
|
1359
|
+
const accounts = Array.isArray(accountsData) ? accountsData : (accountsData.accounts ?? accountsData.data ?? []);
|
|
1360
|
+
const account = accounts.find((a) => a.appSlug === appSlug || a.appName?.toLowerCase() === appSlug.toLowerCase());
|
|
1361
|
+
if (!account) {
|
|
1362
|
+
return {
|
|
1363
|
+
success: false,
|
|
1364
|
+
error: `No connected account found for "${appSlug}"`,
|
|
1365
|
+
available: accounts.map((a) => a.appSlug || a.appName)
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
const url = resolveConnectorUrl(appSlug, apiPath);
|
|
1369
|
+
if (!url) {
|
|
1370
|
+
return {
|
|
1371
|
+
success: false,
|
|
1372
|
+
error: `Unknown app "${appSlug}" and path is not a full URL. Use a full URL (https://...) or a known app slug.`
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
let parsedBody = undefined;
|
|
1376
|
+
if (body) {
|
|
1377
|
+
try {
|
|
1378
|
+
parsedBody = typeof body === 'string' ? JSON.parse(body) : body;
|
|
1379
|
+
}
|
|
1380
|
+
catch {
|
|
1381
|
+
return { success: false, error: 'Invalid JSON in body parameter' };
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
let parsedHeaders = {};
|
|
1385
|
+
if (extraHeaders) {
|
|
1386
|
+
try {
|
|
1387
|
+
parsedHeaders = typeof extraHeaders === 'string' ? JSON.parse(extraHeaders) : extraHeaders;
|
|
1388
|
+
}
|
|
1389
|
+
catch {
|
|
1390
|
+
return { success: false, error: 'Invalid JSON in headers parameter' };
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
const proxyPayload = {
|
|
1394
|
+
accountId: account.accountId,
|
|
1395
|
+
url,
|
|
1396
|
+
method: method.toUpperCase()
|
|
1397
|
+
};
|
|
1398
|
+
if (parsedBody !== undefined)
|
|
1399
|
+
proxyPayload.body = parsedBody;
|
|
1400
|
+
if (Object.keys(parsedHeaders).length > 0)
|
|
1401
|
+
proxyPayload.headers = parsedHeaders;
|
|
1402
|
+
const proxyRes = await fetch(`${COCONUT_HOST}/api/connectors/proxy`, {
|
|
1403
|
+
method: 'POST',
|
|
1404
|
+
headers: {
|
|
1405
|
+
'Content-Type': 'application/json',
|
|
1406
|
+
'X-Callback-Token': token
|
|
1407
|
+
},
|
|
1408
|
+
body: JSON.stringify(proxyPayload)
|
|
1409
|
+
});
|
|
1410
|
+
if (!proxyRes.ok) {
|
|
1411
|
+
const errBody = await proxyRes.text().catch(() => '');
|
|
1412
|
+
return { success: false, error: `Proxy request failed (${proxyRes.status}): ${errBody || proxyRes.statusText}` };
|
|
1413
|
+
}
|
|
1414
|
+
const responseData = await proxyRes.json().catch(async () => {
|
|
1415
|
+
return await proxyRes.text().catch(() => null);
|
|
1416
|
+
});
|
|
1417
|
+
return {
|
|
1418
|
+
success: true,
|
|
1419
|
+
data: responseData,
|
|
1420
|
+
message: `${method.toUpperCase()} ${apiPath} via ${appSlug}`
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
catch (error) {
|
|
1424
|
+
return { success: false, error: error.message || 'Connector request failed' };
|
|
1362
1425
|
}
|
|
1363
|
-
return basePrompt;
|
|
1364
1426
|
}
|
|
@@ -124,12 +124,12 @@ export async function PUT(c) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
else {
|
|
127
|
-
// Update project config
|
|
127
|
+
// Update project config
|
|
128
128
|
try {
|
|
129
129
|
const body = await c.req.json();
|
|
130
|
-
const { coconut } = body;
|
|
131
|
-
if (!coconut) {
|
|
132
|
-
return c.json({ error: 'Missing coconut
|
|
130
|
+
const { coconut, scripts } = body;
|
|
131
|
+
if (!coconut && scripts === undefined) {
|
|
132
|
+
return c.json({ error: 'Missing coconut or scripts in request body' }, 400);
|
|
133
133
|
}
|
|
134
134
|
const configPath = await getConfigPath();
|
|
135
135
|
if (!configPath) {
|
|
@@ -152,11 +152,15 @@ export async function PUT(c) {
|
|
|
152
152
|
// Ensure .nut directory exists
|
|
153
153
|
const configDir = path.dirname(configPath);
|
|
154
154
|
await fs.mkdir(configDir, { recursive: true });
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
if (coconut) {
|
|
156
|
+
config.coconut = {
|
|
157
|
+
...config.coconut,
|
|
158
|
+
...coconut,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (scripts !== undefined) {
|
|
162
|
+
config.scripts = scripts;
|
|
163
|
+
}
|
|
160
164
|
// Save config
|
|
161
165
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
162
166
|
return c.json({
|