tuna-agent 0.1.76 → 0.1.77

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,8 @@ 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
+ * Reads knowledge items, identifies app-related documents, extracts app info.
67
+ */
68
+ export declare function handleSyncApps(ws: AgentWebSocketClient, code: string, taskId: string, apiUrl: string, agentToken: string, agentId: string): Promise<void>;
@@ -890,6 +890,120 @@ 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
+ * Reads knowledge items, identifies app-related documents, extracts app info.
900
+ */
901
+ export async function handleSyncApps(ws, code, taskId, apiUrl, agentToken, agentId) {
902
+ try {
903
+ console.log('[sync_apps] Starting knowledge sync...');
904
+ const knowledgeApi = async (method, apiPath) => {
905
+ const url = `${apiUrl}${apiPath}`;
906
+ const res = await fetch(url, {
907
+ method,
908
+ headers: {
909
+ 'Authorization': `Bearer ${agentToken}`,
910
+ 'Content-Type': 'application/json',
911
+ },
912
+ });
913
+ const json = await res.json();
914
+ if (!res.ok || (json.code && json.code >= 400)) {
915
+ throw new Error(json.message || `API error: ${res.status}`);
916
+ }
917
+ return json.data;
918
+ };
919
+ // 1. List all root-level knowledge items
920
+ const rootData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}`);
921
+ const items = rootData.items || [];
922
+ // 2. Find app-related documents
923
+ const apps = [];
924
+ let colorIdx = 0;
925
+ for (const item of items) {
926
+ const nameLower = item.name.toLowerCase();
927
+ const descLower = (item.description || '').toLowerCase();
928
+ const isApp = nameLower.includes('app') ||
929
+ descLower.includes('app') ||
930
+ descLower.includes('application') ||
931
+ descLower.includes('mobile app') ||
932
+ descLower.includes('product');
933
+ if (!isApp)
934
+ continue;
935
+ if (item.kind === 'folder') {
936
+ const folderData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}&parent_id=${item._id}`);
937
+ const children = folderData.items || [];
938
+ const features = [];
939
+ let appDesc = item.description || '';
940
+ for (const child of children) {
941
+ if (child.kind === 'document') {
942
+ const doc = await knowledgeApi('GET', `/agent-knowledge/${child._id}`);
943
+ features.push(..._extractFeatures(doc.content || ''));
944
+ if (!appDesc && doc.description)
945
+ appDesc = doc.description;
946
+ }
947
+ }
948
+ apps.push({
949
+ id: item._id,
950
+ name: item.name,
951
+ description: appDesc,
952
+ features: [...new Set(features)].slice(0, 20),
953
+ color: APP_COLORS[colorIdx++ % APP_COLORS.length],
954
+ });
955
+ }
956
+ else if (item.kind === 'document') {
957
+ const doc = await knowledgeApi('GET', `/agent-knowledge/${item._id}`);
958
+ apps.push({
959
+ id: item._id,
960
+ name: item.name,
961
+ description: item.description || doc.description || '',
962
+ features: [...new Set(_extractFeatures(doc.content || ''))].slice(0, 20),
963
+ color: APP_COLORS[colorIdx++ % APP_COLORS.length],
964
+ });
965
+ }
966
+ }
967
+ console.log(`[sync_apps] Found ${apps.length} app(s)`);
968
+ ws.sendExtensionEvent(code, {
969
+ type: 'sync_apps_result',
970
+ apps,
971
+ });
972
+ ws.sendExtensionDone(code, taskId, { ok: true, count: apps.length });
973
+ }
974
+ catch (err) {
975
+ const error = err instanceof Error ? err.message : String(err);
976
+ console.error('[sync_apps] Error:', error);
977
+ ws.sendExtensionEvent(code, {
978
+ type: 'sync_apps_result',
979
+ apps: null,
980
+ error,
981
+ });
982
+ ws.sendExtensionDone(code, taskId, { error });
983
+ }
984
+ }
985
+ /** Extract feature names from markdown bullet lists or headings. */
986
+ function _extractFeatures(content) {
987
+ const features = [];
988
+ const bulletRegex = /^[\s]*[-*]\s+\*{0,2}([^*\n]+)\*{0,2}/gm;
989
+ let match;
990
+ while ((match = bulletRegex.exec(content)) !== null) {
991
+ const feat = match[1].trim().replace(/[:–—].+$/, '').trim();
992
+ if (feat.length > 2 && feat.length < 60) {
993
+ features.push(feat);
994
+ }
995
+ }
996
+ if (features.length === 0) {
997
+ const headingRegex = /^#{2,4}\s+(.+)$/gm;
998
+ while ((match = headingRegex.exec(content)) !== null) {
999
+ const feat = match[1].trim();
1000
+ if (feat.length > 2 && feat.length < 60) {
1001
+ features.push(feat);
1002
+ }
1003
+ }
1004
+ }
1005
+ return features;
1006
+ }
893
1007
  function _sleep(ms) {
894
1008
  return new Promise(resolve => setTimeout(resolve, ms));
895
1009
  }
@@ -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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.76",
3
+ "version": "0.1.77",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"