claudehq 1.0.2 → 1.0.3

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/lib/routes/api.js CHANGED
@@ -52,6 +52,10 @@ function createRoutes(deps) {
52
52
  updatePlan,
53
53
  loadConversation,
54
54
 
55
+ // Orchestration
56
+ orchestrationData,
57
+ orchestrationExecutor,
58
+
55
59
  // Utils
56
60
  sendToTmux
57
61
  } = deps;
@@ -604,6 +608,401 @@ function createRoutes(deps) {
604
608
  res.end(JSON.stringify({ error: e.message }));
605
609
  }
606
610
  });
611
+ },
612
+
613
+ // =========================================================================
614
+ // Orchestration
615
+ // =========================================================================
616
+ handleGetOrchestrations(req, res) {
617
+ if (!orchestrationData) {
618
+ res.writeHead(501, { 'Content-Type': 'application/json' });
619
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
620
+ return;
621
+ }
622
+ const orchestrations = orchestrationData.listOrchestrations();
623
+ res.writeHead(200, { 'Content-Type': 'application/json' });
624
+ res.end(JSON.stringify({ ok: true, orchestrations }));
625
+ },
626
+
627
+ handleCreateOrchestration(req, res) {
628
+ if (!orchestrationData) {
629
+ res.writeHead(501, { 'Content-Type': 'application/json' });
630
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
631
+ return;
632
+ }
633
+ let body = '';
634
+ req.on('data', chunk => body += chunk);
635
+ req.on('end', () => {
636
+ try {
637
+ const config = JSON.parse(body);
638
+ const result = orchestrationData.createOrchestration(config);
639
+ if (result.error) {
640
+ res.writeHead(400, { 'Content-Type': 'application/json' });
641
+ res.end(JSON.stringify({ ok: false, error: result.error }));
642
+ } else {
643
+ res.writeHead(201, { 'Content-Type': 'application/json' });
644
+ res.end(JSON.stringify({ ok: true, orchestration: result.orchestration }));
645
+ }
646
+ } catch (e) {
647
+ res.writeHead(400, { 'Content-Type': 'application/json' });
648
+ res.end(JSON.stringify({ ok: false, error: e.message }));
649
+ }
650
+ });
651
+ },
652
+
653
+ handleGetOrchestration(req, res, orchestrationId) {
654
+ if (!orchestrationData) {
655
+ res.writeHead(501, { 'Content-Type': 'application/json' });
656
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
657
+ return;
658
+ }
659
+ const orchestration = orchestrationData.getOrchestration(orchestrationId);
660
+ if (!orchestration) {
661
+ res.writeHead(404, { 'Content-Type': 'application/json' });
662
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not found' }));
663
+ return;
664
+ }
665
+ const stats = orchestrationData.getOrchestrationStats(orchestrationId);
666
+ res.writeHead(200, { 'Content-Type': 'application/json' });
667
+ res.end(JSON.stringify({ ok: true, orchestration, stats }));
668
+ },
669
+
670
+ handleUpdateOrchestration(req, res, orchestrationId) {
671
+ if (!orchestrationData) {
672
+ res.writeHead(501, { 'Content-Type': 'application/json' });
673
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
674
+ return;
675
+ }
676
+ let body = '';
677
+ req.on('data', chunk => body += chunk);
678
+ req.on('end', () => {
679
+ try {
680
+ const updates = JSON.parse(body);
681
+ const result = orchestrationData.updateOrchestration(orchestrationId, updates);
682
+ if (result.error) {
683
+ res.writeHead(400, { 'Content-Type': 'application/json' });
684
+ res.end(JSON.stringify({ ok: false, error: result.error }));
685
+ } else {
686
+ res.writeHead(200, { 'Content-Type': 'application/json' });
687
+ res.end(JSON.stringify({ ok: true, orchestration: result.orchestration }));
688
+ }
689
+ } catch (e) {
690
+ res.writeHead(400, { 'Content-Type': 'application/json' });
691
+ res.end(JSON.stringify({ ok: false, error: e.message }));
692
+ }
693
+ });
694
+ },
695
+
696
+ handleDeleteOrchestration(req, res, orchestrationId) {
697
+ if (!orchestrationData) {
698
+ res.writeHead(501, { 'Content-Type': 'application/json' });
699
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
700
+ return;
701
+ }
702
+ const result = orchestrationData.deleteOrchestration(orchestrationId);
703
+ if (result.error) {
704
+ res.writeHead(404, { 'Content-Type': 'application/json' });
705
+ res.end(JSON.stringify({ ok: false, error: result.error }));
706
+ } else {
707
+ res.writeHead(200, { 'Content-Type': 'application/json' });
708
+ res.end(JSON.stringify({ ok: true }));
709
+ }
710
+ },
711
+
712
+ handleStartOrchestration(req, res, orchestrationId) {
713
+ if (!orchestrationExecutor) {
714
+ res.writeHead(501, { 'Content-Type': 'application/json' });
715
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
716
+ return;
717
+ }
718
+ orchestrationExecutor.startOrchestration(orchestrationId).then((result) => {
719
+ if (result.error) {
720
+ res.writeHead(400, { 'Content-Type': 'application/json' });
721
+ res.end(JSON.stringify({ ok: false, error: result.error }));
722
+ } else {
723
+ res.writeHead(200, { 'Content-Type': 'application/json' });
724
+ res.end(JSON.stringify({ ok: true, ...result }));
725
+ }
726
+ }).catch((e) => {
727
+ res.writeHead(500, { 'Content-Type': 'application/json' });
728
+ res.end(JSON.stringify({ ok: false, error: e.message }));
729
+ });
730
+ },
731
+
732
+ handleStopOrchestration(req, res, orchestrationId) {
733
+ if (!orchestrationExecutor) {
734
+ res.writeHead(501, { 'Content-Type': 'application/json' });
735
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
736
+ return;
737
+ }
738
+ orchestrationExecutor.stopOrchestration(orchestrationId).then((result) => {
739
+ if (result.error) {
740
+ res.writeHead(400, { 'Content-Type': 'application/json' });
741
+ res.end(JSON.stringify({ ok: false, error: result.error }));
742
+ } else {
743
+ res.writeHead(200, { 'Content-Type': 'application/json' });
744
+ res.end(JSON.stringify({ ok: true, ...result }));
745
+ }
746
+ }).catch((e) => {
747
+ res.writeHead(500, { 'Content-Type': 'application/json' });
748
+ res.end(JSON.stringify({ ok: false, error: e.message }));
749
+ });
750
+ },
751
+
752
+ // Agent routes
753
+ handleAddAgent(req, res, orchestrationId) {
754
+ if (!orchestrationData) {
755
+ res.writeHead(501, { 'Content-Type': 'application/json' });
756
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
757
+ return;
758
+ }
759
+ let body = '';
760
+ req.on('data', chunk => body += chunk);
761
+ req.on('end', () => {
762
+ try {
763
+ const agentConfig = JSON.parse(body);
764
+ const result = orchestrationData.addAgent(orchestrationId, agentConfig);
765
+ if (result.error) {
766
+ res.writeHead(400, { 'Content-Type': 'application/json' });
767
+ res.end(JSON.stringify({ ok: false, error: result.error }));
768
+ } else {
769
+ res.writeHead(201, { 'Content-Type': 'application/json' });
770
+ res.end(JSON.stringify({ ok: true, agent: result.agent }));
771
+ }
772
+ } catch (e) {
773
+ res.writeHead(400, { 'Content-Type': 'application/json' });
774
+ res.end(JSON.stringify({ ok: false, error: e.message }));
775
+ }
776
+ });
777
+ },
778
+
779
+ handleUpdateAgent(req, res, orchestrationId, agentId) {
780
+ if (!orchestrationData) {
781
+ res.writeHead(501, { 'Content-Type': 'application/json' });
782
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
783
+ return;
784
+ }
785
+ let body = '';
786
+ req.on('data', chunk => body += chunk);
787
+ req.on('end', () => {
788
+ try {
789
+ const updates = JSON.parse(body);
790
+ const result = orchestrationData.updateAgent(orchestrationId, agentId, updates);
791
+ if (result.error) {
792
+ res.writeHead(400, { 'Content-Type': 'application/json' });
793
+ res.end(JSON.stringify({ ok: false, error: result.error }));
794
+ } else {
795
+ res.writeHead(200, { 'Content-Type': 'application/json' });
796
+ res.end(JSON.stringify({ ok: true, agent: result.agent }));
797
+ }
798
+ } catch (e) {
799
+ res.writeHead(400, { 'Content-Type': 'application/json' });
800
+ res.end(JSON.stringify({ ok: false, error: e.message }));
801
+ }
802
+ });
803
+ },
804
+
805
+ handleRemoveAgent(req, res, orchestrationId, agentId) {
806
+ if (!orchestrationData) {
807
+ res.writeHead(501, { 'Content-Type': 'application/json' });
808
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
809
+ return;
810
+ }
811
+ const result = orchestrationData.removeAgent(orchestrationId, agentId);
812
+ if (result.error) {
813
+ res.writeHead(400, { 'Content-Type': 'application/json' });
814
+ res.end(JSON.stringify({ ok: false, error: result.error }));
815
+ } else {
816
+ res.writeHead(200, { 'Content-Type': 'application/json' });
817
+ res.end(JSON.stringify({ ok: true }));
818
+ }
819
+ },
820
+
821
+ handleSpawnAgent(req, res, orchestrationId, agentId) {
822
+ if (!orchestrationExecutor) {
823
+ res.writeHead(501, { 'Content-Type': 'application/json' });
824
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
825
+ return;
826
+ }
827
+ orchestrationExecutor.spawnAgent(orchestrationId, agentId).then((result) => {
828
+ if (result.error) {
829
+ res.writeHead(400, { 'Content-Type': 'application/json' });
830
+ res.end(JSON.stringify({ ok: false, error: result.error }));
831
+ } else {
832
+ res.writeHead(200, { 'Content-Type': 'application/json' });
833
+ res.end(JSON.stringify({ ok: true, ...result }));
834
+ }
835
+ }).catch((e) => {
836
+ res.writeHead(500, { 'Content-Type': 'application/json' });
837
+ res.end(JSON.stringify({ ok: false, error: e.message }));
838
+ });
839
+ },
840
+
841
+ handleKillAgent(req, res, orchestrationId, agentId) {
842
+ if (!orchestrationExecutor) {
843
+ res.writeHead(501, { 'Content-Type': 'application/json' });
844
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
845
+ return;
846
+ }
847
+ orchestrationExecutor.killAgent(orchestrationId, agentId).then((result) => {
848
+ if (result.error) {
849
+ res.writeHead(400, { 'Content-Type': 'application/json' });
850
+ res.end(JSON.stringify({ ok: false, error: result.error }));
851
+ } else {
852
+ res.writeHead(200, { 'Content-Type': 'application/json' });
853
+ res.end(JSON.stringify({ ok: true }));
854
+ }
855
+ }).catch((e) => {
856
+ res.writeHead(500, { 'Content-Type': 'application/json' });
857
+ res.end(JSON.stringify({ ok: false, error: e.message }));
858
+ });
859
+ },
860
+
861
+ handleSendPromptToAgent(req, res, orchestrationId, agentId) {
862
+ if (!orchestrationExecutor) {
863
+ res.writeHead(501, { 'Content-Type': 'application/json' });
864
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
865
+ return;
866
+ }
867
+ let body = '';
868
+ req.on('data', chunk => body += chunk);
869
+ req.on('end', async () => {
870
+ try {
871
+ const { prompt } = JSON.parse(body);
872
+ if (!prompt) {
873
+ res.writeHead(400, { 'Content-Type': 'application/json' });
874
+ res.end(JSON.stringify({ ok: false, error: 'Prompt is required' }));
875
+ return;
876
+ }
877
+ const result = await orchestrationExecutor.sendPromptToAgent(orchestrationId, agentId, prompt);
878
+ if (result.error) {
879
+ res.writeHead(400, { 'Content-Type': 'application/json' });
880
+ res.end(JSON.stringify({ ok: false, error: result.error }));
881
+ } else {
882
+ res.writeHead(200, { 'Content-Type': 'application/json' });
883
+ res.end(JSON.stringify({ ok: true }));
884
+ }
885
+ } catch (e) {
886
+ res.writeHead(500, { 'Content-Type': 'application/json' });
887
+ res.end(JSON.stringify({ ok: false, error: e.message }));
888
+ }
889
+ });
890
+ },
891
+
892
+ handleGetAgentStatus(req, res, orchestrationId, agentId) {
893
+ if (!orchestrationExecutor) {
894
+ res.writeHead(501, { 'Content-Type': 'application/json' });
895
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration executor not available' }));
896
+ return;
897
+ }
898
+ orchestrationExecutor.getAgentTmuxStatus(agentId).then((status) => {
899
+ res.writeHead(200, { 'Content-Type': 'application/json' });
900
+ res.end(JSON.stringify({ ok: true, ...status }));
901
+ }).catch((e) => {
902
+ res.writeHead(500, { 'Content-Type': 'application/json' });
903
+ res.end(JSON.stringify({ ok: false, error: e.message }));
904
+ });
905
+ },
906
+
907
+ handleAddAgentDependency(req, res, orchestrationId, agentId) {
908
+ if (!orchestrationData) {
909
+ res.writeHead(501, { 'Content-Type': 'application/json' });
910
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
911
+ return;
912
+ }
913
+ let body = '';
914
+ req.on('data', chunk => body += chunk);
915
+ req.on('end', () => {
916
+ try {
917
+ const { dependsOnAgentId } = JSON.parse(body);
918
+ if (!dependsOnAgentId) {
919
+ res.writeHead(400, { 'Content-Type': 'application/json' });
920
+ res.end(JSON.stringify({ ok: false, error: 'dependsOnAgentId is required' }));
921
+ return;
922
+ }
923
+ const result = orchestrationData.addAgentDependency(orchestrationId, agentId, dependsOnAgentId);
924
+ if (result.error) {
925
+ res.writeHead(400, { 'Content-Type': 'application/json' });
926
+ res.end(JSON.stringify({ ok: false, error: result.error }));
927
+ } else {
928
+ res.writeHead(200, { 'Content-Type': 'application/json' });
929
+ res.end(JSON.stringify({ ok: true }));
930
+ }
931
+ } catch (e) {
932
+ res.writeHead(400, { 'Content-Type': 'application/json' });
933
+ res.end(JSON.stringify({ ok: false, error: e.message }));
934
+ }
935
+ });
936
+ },
937
+
938
+ handleRemoveAgentDependency(req, res, orchestrationId, agentId, dependsOnAgentId) {
939
+ if (!orchestrationData) {
940
+ res.writeHead(501, { 'Content-Type': 'application/json' });
941
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
942
+ return;
943
+ }
944
+ const result = orchestrationData.removeAgentDependency(orchestrationId, agentId, dependsOnAgentId);
945
+ if (result.error) {
946
+ res.writeHead(400, { 'Content-Type': 'application/json' });
947
+ res.end(JSON.stringify({ ok: false, error: result.error }));
948
+ } else {
949
+ res.writeHead(200, { 'Content-Type': 'application/json' });
950
+ res.end(JSON.stringify({ ok: true }));
951
+ }
952
+ },
953
+
954
+ // Template routes
955
+ handleGetTemplates(req, res) {
956
+ if (!orchestrationData) {
957
+ res.writeHead(501, { 'Content-Type': 'application/json' });
958
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
959
+ return;
960
+ }
961
+ const templates = orchestrationData.getTemplates();
962
+ res.writeHead(200, { 'Content-Type': 'application/json' });
963
+ res.end(JSON.stringify({ ok: true, templates }));
964
+ },
965
+
966
+ handleGetTemplate(req, res, templateId) {
967
+ if (!orchestrationData) {
968
+ res.writeHead(501, { 'Content-Type': 'application/json' });
969
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
970
+ return;
971
+ }
972
+ const template = orchestrationData.getTemplate(templateId);
973
+ if (!template) {
974
+ res.writeHead(404, { 'Content-Type': 'application/json' });
975
+ res.end(JSON.stringify({ ok: false, error: 'Template not found' }));
976
+ return;
977
+ }
978
+ res.writeHead(200, { 'Content-Type': 'application/json' });
979
+ res.end(JSON.stringify({ ok: true, template }));
980
+ },
981
+
982
+ handleCreateFromTemplate(req, res, templateId) {
983
+ if (!orchestrationData) {
984
+ res.writeHead(501, { 'Content-Type': 'application/json' });
985
+ res.end(JSON.stringify({ ok: false, error: 'Orchestration not available' }));
986
+ return;
987
+ }
988
+ let body = '';
989
+ req.on('data', chunk => body += chunk);
990
+ req.on('end', () => {
991
+ try {
992
+ const options = body ? JSON.parse(body) : {};
993
+ const result = orchestrationData.createFromTemplate(templateId, options);
994
+ if (result.error) {
995
+ res.writeHead(400, { 'Content-Type': 'application/json' });
996
+ res.end(JSON.stringify({ ok: false, error: result.error }));
997
+ } else {
998
+ res.writeHead(201, { 'Content-Type': 'application/json' });
999
+ res.end(JSON.stringify({ ok: true, orchestration: result.orchestration }));
1000
+ }
1001
+ } catch (e) {
1002
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1003
+ res.end(JSON.stringify({ ok: false, error: e.message }));
1004
+ }
1005
+ });
607
1006
  }
608
1007
  };
609
1008
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudehq",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Claude HQ - A real-time command center for Claude Code sessions",
5
5
  "main": "lib/index.js",
6
6
  "bin": {