@assistkick/create 1.7.0 → 1.9.0
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/bin/create.js +0 -0
- package/package.json +9 -7
- package/templates/assistkick-product-system/.env.example +1 -0
- package/templates/assistkick-product-system/local.db +0 -0
- package/templates/assistkick-product-system/package.json +4 -2
- package/templates/assistkick-product-system/packages/backend/package.json +2 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +165 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +358 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +356 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +96 -1
- package/templates/assistkick-product-system/packages/backend/src/routes/graph.ts +1 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/kanban.ts +61 -6
- package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +200 -84
- package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +6 -3
- package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +53 -17
- package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +218 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +119 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +158 -0
- package/templates/assistkick-product-system/packages/backend/src/server.ts +60 -9
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +489 -0
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +416 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.test.ts +189 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.ts +182 -0
- package/templates/assistkick-product-system/packages/backend/src/services/init.ts +43 -77
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +16 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +73 -2
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +4 -4
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +87 -11
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +210 -69
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +210 -215
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +162 -0
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +148 -0
- package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +11 -5
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.test.ts +64 -0
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +134 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.test.ts +256 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +258 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_group_service.ts +106 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.test.ts +275 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.ts +245 -0
- package/templates/assistkick-product-system/packages/frontend/package-lock.json +3455 -0
- package/templates/assistkick-product-system/packages/frontend/package.json +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/App.tsx +8 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +458 -18
- package/templates/assistkick-product-system/packages/frontend/src/api/client_files.test.ts +172 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client_video.test.ts +238 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +307 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/CoherenceView.tsx +82 -66
- package/templates/assistkick-product-system/packages/frontend/src/components/CompositionPlaceholder.tsx +97 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/DesignSystemView.tsx +20 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +57 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeContextMenu.tsx +61 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +73 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +404 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +187 -56
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +71 -73
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphSettings.tsx +8 -8
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphView.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/components/InviteUserDialog.tsx +15 -11
- package/templates/assistkick-product-system/packages/frontend/src/components/IterationCommentModal.tsx +80 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +263 -167
- package/templates/assistkick-product-system/packages/frontend/src/components/LoginPage.tsx +14 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +54 -33
- package/templates/assistkick-product-system/packages/frontend/src/components/QaIssueSheet.tsx +32 -49
- package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +43 -48
- package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +121 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +20 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/UsersView.tsx +52 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/VideoGallery.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/VideographyView.tsx +250 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/WorkflowsView.tsx +474 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/AccentBorderList.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Button.tsx +87 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonGroup.tsx +29 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx +221 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CardGlass.tsx +141 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx +30 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx +34 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx +74 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx +103 -87
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCardShowcase.tsx +9 -188
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Kbd.tsx +11 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KindBadge.tsx +21 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/NavBarSidekick.tsx +81 -37
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SidePanelShowcase.tsx +370 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SideSheet.tsx +64 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/StatusDot.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCardPositionNode.tsx +36 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCycleCountNode.tsx +60 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/EndNode.tsx +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GenerateTTSNode.tsx +52 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +189 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +123 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RebuildBundleNode.tsx +20 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RenderVideoNode.tsx +72 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RunAgentNode.tsx +51 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/SetCardMetadataNode.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/StartNode.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/TransitionCardNode.tsx +59 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +341 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +643 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/autoLayout.ts +103 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/edgeColors.ts +35 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +246 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.test.ts +119 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +136 -0
- package/templates/assistkick-product-system/packages/frontend/src/constants/graph.ts +13 -11
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useAutoSave.ts +75 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useToast.tsx +16 -3
- package/templates/assistkick-product-system/packages/frontend/src/pages/accept_invitation_page.tsx +30 -27
- package/templates/assistkick-product-system/packages/frontend/src/pages/forgot_password_page.tsx +18 -15
- package/templates/assistkick-product-system/packages/frontend/src/pages/register_page.tsx +21 -18
- package/templates/assistkick-product-system/packages/frontend/src/pages/reset_password_page.tsx +28 -25
- package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +6 -3
- package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +4 -4
- package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +275 -3535
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.test.ts +167 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.ts +101 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.test.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.ts +17 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.test.ts +145 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.test.ts +4 -10
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.ts +19 -1
- package/templates/assistkick-product-system/packages/frontend/vite.config.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/db/local.db +0 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0004_tidy_matthew_murdock.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0005_mysterious_falcon.sql +692 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0006_next_venom.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0007_deep_barracuda.sql +39 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0008_puzzling_hannibal_king.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0009_amused_beast.sql +8 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0010_spotty_moira_mactaggert.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_goofy_snowbird.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_supreme_doctor_octopus.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0013_reflective_prowler.sql +15 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0014_nifty_punisher.sql +15 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0004_snapshot.json +921 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0005_snapshot.json +1042 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0006_snapshot.json +1101 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0007_snapshot.json +1336 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0008_snapshot.json +1275 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0009_snapshot.json +1327 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0010_snapshot.json +1393 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0011_snapshot.json +1436 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0013_snapshot.json +1538 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0014_snapshot.json +1545 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +77 -0
- package/templates/assistkick-product-system/packages/shared/db/schema.ts +114 -0
- package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +32 -7
- package/templates/assistkick-product-system/packages/shared/lib/constants.ts +9 -0
- package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +12 -4
- package/templates/assistkick-product-system/packages/shared/lib/graph.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +1999 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +1437 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +211 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +43 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +13 -2
- package/templates/assistkick-product-system/packages/shared/tools/get_kanban.ts +1 -1
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.test.ts +226 -0
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.ts +251 -0
- package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -2
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.test.ts +10 -0
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.ts +6 -0
- package/templates/assistkick-product-system/packages/video/Root.tsx +85 -0
- package/templates/assistkick-product-system/packages/video/components/email_scene.tsx +231 -0
- package/templates/assistkick-product-system/packages/video/components/outro_scene.tsx +153 -0
- package/templates/assistkick-product-system/packages/video/components/part_divider.tsx +90 -0
- package/templates/assistkick-product-system/packages/video/components/scene.tsx +226 -0
- package/templates/assistkick-product-system/packages/video/components/theme.ts +22 -0
- package/templates/assistkick-product-system/packages/video/components/title_scene.tsx +169 -0
- package/templates/assistkick-product-system/packages/video/components/video_split_layout.tsx +84 -0
- package/templates/assistkick-product-system/packages/video/compositions/.gitkeep +0 -0
- package/templates/assistkick-product-system/packages/video/index.ts +4 -0
- package/templates/assistkick-product-system/packages/video/package.json +28 -0
- package/templates/assistkick-product-system/packages/video/remotion.config.ts +11 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.test.ts +326 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.ts +630 -0
- package/templates/assistkick-product-system/packages/video/style.css +1 -0
- package/templates/assistkick-product-system/packages/video/tsconfig.json +18 -0
- package/templates/assistkick-product-system/tests/graph_legend.test.ts +2 -1
- package/templates/assistkick-product-system/tests/video_render_service.test.ts +181 -0
- package/templates/assistkick-product-system/tests/web_terminal.test.ts +219 -455
- package/templates/assistkick-product-system/tests/workflow_integration.test.ts +341 -0
- package/templates/skills/assistkick-developer/SKILL.md +3 -0
- package/templates/skills/assistkick-developer/references/react_development_guidelines.md +225 -0
- package/templates/skills/product-system/graph.json +1890 -0
- package/templates/skills/product-system/kanban.json +304 -0
- package/templates/skills/product-system/nodes/comp_001.md +56 -0
- package/templates/skills/product-system/nodes/comp_002.md +57 -0
- package/templates/skills/product-system/nodes/data_001.md +51 -0
- package/templates/skills/product-system/nodes/data_002.md +40 -0
- package/templates/skills/product-system/nodes/data_004.md +38 -0
- package/templates/skills/product-system/nodes/dec_001.md +34 -0
- package/templates/skills/product-system/nodes/dec_016.md +32 -0
- package/templates/skills/product-system/nodes/feat_008.md +30 -0
- package/templates/skills/video-composition-agent/SKILL.md +232 -0
- package/templates/skills/video-script-writer/SKILL.md +136 -0
|
@@ -10,15 +10,21 @@
|
|
|
10
10
|
"clean": "rm -rf dist"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@monaco-editor/react": "^4.7.0",
|
|
14
|
+
"@remotion/media": "^4.0.434",
|
|
15
|
+
"@remotion/player": "^4.0.434",
|
|
16
|
+
"@remotion/transitions": "^4.0.434",
|
|
13
17
|
"@xterm/addon-fit": "^0.11.0",
|
|
14
18
|
"@xterm/addon-web-links": "^0.12.0",
|
|
15
19
|
"@xterm/xterm": "^6.0.0",
|
|
20
|
+
"@xyflow/react": "^12.10.1",
|
|
16
21
|
"d3": "^7.9.0",
|
|
17
22
|
"lucide-react": "^0.577.0",
|
|
18
23
|
"marked": "^15.0.0",
|
|
19
24
|
"react": "^19.1.0",
|
|
20
25
|
"react-dom": "^19.1.0",
|
|
21
26
|
"react-router-dom": "^7.6.0",
|
|
27
|
+
"remotion": "^4.0.434",
|
|
22
28
|
"zustand": "^5.0.11"
|
|
23
29
|
},
|
|
24
30
|
"devDependencies": {
|
|
@@ -13,6 +13,10 @@ import { CoherenceRoute } from './routes/CoherenceRoute';
|
|
|
13
13
|
import { UsersRoute } from './routes/UsersRoute';
|
|
14
14
|
import { TerminalRoute } from './routes/TerminalRoute';
|
|
15
15
|
import { DesignSystemRoute } from './routes/DesignSystemRoute';
|
|
16
|
+
import { AgentsRoute } from './routes/AgentsRoute';
|
|
17
|
+
import { WorkflowsRoute } from './routes/WorkflowsRoute';
|
|
18
|
+
import { FilesRoute } from './routes/FilesRoute';
|
|
19
|
+
import { VideographyRoute } from './routes/VideographyRoute';
|
|
16
20
|
|
|
17
21
|
export function App() {
|
|
18
22
|
return (
|
|
@@ -30,7 +34,11 @@ export function App() {
|
|
|
30
34
|
<Route path="/coherence" element={<CoherenceRoute />} />
|
|
31
35
|
<Route path="/users" element={<UsersRoute />} />
|
|
32
36
|
<Route path="/terminal" element={<TerminalRoute />} />
|
|
37
|
+
<Route path="/agents" element={<AgentsRoute />} />
|
|
38
|
+
<Route path="/workflows" element={<WorkflowsRoute />} />
|
|
39
|
+
<Route path="/files" element={<FilesRoute />} />
|
|
33
40
|
<Route path="/design-system" element={<DesignSystemRoute />} />
|
|
41
|
+
<Route path="/videography" element={<VideographyRoute />} />
|
|
34
42
|
</Route>
|
|
35
43
|
</Route>
|
|
36
44
|
</Routes>
|
|
@@ -1,3 +1,91 @@
|
|
|
1
|
+
export interface VideoCompositionMeta {
|
|
2
|
+
id: string;
|
|
3
|
+
durationInFrames: number;
|
|
4
|
+
fps: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
folder?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface VideoBundleStatus {
|
|
11
|
+
ready: boolean;
|
|
12
|
+
building: boolean;
|
|
13
|
+
bundlePath: string | null;
|
|
14
|
+
lastBuiltAt: string | null;
|
|
15
|
+
error: string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface VideoRenderStatus {
|
|
19
|
+
id: string;
|
|
20
|
+
status: 'queued' | 'rendering' | 'complete' | 'failed';
|
|
21
|
+
progress: number;
|
|
22
|
+
filePath: string | null;
|
|
23
|
+
fileSize: number | null;
|
|
24
|
+
durationSeconds: number | null;
|
|
25
|
+
error: string | null;
|
|
26
|
+
compositionId: string;
|
|
27
|
+
resolution: string | null;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
completedAt: string | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AgentMetrics {
|
|
33
|
+
nodeId: string;
|
|
34
|
+
agentName: string | null;
|
|
35
|
+
toolCalls: Record<string, number> | null;
|
|
36
|
+
costUsd: number | null;
|
|
37
|
+
numTurns: number | null;
|
|
38
|
+
stopReason: string | null;
|
|
39
|
+
model: string | null;
|
|
40
|
+
contextWindowPct: number | null;
|
|
41
|
+
status: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ToolCallEntry {
|
|
45
|
+
id: string;
|
|
46
|
+
timestamp: string;
|
|
47
|
+
toolName: string;
|
|
48
|
+
target: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface NodeExecutionData {
|
|
52
|
+
id: string;
|
|
53
|
+
nodeId: string;
|
|
54
|
+
status: string;
|
|
55
|
+
startedAt: string | null;
|
|
56
|
+
completedAt: string | null;
|
|
57
|
+
outputData: {
|
|
58
|
+
agentId?: string;
|
|
59
|
+
agentName?: string;
|
|
60
|
+
output?: string;
|
|
61
|
+
toolCalls?: Record<string, number>;
|
|
62
|
+
costUsd?: number;
|
|
63
|
+
numTurns?: number;
|
|
64
|
+
stopReason?: string;
|
|
65
|
+
model?: string;
|
|
66
|
+
contextWindowPct?: number;
|
|
67
|
+
} | null;
|
|
68
|
+
error: string | null;
|
|
69
|
+
attempt: number;
|
|
70
|
+
toolCalls: ToolCallEntry[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface WorkflowMonitorData {
|
|
74
|
+
executionId: string;
|
|
75
|
+
workflowId: string;
|
|
76
|
+
workflowName: string;
|
|
77
|
+
featureId: string;
|
|
78
|
+
status: string;
|
|
79
|
+
currentNodeId: string | null;
|
|
80
|
+
startedAt: string;
|
|
81
|
+
updatedAt: string;
|
|
82
|
+
graphData: {
|
|
83
|
+
nodes: Array<{ id: string; type: string; position: { x: number; y: number }; data: Record<string, unknown> }>;
|
|
84
|
+
edges: Array<{ id: string; source: string; target: string; sourceHandle?: string; data?: { label?: string } }>;
|
|
85
|
+
};
|
|
86
|
+
nodeExecutions: Record<string, NodeExecutionData>;
|
|
87
|
+
}
|
|
88
|
+
|
|
1
89
|
/**
|
|
2
90
|
* API client for fetching graph data and node content.
|
|
3
91
|
* All HTTP calls to the server go through this class.
|
|
@@ -66,11 +154,11 @@ export class ApiClient {
|
|
|
66
154
|
return resp.json();
|
|
67
155
|
};
|
|
68
156
|
|
|
69
|
-
moveCard = async (featureId: string, column: string) => {
|
|
157
|
+
moveCard = async (featureId: string, column: string, comment?: string) => {
|
|
70
158
|
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/move`, {
|
|
71
159
|
method: 'POST',
|
|
72
160
|
headers: { 'Content-Type': 'application/json' },
|
|
73
|
-
body: JSON.stringify({ column }),
|
|
161
|
+
body: JSON.stringify({ column, ...(comment ? { comment } : {}) }),
|
|
74
162
|
});
|
|
75
163
|
if (!resp.ok) {
|
|
76
164
|
const err = await resp.json();
|
|
@@ -107,22 +195,35 @@ export class ApiClient {
|
|
|
107
195
|
return resp.json();
|
|
108
196
|
};
|
|
109
197
|
|
|
110
|
-
|
|
111
|
-
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/
|
|
198
|
+
startWorkflow = async (featureId: string, workflowId?: string, projectId?: string) => {
|
|
199
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow`, {
|
|
112
200
|
method: 'POST',
|
|
113
201
|
headers: { 'Content-Type': 'application/json' },
|
|
202
|
+
body: JSON.stringify({ workflowId, projectId }),
|
|
114
203
|
});
|
|
115
204
|
if (!resp.ok) {
|
|
116
|
-
let msg = `Failed to start
|
|
205
|
+
let msg = `Failed to start workflow: ${resp.status}`;
|
|
117
206
|
try { const err = await resp.json(); msg = err.error || msg; } catch { /* non-JSON response */ }
|
|
118
207
|
throw new Error(msg);
|
|
119
208
|
}
|
|
120
209
|
return resp.json();
|
|
121
210
|
};
|
|
122
211
|
|
|
123
|
-
|
|
124
|
-
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/
|
|
125
|
-
if (!resp.ok) throw new Error(`Failed to get
|
|
212
|
+
getWorkflowStatus = async (featureId: string) => {
|
|
213
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow-status`);
|
|
214
|
+
if (!resp.ok) throw new Error(`Failed to get workflow status: ${resp.status}`);
|
|
215
|
+
return resp.json();
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
getWorkflowMonitor = async (featureId: string): Promise<{ monitor: WorkflowMonitorData | null }> => {
|
|
219
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow-monitor`);
|
|
220
|
+
if (!resp.ok) throw new Error(`Failed to get workflow monitor: ${resp.status}`);
|
|
221
|
+
return resp.json();
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
getWorkflowMetrics = async (featureId: string): Promise<{ metrics: AgentMetrics[] }> => {
|
|
225
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow-metrics`);
|
|
226
|
+
if (!resp.ok) throw new Error(`Failed to get workflow metrics: ${resp.status}`);
|
|
126
227
|
return resp.json();
|
|
127
228
|
};
|
|
128
229
|
|
|
@@ -192,8 +293,11 @@ export class ApiClient {
|
|
|
192
293
|
|
|
193
294
|
// --- Orchestrator (Play All) ---
|
|
194
295
|
|
|
195
|
-
startPlayAll = async (projectId?: string) => {
|
|
196
|
-
const
|
|
296
|
+
startPlayAll = async (projectId?: string, epicId?: string) => {
|
|
297
|
+
const params = new URLSearchParams();
|
|
298
|
+
if (projectId) params.set('project_id', projectId);
|
|
299
|
+
if (epicId) params.set('epic_id', epicId);
|
|
300
|
+
const qs = params.toString() ? `?${params}` : '';
|
|
197
301
|
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/pipeline/play-all${qs}`, {
|
|
198
302
|
method: 'POST',
|
|
199
303
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -225,26 +329,41 @@ export class ApiClient {
|
|
|
225
329
|
return resp.json();
|
|
226
330
|
};
|
|
227
331
|
|
|
228
|
-
|
|
229
|
-
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/resume`, {
|
|
332
|
+
resumeWorkflow = async (featureId: string) => {
|
|
333
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow/resume`, {
|
|
334
|
+
method: 'POST',
|
|
335
|
+
headers: { 'Content-Type': 'application/json' },
|
|
336
|
+
});
|
|
337
|
+
if (!resp.ok) {
|
|
338
|
+
let msg = `Failed to resume workflow: ${resp.status}`;
|
|
339
|
+
try { const err = await resp.json(); msg = err.error || msg; } catch { /* non-JSON response */ }
|
|
340
|
+
throw new Error(msg);
|
|
341
|
+
}
|
|
342
|
+
return resp.json();
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
forceNextNode = async (featureId: string, nodeId: string) => {
|
|
346
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow/force-next`, {
|
|
230
347
|
method: 'POST',
|
|
231
348
|
headers: { 'Content-Type': 'application/json' },
|
|
349
|
+
body: JSON.stringify({ nodeId }),
|
|
232
350
|
});
|
|
233
351
|
if (!resp.ok) {
|
|
234
|
-
let msg = `Failed to
|
|
352
|
+
let msg = `Failed to force next: ${resp.status}`;
|
|
235
353
|
try { const err = await resp.json(); msg = err.error || msg; } catch { /* non-JSON response */ }
|
|
236
354
|
throw new Error(msg);
|
|
237
355
|
}
|
|
238
356
|
return resp.json();
|
|
239
357
|
};
|
|
240
358
|
|
|
241
|
-
|
|
242
|
-
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/
|
|
359
|
+
restartNode = async (featureId: string, nodeId: string) => {
|
|
360
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/kanban/${featureId}/workflow/restart-node`, {
|
|
243
361
|
method: 'POST',
|
|
244
362
|
headers: { 'Content-Type': 'application/json' },
|
|
363
|
+
body: JSON.stringify({ nodeId }),
|
|
245
364
|
});
|
|
246
365
|
if (!resp.ok) {
|
|
247
|
-
let msg = `Failed to
|
|
366
|
+
let msg = `Failed to restart node: ${resp.status}`;
|
|
248
367
|
try { const err = await resp.json(); msg = err.error || msg; } catch { /* non-JSON response */ }
|
|
249
368
|
throw new Error(msg);
|
|
250
369
|
}
|
|
@@ -366,11 +485,11 @@ export class ApiClient {
|
|
|
366
485
|
return resp.json();
|
|
367
486
|
};
|
|
368
487
|
|
|
369
|
-
createProject = async (name: string) => {
|
|
488
|
+
createProject = async (name: string, type?: string) => {
|
|
370
489
|
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects`, {
|
|
371
490
|
method: 'POST',
|
|
372
491
|
headers: { 'Content-Type': 'application/json' },
|
|
373
|
-
body: JSON.stringify({ name }),
|
|
492
|
+
body: JSON.stringify({ name, ...(type ? { type } : {}) }),
|
|
374
493
|
});
|
|
375
494
|
if (!resp.ok) {
|
|
376
495
|
const data = await resp.json();
|
|
@@ -489,6 +608,31 @@ export class ApiClient {
|
|
|
489
608
|
return resp.json();
|
|
490
609
|
};
|
|
491
610
|
|
|
611
|
+
generateSshKey = async (projectId: string) => {
|
|
612
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/git/ssh/generate`, {
|
|
613
|
+
method: 'POST',
|
|
614
|
+
headers: { 'Content-Type': 'application/json' },
|
|
615
|
+
});
|
|
616
|
+
if (!resp.ok) {
|
|
617
|
+
const data = await resp.json();
|
|
618
|
+
throw new Error(data.error || `Failed to generate SSH key: ${resp.status}`);
|
|
619
|
+
}
|
|
620
|
+
return resp.json();
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
connectSshRepo = async (projectId: string, repoUrl: string, baseBranch?: string) => {
|
|
624
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/git/ssh/connect`, {
|
|
625
|
+
method: 'POST',
|
|
626
|
+
headers: { 'Content-Type': 'application/json' },
|
|
627
|
+
body: JSON.stringify({ repoUrl, baseBranch }),
|
|
628
|
+
});
|
|
629
|
+
if (!resp.ok) {
|
|
630
|
+
const data = await resp.json();
|
|
631
|
+
throw new Error(data.error || `Failed to connect repo via SSH: ${resp.status}`);
|
|
632
|
+
}
|
|
633
|
+
return resp.json();
|
|
634
|
+
};
|
|
635
|
+
|
|
492
636
|
listTerminalSessions = async () => {
|
|
493
637
|
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/terminal/sessions`);
|
|
494
638
|
if (!resp.ok) throw new Error(`Failed to list terminal sessions: ${resp.status}`);
|
|
@@ -508,6 +652,23 @@ export class ApiClient {
|
|
|
508
652
|
return resp.json();
|
|
509
653
|
};
|
|
510
654
|
|
|
655
|
+
uploadTerminalImage = async (file: File): Promise<{ path: string }> => {
|
|
656
|
+
const buffer = await file.arrayBuffer();
|
|
657
|
+
const resp = await this.fetchWithRefresh(
|
|
658
|
+
`${this.baseUrl}/api/terminal/upload-image?filename=${encodeURIComponent(file.name)}`,
|
|
659
|
+
{
|
|
660
|
+
method: 'POST',
|
|
661
|
+
headers: { 'Content-Type': 'application/octet-stream' },
|
|
662
|
+
body: buffer,
|
|
663
|
+
},
|
|
664
|
+
);
|
|
665
|
+
if (!resp.ok) {
|
|
666
|
+
const data = await resp.json();
|
|
667
|
+
throw new Error(data.error || `Failed to upload image: ${resp.status}`);
|
|
668
|
+
}
|
|
669
|
+
return resp.json();
|
|
670
|
+
};
|
|
671
|
+
|
|
511
672
|
killTerminalSession = async (sessionId: string) => {
|
|
512
673
|
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/terminal/sessions/${sessionId}`, {
|
|
513
674
|
method: 'DELETE',
|
|
@@ -519,6 +680,285 @@ export class ApiClient {
|
|
|
519
680
|
return resp.json();
|
|
520
681
|
};
|
|
521
682
|
|
|
683
|
+
// --- Agent management ---
|
|
684
|
+
|
|
685
|
+
fetchAgents = async (scope: 'global' | 'project', projectId?: string) => {
|
|
686
|
+
const params = new URLSearchParams({ scope });
|
|
687
|
+
if (projectId) params.set('projectId', projectId);
|
|
688
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents?${params}`);
|
|
689
|
+
if (!resp.ok) throw new Error(`Failed to fetch agents: ${resp.status}`);
|
|
690
|
+
return resp.json();
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
fetchAgent = async (id: string) => {
|
|
694
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents/${id}`);
|
|
695
|
+
if (!resp.ok) throw new Error(`Failed to fetch agent: ${resp.status}`);
|
|
696
|
+
return resp.json();
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
createAgent = async (data: { name: string; promptTemplate: string; projectId?: string }) => {
|
|
700
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents`, {
|
|
701
|
+
method: 'POST',
|
|
702
|
+
headers: { 'Content-Type': 'application/json' },
|
|
703
|
+
body: JSON.stringify(data),
|
|
704
|
+
});
|
|
705
|
+
if (!resp.ok) {
|
|
706
|
+
const err = await resp.json();
|
|
707
|
+
throw new Error(err.error || `Failed to create agent: ${resp.status}`);
|
|
708
|
+
}
|
|
709
|
+
return resp.json();
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
updateAgent = async (id: string, data: { name?: string; promptTemplate?: string }) => {
|
|
713
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents/${id}`, {
|
|
714
|
+
method: 'PUT',
|
|
715
|
+
headers: { 'Content-Type': 'application/json' },
|
|
716
|
+
body: JSON.stringify(data),
|
|
717
|
+
});
|
|
718
|
+
if (!resp.ok) {
|
|
719
|
+
const err = await resp.json();
|
|
720
|
+
throw new Error(err.error || `Failed to update agent: ${resp.status}`);
|
|
721
|
+
}
|
|
722
|
+
return resp.json();
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
deleteAgent = async (id: string) => {
|
|
726
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents/${id}`, {
|
|
727
|
+
method: 'DELETE',
|
|
728
|
+
});
|
|
729
|
+
if (!resp.ok) {
|
|
730
|
+
const err = await resp.json();
|
|
731
|
+
throw new Error(err.error || `Failed to delete agent: ${resp.status}`);
|
|
732
|
+
}
|
|
733
|
+
return resp.json();
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
resetAgent = async (id: string) => {
|
|
737
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/agents/${id}/reset`, {
|
|
738
|
+
method: 'POST',
|
|
739
|
+
headers: { 'Content-Type': 'application/json' },
|
|
740
|
+
});
|
|
741
|
+
if (!resp.ok) {
|
|
742
|
+
const err = await resp.json();
|
|
743
|
+
throw new Error(err.error || `Failed to reset agent: ${resp.status}`);
|
|
744
|
+
}
|
|
745
|
+
return resp.json();
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// --- Workflow management ---
|
|
749
|
+
|
|
750
|
+
fetchWorkflows = async (projectId?: string) => {
|
|
751
|
+
const params = projectId ? `?projectId=${encodeURIComponent(projectId)}` : '';
|
|
752
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows${params}`);
|
|
753
|
+
if (!resp.ok) throw new Error(`Failed to fetch workflows: ${resp.status}`);
|
|
754
|
+
return resp.json();
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
fetchWorkflow = async (id: string) => {
|
|
758
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows/${id}`);
|
|
759
|
+
if (!resp.ok) throw new Error(`Failed to fetch workflow: ${resp.status}`);
|
|
760
|
+
return resp.json();
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
createWorkflow = async (data: { name: string; description?: string; projectId?: string; graphData: string }) => {
|
|
764
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows`, {
|
|
765
|
+
method: 'POST',
|
|
766
|
+
headers: { 'Content-Type': 'application/json' },
|
|
767
|
+
body: JSON.stringify(data),
|
|
768
|
+
});
|
|
769
|
+
if (!resp.ok) {
|
|
770
|
+
const err = await resp.json();
|
|
771
|
+
throw new Error(err.error || `Failed to create workflow: ${resp.status}`);
|
|
772
|
+
}
|
|
773
|
+
return resp.json();
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
updateWorkflow = async (id: string, data: { name?: string; description?: string; graphData?: string }) => {
|
|
777
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows/${id}`, {
|
|
778
|
+
method: 'PUT',
|
|
779
|
+
headers: { 'Content-Type': 'application/json' },
|
|
780
|
+
body: JSON.stringify(data),
|
|
781
|
+
});
|
|
782
|
+
if (!resp.ok) {
|
|
783
|
+
const err = await resp.json();
|
|
784
|
+
throw new Error(err.error || `Failed to update workflow: ${resp.status}`);
|
|
785
|
+
}
|
|
786
|
+
return resp.json();
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
deleteWorkflow = async (id: string) => {
|
|
790
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows/${id}`, {
|
|
791
|
+
method: 'DELETE',
|
|
792
|
+
});
|
|
793
|
+
if (!resp.ok) {
|
|
794
|
+
const err = await resp.json();
|
|
795
|
+
throw new Error(err.error || `Failed to delete workflow: ${resp.status}`);
|
|
796
|
+
}
|
|
797
|
+
return resp.json();
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
// --- Workflow group management ---
|
|
801
|
+
|
|
802
|
+
fetchWorkflowGroups = async (projectId?: string) => {
|
|
803
|
+
const params = projectId ? `?projectId=${encodeURIComponent(projectId)}` : '';
|
|
804
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflow-groups${params}`);
|
|
805
|
+
if (!resp.ok) throw new Error(`Failed to fetch workflow groups: ${resp.status}`);
|
|
806
|
+
return resp.json();
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
createWorkflowGroup = async (data: { name: string; projectId?: string; graphData: string }) => {
|
|
810
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflow-groups`, {
|
|
811
|
+
method: 'POST',
|
|
812
|
+
headers: { 'Content-Type': 'application/json' },
|
|
813
|
+
body: JSON.stringify(data),
|
|
814
|
+
});
|
|
815
|
+
if (!resp.ok) {
|
|
816
|
+
const err = await resp.json();
|
|
817
|
+
throw new Error(err.error || `Failed to create workflow group: ${resp.status}`);
|
|
818
|
+
}
|
|
819
|
+
return resp.json();
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
deleteWorkflowGroup = async (id: string) => {
|
|
823
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflow-groups/${id}`, {
|
|
824
|
+
method: 'DELETE',
|
|
825
|
+
});
|
|
826
|
+
if (!resp.ok) {
|
|
827
|
+
const err = await resp.json();
|
|
828
|
+
throw new Error(err.error || `Failed to delete workflow group: ${resp.status}`);
|
|
829
|
+
}
|
|
830
|
+
return resp.json();
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
setDefaultWorkflow = async (id: string) => {
|
|
834
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/workflows/${id}/set-default`, {
|
|
835
|
+
method: 'POST',
|
|
836
|
+
headers: { 'Content-Type': 'application/json' },
|
|
837
|
+
});
|
|
838
|
+
if (!resp.ok) {
|
|
839
|
+
const err = await resp.json();
|
|
840
|
+
throw new Error(err.error || `Failed to set default workflow: ${resp.status}`);
|
|
841
|
+
}
|
|
842
|
+
return resp.json();
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// --- File system ---
|
|
846
|
+
|
|
847
|
+
fetchFileTree = async (projectId: string) => {
|
|
848
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/files`);
|
|
849
|
+
if (!resp.ok) throw new Error(`Failed to fetch file tree: ${resp.status}`);
|
|
850
|
+
return resp.json();
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
fetchFileContent = async (projectId: string, path: string) => {
|
|
854
|
+
const resp = await this.fetchWithRefresh(
|
|
855
|
+
`${this.baseUrl}/api/projects/${projectId}/files/content?path=${encodeURIComponent(path)}`,
|
|
856
|
+
);
|
|
857
|
+
if (!resp.ok) throw new Error(`Failed to fetch file content: ${resp.status}`);
|
|
858
|
+
return resp.json();
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
saveFileContent = async (projectId: string, path: string, content: string) => {
|
|
862
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/files/content`, {
|
|
863
|
+
method: 'PUT',
|
|
864
|
+
headers: { 'Content-Type': 'application/json' },
|
|
865
|
+
body: JSON.stringify({ path, content }),
|
|
866
|
+
});
|
|
867
|
+
if (!resp.ok) throw new Error(`Failed to save file: ${resp.status}`);
|
|
868
|
+
return resp.json();
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
createFile = async (projectId: string, path: string, type: 'file' | 'directory') => {
|
|
872
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/files`, {
|
|
873
|
+
method: 'POST',
|
|
874
|
+
headers: { 'Content-Type': 'application/json' },
|
|
875
|
+
body: JSON.stringify({ path, type }),
|
|
876
|
+
});
|
|
877
|
+
if (!resp.ok) {
|
|
878
|
+
const data = await resp.json();
|
|
879
|
+
throw new Error(data.error || `Failed to create ${type}: ${resp.status}`);
|
|
880
|
+
}
|
|
881
|
+
return resp.json();
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
deleteFile = async (projectId: string, path: string) => {
|
|
885
|
+
const resp = await this.fetchWithRefresh(
|
|
886
|
+
`${this.baseUrl}/api/projects/${projectId}/files?path=${encodeURIComponent(path)}`,
|
|
887
|
+
{ method: 'DELETE' },
|
|
888
|
+
);
|
|
889
|
+
if (!resp.ok) {
|
|
890
|
+
const data = await resp.json();
|
|
891
|
+
throw new Error(data.error || `Failed to delete file: ${resp.status}`);
|
|
892
|
+
}
|
|
893
|
+
return resp.json();
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
renameFile = async (projectId: string, oldPath: string, newPath: string) => {
|
|
897
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/projects/${projectId}/files`, {
|
|
898
|
+
method: 'PATCH',
|
|
899
|
+
headers: { 'Content-Type': 'application/json' },
|
|
900
|
+
body: JSON.stringify({ oldPath, newPath }),
|
|
901
|
+
});
|
|
902
|
+
if (!resp.ok) {
|
|
903
|
+
const data = await resp.json();
|
|
904
|
+
throw new Error(data.error || `Failed to rename file: ${resp.status}`);
|
|
905
|
+
}
|
|
906
|
+
return resp.json();
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
// --- Video / Remotion ---
|
|
910
|
+
|
|
911
|
+
fetchVideoCompositions = async (): Promise<{ compositions: VideoCompositionMeta[] }> => {
|
|
912
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/compositions`);
|
|
913
|
+
if (!resp.ok) throw new Error(`Failed to fetch video compositions: ${resp.status}`);
|
|
914
|
+
return resp.json();
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
fetchVideoBundleStatus = async (): Promise<VideoBundleStatus> => {
|
|
918
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/bundle/status`);
|
|
919
|
+
if (!resp.ok) throw new Error(`Failed to fetch bundle status: ${resp.status}`);
|
|
920
|
+
return resp.json();
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
rebuildVideoBundle = async (): Promise<VideoBundleStatus> => {
|
|
924
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/bundle/rebuild`, {
|
|
925
|
+
method: 'POST',
|
|
926
|
+
headers: { 'Content-Type': 'application/json' },
|
|
927
|
+
});
|
|
928
|
+
if (!resp.ok) {
|
|
929
|
+
let msg = `Failed to rebuild bundle: ${resp.status}`;
|
|
930
|
+
try { const err = await resp.json(); msg = err.error || msg; } catch { /* non-JSON */ }
|
|
931
|
+
throw new Error(msg);
|
|
932
|
+
}
|
|
933
|
+
return resp.json();
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
fetchVideoRenders = async (projectId: string): Promise<{ renders: VideoRenderStatus[] }> => {
|
|
937
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/renders?projectId=${encodeURIComponent(projectId)}`);
|
|
938
|
+
if (!resp.ok) throw new Error(`Failed to fetch video renders: ${resp.status}`);
|
|
939
|
+
return resp.json();
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
fetchVideoRenderStatus = async (renderId: string): Promise<VideoRenderStatus> => {
|
|
943
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/render/${encodeURIComponent(renderId)}`);
|
|
944
|
+
if (!resp.ok) throw new Error(`Failed to fetch render status: ${resp.status}`);
|
|
945
|
+
return resp.json();
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
deleteVideoRender = async (renderId: string): Promise<void> => {
|
|
949
|
+
const resp = await this.fetchWithRefresh(`${this.baseUrl}/api/video/render/${encodeURIComponent(renderId)}`, {
|
|
950
|
+
method: 'DELETE',
|
|
951
|
+
});
|
|
952
|
+
if (!resp.ok) {
|
|
953
|
+
const data = await resp.json();
|
|
954
|
+
throw new Error(data.error || `Failed to delete render: ${resp.status}`);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
getVideoFileUrl = (renderId: string): string => {
|
|
959
|
+
return `${this.baseUrl}/api/video/file/${encodeURIComponent(renderId)}`;
|
|
960
|
+
};
|
|
961
|
+
|
|
522
962
|
acceptInvitation = async (token: string, email: string, password: string) => {
|
|
523
963
|
const resp = await fetch(`${this.baseUrl}/api/auth/accept-invitation`, {
|
|
524
964
|
method: 'POST',
|