tuna-agent 0.1.76 → 0.1.78
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.
|
@@ -61,3 +61,9 @@ export interface CharProfile {
|
|
|
61
61
|
export declare function handleListCharacters(ws: AgentWebSocketClient, code: string, taskId: string): void;
|
|
62
62
|
export declare function handleCreateCharacter(ws: AgentWebSocketClient, code: string, taskId: string, name: string, displayName: string, prompt: string, outputCount?: number, orientation?: string): Promise<void>;
|
|
63
63
|
export declare function handleSaveCharacterSelection(ws: AgentWebSocketClient, code: string, taskId: string, characterId: string, selectedImages: string[]): void;
|
|
64
|
+
/**
|
|
65
|
+
* Sync apps from the agent's knowledge base.
|
|
66
|
+
* Searches all folders (2 levels deep) for the "App Info" document,
|
|
67
|
+
* then parses the multi-app markdown format.
|
|
68
|
+
*/
|
|
69
|
+
export declare function handleSyncApps(ws: AgentWebSocketClient, code: string, taskId: string, apiUrl: string, agentToken: string, agentId: string): Promise<void>;
|
|
@@ -890,6 +890,126 @@ export function handleSaveCharacterSelection(ws, code, taskId, characterId, sele
|
|
|
890
890
|
ws.sendExtensionDone(code, taskId, { error });
|
|
891
891
|
}
|
|
892
892
|
}
|
|
893
|
+
const APP_COLORS = [
|
|
894
|
+
'#22D3EE', '#A78BFA', '#F472B6', '#34D399', '#FBBF24',
|
|
895
|
+
'#FB923C', '#60A5FA', '#E879F9', '#2DD4BF', '#F87171',
|
|
896
|
+
];
|
|
897
|
+
/**
|
|
898
|
+
* Sync apps from the agent's knowledge base.
|
|
899
|
+
* Searches all folders (2 levels deep) for the "App Info" document,
|
|
900
|
+
* then parses the multi-app markdown format.
|
|
901
|
+
*/
|
|
902
|
+
export async function handleSyncApps(ws, code, taskId, apiUrl, agentToken, agentId) {
|
|
903
|
+
try {
|
|
904
|
+
console.log('[sync_apps] Starting knowledge sync...');
|
|
905
|
+
const knowledgeApi = async (method, apiPath) => {
|
|
906
|
+
const url = `${apiUrl}${apiPath}`;
|
|
907
|
+
const res = await fetch(url, {
|
|
908
|
+
method,
|
|
909
|
+
headers: {
|
|
910
|
+
'Authorization': `Bearer ${agentToken}`,
|
|
911
|
+
'Content-Type': 'application/json',
|
|
912
|
+
},
|
|
913
|
+
});
|
|
914
|
+
const json = await res.json();
|
|
915
|
+
if (!res.ok || (json.code && json.code >= 400)) {
|
|
916
|
+
throw new Error(json.message || `API error: ${res.status}`);
|
|
917
|
+
}
|
|
918
|
+
return json.data;
|
|
919
|
+
};
|
|
920
|
+
// Collect all documents (2 levels deep)
|
|
921
|
+
const allDocs = [];
|
|
922
|
+
const rootData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}`);
|
|
923
|
+
const rootItems = rootData.items || [];
|
|
924
|
+
for (const item of rootItems) {
|
|
925
|
+
if (item.kind === 'folder') {
|
|
926
|
+
const folderData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}&parent_id=${item._id}`);
|
|
927
|
+
for (const child of (folderData.items || [])) {
|
|
928
|
+
if (child.kind !== 'folder')
|
|
929
|
+
allDocs.push(child);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
allDocs.push(item);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
// Find "App Info" document (or any doc with "app info" in name)
|
|
937
|
+
const appInfoDoc = allDocs.find(d => d.name.toLowerCase().includes('app info'));
|
|
938
|
+
let apps = [];
|
|
939
|
+
if (appInfoDoc) {
|
|
940
|
+
const doc = await knowledgeApi('GET', `/agent-knowledge/${appInfoDoc._id}`);
|
|
941
|
+
apps = _parseAppInfoDocument(doc.content || '');
|
|
942
|
+
console.log(`[sync_apps] Parsed ${apps.length} app(s) from "${appInfoDoc.name}"`);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
console.log('[sync_apps] No "App Info" document found in knowledge');
|
|
946
|
+
}
|
|
947
|
+
ws.sendExtensionEvent(code, {
|
|
948
|
+
type: 'sync_apps_result',
|
|
949
|
+
apps,
|
|
950
|
+
});
|
|
951
|
+
ws.sendExtensionDone(code, taskId, { ok: true, count: apps.length });
|
|
952
|
+
}
|
|
953
|
+
catch (err) {
|
|
954
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
955
|
+
console.error('[sync_apps] Error:', error);
|
|
956
|
+
ws.sendExtensionEvent(code, {
|
|
957
|
+
type: 'sync_apps_result',
|
|
958
|
+
apps: null,
|
|
959
|
+
error,
|
|
960
|
+
});
|
|
961
|
+
ws.sendExtensionDone(code, taskId, { error });
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Parse the multi-app markdown document format.
|
|
966
|
+
* Each app starts with `# App Name - Tagline` and is separated by `---`.
|
|
967
|
+
* Features are numbered lists under `## Features`.
|
|
968
|
+
*/
|
|
969
|
+
function _parseAppInfoDocument(content) {
|
|
970
|
+
// Split by horizontal rules (---) into app sections
|
|
971
|
+
const sections = content.split(/\n---\n/).filter(s => s.trim());
|
|
972
|
+
const apps = [];
|
|
973
|
+
for (let i = 0; i < sections.length; i++) {
|
|
974
|
+
const section = sections[i];
|
|
975
|
+
// Extract app name from first H1: # App Name - Tagline
|
|
976
|
+
const h1Match = section.match(/^#\s+(.+?)(?:\s*\n|$)/m);
|
|
977
|
+
if (!h1Match)
|
|
978
|
+
continue;
|
|
979
|
+
const fullTitle = h1Match[1].trim();
|
|
980
|
+
// Split "Name - Tagline" at first " - "
|
|
981
|
+
const dashIdx = fullTitle.indexOf(' - ');
|
|
982
|
+
const name = dashIdx > 0 ? fullTitle.substring(0, dashIdx).trim() : fullTitle;
|
|
983
|
+
const tagline = dashIdx > 0 ? fullTitle.substring(dashIdx + 3).trim() : '';
|
|
984
|
+
// Extract ID from `- **ID:** \`xxx\``
|
|
985
|
+
const idMatch = section.match(/\*\*ID:\*\*\s*`([^`]+)`/);
|
|
986
|
+
const appId = idMatch ? idMatch[1] : name.toLowerCase().replace(/\s+/g, '-');
|
|
987
|
+
// Extract description from ## Promotional Text > blockquote
|
|
988
|
+
const promoMatch = section.match(/## Promotional Text\s*\n>\s*(.+)/);
|
|
989
|
+
const description = promoMatch ? promoMatch[1].trim() : tagline;
|
|
990
|
+
// Extract features from numbered list under ## Features
|
|
991
|
+
const features = [];
|
|
992
|
+
const featSection = section.match(/## Features\n([\s\S]*?)(?=\n##|\n---|\n_Last|$)/);
|
|
993
|
+
if (featSection) {
|
|
994
|
+
const featRegex = /^\d+\.\s+\*\*([^*]+)\*\*/gm;
|
|
995
|
+
let m;
|
|
996
|
+
while ((m = featRegex.exec(featSection[1])) !== null) {
|
|
997
|
+
features.push(m[1].trim());
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
// Skip metadata-only sections (like _Last synced_)
|
|
1001
|
+
if (!name || name.startsWith('_'))
|
|
1002
|
+
continue;
|
|
1003
|
+
apps.push({
|
|
1004
|
+
id: appId,
|
|
1005
|
+
name,
|
|
1006
|
+
description,
|
|
1007
|
+
features,
|
|
1008
|
+
color: APP_COLORS[i % APP_COLORS.length],
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
return apps;
|
|
1012
|
+
}
|
|
893
1013
|
function _sleep(ms) {
|
|
894
1014
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
895
1015
|
}
|
package/dist/daemon/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { loadPMState, savePMState, clearPMState } from './pm-state.js';
|
|
|
9
9
|
import { chatWithPM } from '../pm/planner.js';
|
|
10
10
|
import { executePlanAndReport, simplifyMarkdown, waitForInput } from '../utils/execution-helpers.js';
|
|
11
11
|
import { runClaude } from '../utils/claude-cli.js';
|
|
12
|
-
import { handleGetHistory, handleRetryVideo, handleGenerateIdeas, handleGenerateScript, handleGenerateScene, handleGenerateScenes, handleRenderVideo, handleListCharacters, handleCreateCharacter, handleSaveCharacterSelection, } from './extension-handlers.js';
|
|
12
|
+
import { handleGetHistory, handleRetryVideo, handleGenerateIdeas, handleGenerateScript, handleGenerateScene, handleGenerateScenes, handleRenderVideo, handleListCharacters, handleCreateCharacter, handleSaveCharacterSelection, handleSyncApps, } from './extension-handlers.js';
|
|
13
13
|
import { downloadAttachments, cleanupAttachments } from '../utils/image-download.js';
|
|
14
14
|
import { scanSkills } from '../utils/skill-scanner.js';
|
|
15
15
|
import { setupMcpConfig } from '../mcp/setup.js';
|
|
@@ -565,6 +565,12 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
565
565
|
handleSaveCharacterSelection(ws, extCode, extTaskId, msg.characterId, msg.selectedImages || []);
|
|
566
566
|
break;
|
|
567
567
|
}
|
|
568
|
+
if (extTask === 'sync_apps') {
|
|
569
|
+
(async () => {
|
|
570
|
+
await handleSyncApps(ws, extCode, extTaskId, config.apiUrl, config.agentToken, config.agentId);
|
|
571
|
+
})();
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
568
574
|
// ── Claude-powered tasks (ideas, script, etc.) ────────────────────────
|
|
569
575
|
(async () => {
|
|
570
576
|
try {
|