bopodev-api 0.1.34 → 0.1.36

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.
Files changed (95) hide show
  1. package/package.json +5 -5
  2. package/src/app.ts +4 -2
  3. package/src/assets/starter-packs/customer-support-excellence.zip +0 -0
  4. package/src/assets/starter-packs/devrel-growth.zip +0 -0
  5. package/src/assets/starter-packs/product-delivery-trio.zip +0 -0
  6. package/src/assets/starter-packs/revenue-gtm-b2b.zip +0 -0
  7. package/src/assets/starter-packs/sources/customer-support-excellence/.bopo.yaml +129 -0
  8. package/src/assets/starter-packs/sources/customer-support-excellence/COMPANY.md +7 -0
  9. package/src/assets/starter-packs/sources/customer-support-excellence/README.md +3 -0
  10. package/src/assets/starter-packs/sources/customer-support-excellence/agents/founder-ceo/HEARTBEAT.md +5 -0
  11. package/src/assets/starter-packs/sources/customer-support-excellence/agents/support-lead/HEARTBEAT.md +5 -0
  12. package/src/assets/starter-packs/sources/customer-support-excellence/agents/support-specialist/HEARTBEAT.md +5 -0
  13. package/src/assets/starter-packs/sources/customer-support-excellence/projects/knowledge-base/PROJECT.md +7 -0
  14. package/src/assets/starter-packs/sources/customer-support-excellence/projects/quality/PROJECT.md +7 -0
  15. package/src/assets/starter-packs/sources/customer-support-excellence/projects/queue/PROJECT.md +7 -0
  16. package/src/assets/starter-packs/sources/customer-support-excellence/skills/kb-article-skeleton/SKILL.md +17 -0
  17. package/src/assets/starter-packs/sources/customer-support-excellence/skills/ticket-response-playbook/SKILL.md +15 -0
  18. package/src/assets/starter-packs/sources/customer-support-excellence/tasks/daily-queue-standup/TASK.md +11 -0
  19. package/src/assets/starter-packs/sources/customer-support-excellence/tasks/kb-gap-sweep/TASK.md +11 -0
  20. package/src/assets/starter-packs/sources/devrel-growth/.bopo.yaml +128 -0
  21. package/src/assets/starter-packs/sources/devrel-growth/COMPANY.md +7 -0
  22. package/src/assets/starter-packs/sources/devrel-growth/README.md +3 -0
  23. package/src/assets/starter-packs/sources/devrel-growth/agents/content-producer/HEARTBEAT.md +5 -0
  24. package/src/assets/starter-packs/sources/devrel-growth/agents/devrel-lead/HEARTBEAT.md +5 -0
  25. package/src/assets/starter-packs/sources/devrel-growth/agents/founder-ceo/HEARTBEAT.md +5 -0
  26. package/src/assets/starter-packs/sources/devrel-growth/projects/community/PROJECT.md +7 -0
  27. package/src/assets/starter-packs/sources/devrel-growth/projects/docs-education/PROJECT.md +7 -0
  28. package/src/assets/starter-packs/sources/devrel-growth/projects/partners/PROJECT.md +7 -0
  29. package/src/assets/starter-packs/sources/devrel-growth/skills/changelog-to-post/SKILL.md +14 -0
  30. package/src/assets/starter-packs/sources/devrel-growth/skills/tutorial-outline/SKILL.md +15 -0
  31. package/src/assets/starter-packs/sources/devrel-growth/tasks/community-health-review/TASK.md +11 -0
  32. package/src/assets/starter-packs/sources/devrel-growth/tasks/weekly-content-plan/TASK.md +11 -0
  33. package/src/assets/starter-packs/sources/product-delivery-trio/.bopo.yaml +138 -0
  34. package/src/assets/starter-packs/sources/product-delivery-trio/COMPANY.md +7 -0
  35. package/src/assets/starter-packs/sources/product-delivery-trio/README.md +9 -0
  36. package/src/assets/starter-packs/sources/product-delivery-trio/agents/engineer-ic/HEARTBEAT.md +5 -0
  37. package/src/assets/starter-packs/sources/product-delivery-trio/agents/founder-ceo/HEARTBEAT.md +6 -0
  38. package/src/assets/starter-packs/sources/product-delivery-trio/agents/product-lead/HEARTBEAT.md +5 -0
  39. package/src/assets/starter-packs/sources/product-delivery-trio/projects/delivery/PROJECT.md +7 -0
  40. package/src/assets/starter-packs/sources/product-delivery-trio/projects/quality/PROJECT.md +7 -0
  41. package/src/assets/starter-packs/sources/product-delivery-trio/projects/strategy/PROJECT.md +7 -0
  42. package/src/assets/starter-packs/sources/product-delivery-trio/skills/issue-triage/SKILL.md +21 -0
  43. package/src/assets/starter-packs/sources/product-delivery-trio/skills/rca-template/SKILL.md +16 -0
  44. package/src/assets/starter-packs/sources/product-delivery-trio/tasks/release-hygiene/TASK.md +11 -0
  45. package/src/assets/starter-packs/sources/product-delivery-trio/tasks/weekly-leadership-sync/TASK.md +11 -0
  46. package/src/assets/starter-packs/sources/revenue-gtm-b2b/.bopo.yaml +132 -0
  47. package/src/assets/starter-packs/sources/revenue-gtm-b2b/COMPANY.md +7 -0
  48. package/src/assets/starter-packs/sources/revenue-gtm-b2b/README.md +3 -0
  49. package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/founder-ceo/HEARTBEAT.md +5 -0
  50. package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/gtm-lead/HEARTBEAT.md +5 -0
  51. package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/pipeline-owner/HEARTBEAT.md +5 -0
  52. package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/customer-success/PROJECT.md +7 -0
  53. package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/deals/PROJECT.md +7 -0
  54. package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/pipeline/PROJECT.md +7 -0
  55. package/src/assets/starter-packs/sources/revenue-gtm-b2b/skills/discovery-call-brief/SKILL.md +14 -0
  56. package/src/assets/starter-packs/sources/revenue-gtm-b2b/skills/icp-scoring/SKILL.md +20 -0
  57. package/src/assets/starter-packs/sources/revenue-gtm-b2b/tasks/pipeline-hygiene/TASK.md +11 -0
  58. package/src/assets/starter-packs/sources/revenue-gtm-b2b/tasks/weekly-revenue-review/TASK.md +11 -0
  59. package/src/lib/agent-issue-permissions.ts +56 -0
  60. package/src/lib/builtin-bopo-skills/bopodev-control-plane.md +7 -0
  61. package/src/lib/instance-paths.ts +5 -0
  62. package/src/realtime/office-space.ts +7 -0
  63. package/src/routes/agents.ts +23 -1
  64. package/src/routes/assistant.ts +40 -1
  65. package/src/routes/companies.ts +227 -15
  66. package/src/routes/issues.ts +82 -3
  67. package/src/routes/observability.ts +222 -0
  68. package/src/routes/plugins.ts +393 -103
  69. package/src/routes/{loops.ts → routines.ts} +72 -76
  70. package/src/scripts/onboard-seed.ts +2 -0
  71. package/src/server.ts +3 -1
  72. package/src/services/company-assistant-context-snapshot.ts +4 -2
  73. package/src/services/company-assistant-service.ts +17 -15
  74. package/src/services/company-file-archive-service.ts +81 -6
  75. package/src/services/company-file-import-service.ts +221 -31
  76. package/src/services/company-knowledge-file-service.ts +361 -0
  77. package/src/services/company-skill-file-service.ts +151 -2
  78. package/src/services/governance-service.ts +58 -3
  79. package/src/services/heartbeat-service/heartbeat-run.ts +7 -0
  80. package/src/services/plugin-artifact-installer.ts +115 -0
  81. package/src/services/plugin-artifact-store.ts +28 -0
  82. package/src/services/plugin-capability-policy.ts +31 -0
  83. package/src/services/plugin-jobs-service.ts +74 -0
  84. package/src/services/plugin-manifest-loader.ts +78 -3
  85. package/src/services/plugin-rpc.ts +102 -0
  86. package/src/services/plugin-runtime.ts +240 -209
  87. package/src/services/plugin-worker-host.ts +167 -0
  88. package/src/services/starter-pack-registry.ts +68 -0
  89. package/src/services/template-apply-service.ts +3 -1
  90. package/src/services/template-catalog.ts +29 -0
  91. package/src/services/work-loop-service/work-loop-service.ts +18 -18
  92. package/src/shutdown/graceful-shutdown.ts +3 -1
  93. package/src/validation/issue-routes.ts +19 -2
  94. package/src/worker/scheduler.ts +21 -1
  95. package/src/services/company-export-service.ts +0 -63
@@ -25,14 +25,27 @@ import {
25
25
  writeAgentOperatingFile
26
26
  } from "../services/agent-operating-file-service";
27
27
  import { BUILTIN_BOPO_SKILLS } from "../lib/builtin-bopo-skills";
28
+ import {
29
+ buildKnowledgeTreeFromPaths,
30
+ createKnowledgeFile,
31
+ deleteKnowledgeFile,
32
+ listKnowledgeFiles,
33
+ readKnowledgeFile,
34
+ renameKnowledgeFile,
35
+ renameKnowledgeFolderPrefix,
36
+ writeKnowledgeFile
37
+ } from "../services/company-knowledge-file-service";
28
38
  import {
29
39
  createCompanySkillPackage,
40
+ deleteCompanySkillFile,
30
41
  deleteCompanySkillPackage,
31
42
  linkCompanySkillFromUrl,
32
43
  listCompanySkillFiles,
33
44
  listCompanySkillPackages,
34
45
  refreshCompanySkillFromUrl,
35
46
  readCompanySkillFile,
47
+ renameCompanySkillFile,
48
+ setCompanySkillSidebarTitle,
36
49
  writeCompanySkillFile
37
50
  } from "../services/company-skill-file-service";
38
51
  import {
@@ -550,6 +563,7 @@ export function createObservabilityRouter(ctx: AppContext) {
550
563
  linkedUrl: pack.linkedUrl,
551
564
  linkLastFetchedAt: pack.linkLastFetchedAt,
552
565
  hasLocalSkillMd,
566
+ sidebarTitle: pack.sidebarTitle,
553
567
  files: relativePaths.map((relativePath) => ({ relativePath }))
554
568
  };
555
569
  })
@@ -602,6 +616,77 @@ export function createObservabilityRouter(ctx: AppContext) {
602
616
  }
603
617
  });
604
618
 
619
+ router.patch("/company-skills/file", async (req, res) => {
620
+ if (!enforcePermission(req, res, "agents:write")) {
621
+ return;
622
+ }
623
+ const companyId = req.companyId!;
624
+ const skillId = typeof req.query.skillId === "string" ? req.query.skillId.trim() : "";
625
+ if (!skillId) {
626
+ return sendError(res, "Query parameter 'skillId' is required.", 422);
627
+ }
628
+ const body = req.body as { from?: unknown; to?: unknown };
629
+ if (typeof body?.from !== "string" || !body.from.trim()) {
630
+ return sendError(res, "Expected JSON body with string 'from' (current path).", 422);
631
+ }
632
+ if (typeof body?.to !== "string" || !body.to.trim()) {
633
+ return sendError(res, "Expected JSON body with string 'to' (new path).", 422);
634
+ }
635
+ try {
636
+ const result = await renameCompanySkillFile({
637
+ companyId,
638
+ skillId,
639
+ fromRelativePath: body.from.trim(),
640
+ toRelativePath: body.to.trim()
641
+ });
642
+ return sendOk(res, result);
643
+ } catch (error) {
644
+ return sendError(res, String(error), 422);
645
+ }
646
+ });
647
+
648
+ router.patch("/company-skills/sidebar-title", async (req, res) => {
649
+ if (!enforcePermission(req, res, "agents:write")) {
650
+ return;
651
+ }
652
+ const companyId = req.companyId!;
653
+ const body = req.body as { skillId?: unknown; title?: unknown };
654
+ if (typeof body?.skillId !== "string" || !body.skillId.trim()) {
655
+ return sendError(res, "Expected JSON body with string 'skillId'.", 422);
656
+ }
657
+ if (typeof body?.title !== "string") {
658
+ return sendError(res, "Expected JSON body with string 'title' (empty string resets to skill id).", 422);
659
+ }
660
+ try {
661
+ const result = await setCompanySkillSidebarTitle({
662
+ companyId,
663
+ skillId: body.skillId.trim(),
664
+ title: body.title
665
+ });
666
+ return sendOk(res, result);
667
+ } catch (error) {
668
+ return sendError(res, String(error), 422);
669
+ }
670
+ });
671
+
672
+ router.delete("/company-skills/file", async (req, res) => {
673
+ if (!enforcePermission(req, res, "agents:write")) {
674
+ return;
675
+ }
676
+ const companyId = req.companyId!;
677
+ const skillId = typeof req.query.skillId === "string" ? req.query.skillId.trim() : "";
678
+ const relativePath = typeof req.query.path === "string" ? req.query.path.trim() : "";
679
+ if (!skillId || !relativePath) {
680
+ return sendError(res, "Query parameters 'skillId' and 'path' are required.", 422);
681
+ }
682
+ try {
683
+ const result = await deleteCompanySkillFile({ companyId, skillId, relativePath });
684
+ return sendOk(res, result);
685
+ } catch (error) {
686
+ return sendError(res, String(error), 422);
687
+ }
688
+ });
689
+
605
690
  router.post("/company-skills/create", async (req, res) => {
606
691
  if (!enforcePermission(req, res, "agents:write")) {
607
692
  return;
@@ -679,6 +764,143 @@ export function createObservabilityRouter(ctx: AppContext) {
679
764
  }
680
765
  });
681
766
 
767
+ router.get("/company-knowledge", async (req, res) => {
768
+ const companyId = req.companyId!;
769
+ try {
770
+ const { files } = await listKnowledgeFiles({ companyId });
771
+ const tree = buildKnowledgeTreeFromPaths(files);
772
+ return sendOk(res, { items: files, tree });
773
+ } catch (error) {
774
+ return sendError(res, String(error), 422);
775
+ }
776
+ });
777
+
778
+ router.get("/company-knowledge/file", async (req, res) => {
779
+ const companyId = req.companyId!;
780
+ const relativePath = typeof req.query.path === "string" ? req.query.path.trim() : "";
781
+ if (!relativePath) {
782
+ return sendError(res, "Query parameter 'path' is required.", 422);
783
+ }
784
+ try {
785
+ const file = await readKnowledgeFile({ companyId, relativePath });
786
+ return sendOk(res, { content: file.content });
787
+ } catch (error) {
788
+ return sendError(res, String(error), 422);
789
+ }
790
+ });
791
+
792
+ router.put("/company-knowledge/file", async (req, res) => {
793
+ if (!enforcePermission(req, res, "agents:write")) {
794
+ return;
795
+ }
796
+ const companyId = req.companyId!;
797
+ const relativePath = typeof req.query.path === "string" ? req.query.path.trim() : "";
798
+ if (!relativePath) {
799
+ return sendError(res, "Query parameter 'path' is required.", 422);
800
+ }
801
+ const body = req.body as { content?: unknown };
802
+ if (typeof body?.content !== "string") {
803
+ return sendError(res, "Expected JSON body with string 'content'.", 422);
804
+ }
805
+ try {
806
+ const result = await writeKnowledgeFile({
807
+ companyId,
808
+ relativePath,
809
+ content: body.content
810
+ });
811
+ return sendOk(res, result);
812
+ } catch (error) {
813
+ return sendError(res, String(error), 422);
814
+ }
815
+ });
816
+
817
+ router.post("/company-knowledge/file", async (req, res) => {
818
+ if (!enforcePermission(req, res, "agents:write")) {
819
+ return;
820
+ }
821
+ const companyId = req.companyId!;
822
+ const body = req.body as { path?: unknown; content?: unknown };
823
+ if (typeof body?.path !== "string" || !body.path.trim()) {
824
+ return sendError(res, "Expected JSON body with string 'path'.", 422);
825
+ }
826
+ const content = typeof body.content === "string" ? body.content : undefined;
827
+ try {
828
+ const result = await createKnowledgeFile({
829
+ companyId,
830
+ relativePath: body.path.trim(),
831
+ ...(content !== undefined ? { content } : {})
832
+ });
833
+ return sendOk(res, result);
834
+ } catch (error) {
835
+ return sendError(res, String(error), 422);
836
+ }
837
+ });
838
+
839
+ router.patch("/company-knowledge/file", async (req, res) => {
840
+ if (!enforcePermission(req, res, "agents:write")) {
841
+ return;
842
+ }
843
+ const companyId = req.companyId!;
844
+ const body = req.body as { from?: unknown; to?: unknown };
845
+ if (typeof body?.from !== "string" || !body.from.trim()) {
846
+ return sendError(res, "Expected JSON body with string 'from' (current path).", 422);
847
+ }
848
+ if (typeof body?.to !== "string" || !body.to.trim()) {
849
+ return sendError(res, "Expected JSON body with string 'to' (new path).", 422);
850
+ }
851
+ try {
852
+ const result = await renameKnowledgeFile({
853
+ companyId,
854
+ fromRelativePath: body.from.trim(),
855
+ toRelativePath: body.to.trim()
856
+ });
857
+ return sendOk(res, result);
858
+ } catch (error) {
859
+ return sendError(res, String(error), 422);
860
+ }
861
+ });
862
+
863
+ router.patch("/company-knowledge/folder", async (req, res) => {
864
+ if (!enforcePermission(req, res, "agents:write")) {
865
+ return;
866
+ }
867
+ const companyId = req.companyId!;
868
+ const body = req.body as { from?: unknown; to?: unknown };
869
+ if (typeof body?.from !== "string" || !body.from.trim()) {
870
+ return sendError(res, "Expected JSON body with string 'from' (current folder prefix).", 422);
871
+ }
872
+ if (typeof body?.to !== "string" || !body.to.trim()) {
873
+ return sendError(res, "Expected JSON body with string 'to' (new folder prefix).", 422);
874
+ }
875
+ try {
876
+ const result = await renameKnowledgeFolderPrefix({
877
+ companyId,
878
+ fromPrefix: body.from.trim(),
879
+ toPrefix: body.to.trim()
880
+ });
881
+ return sendOk(res, result);
882
+ } catch (error) {
883
+ return sendError(res, String(error), 422);
884
+ }
885
+ });
886
+
887
+ router.delete("/company-knowledge/file", async (req, res) => {
888
+ if (!enforcePermission(req, res, "agents:write")) {
889
+ return;
890
+ }
891
+ const companyId = req.companyId!;
892
+ const relativePath = typeof req.query.path === "string" ? req.query.path.trim() : "";
893
+ if (!relativePath) {
894
+ return sendError(res, "Query parameter 'path' is required.", 422);
895
+ }
896
+ try {
897
+ const result = await deleteKnowledgeFile({ companyId, relativePath });
898
+ return sendOk(res, result);
899
+ } catch (error) {
900
+ return sendError(res, String(error), 422);
901
+ }
902
+ });
903
+
682
904
  router.get("/memory/:agentId/context-preview", async (req, res) => {
683
905
  const companyId = req.companyId!;
684
906
  const agentId = req.params.agentId;