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.
- package/package.json +5 -5
- package/src/app.ts +4 -2
- package/src/assets/starter-packs/customer-support-excellence.zip +0 -0
- package/src/assets/starter-packs/devrel-growth.zip +0 -0
- package/src/assets/starter-packs/product-delivery-trio.zip +0 -0
- package/src/assets/starter-packs/revenue-gtm-b2b.zip +0 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/.bopo.yaml +129 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/COMPANY.md +7 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/README.md +3 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/agents/founder-ceo/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/agents/support-lead/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/agents/support-specialist/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/projects/knowledge-base/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/projects/quality/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/projects/queue/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/skills/kb-article-skeleton/SKILL.md +17 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/skills/ticket-response-playbook/SKILL.md +15 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/tasks/daily-queue-standup/TASK.md +11 -0
- package/src/assets/starter-packs/sources/customer-support-excellence/tasks/kb-gap-sweep/TASK.md +11 -0
- package/src/assets/starter-packs/sources/devrel-growth/.bopo.yaml +128 -0
- package/src/assets/starter-packs/sources/devrel-growth/COMPANY.md +7 -0
- package/src/assets/starter-packs/sources/devrel-growth/README.md +3 -0
- package/src/assets/starter-packs/sources/devrel-growth/agents/content-producer/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/devrel-growth/agents/devrel-lead/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/devrel-growth/agents/founder-ceo/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/devrel-growth/projects/community/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/devrel-growth/projects/docs-education/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/devrel-growth/projects/partners/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/devrel-growth/skills/changelog-to-post/SKILL.md +14 -0
- package/src/assets/starter-packs/sources/devrel-growth/skills/tutorial-outline/SKILL.md +15 -0
- package/src/assets/starter-packs/sources/devrel-growth/tasks/community-health-review/TASK.md +11 -0
- package/src/assets/starter-packs/sources/devrel-growth/tasks/weekly-content-plan/TASK.md +11 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/.bopo.yaml +138 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/COMPANY.md +7 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/README.md +9 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/agents/engineer-ic/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/agents/founder-ceo/HEARTBEAT.md +6 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/agents/product-lead/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/projects/delivery/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/projects/quality/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/projects/strategy/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/skills/issue-triage/SKILL.md +21 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/skills/rca-template/SKILL.md +16 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/tasks/release-hygiene/TASK.md +11 -0
- package/src/assets/starter-packs/sources/product-delivery-trio/tasks/weekly-leadership-sync/TASK.md +11 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/.bopo.yaml +132 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/COMPANY.md +7 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/README.md +3 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/founder-ceo/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/gtm-lead/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/agents/pipeline-owner/HEARTBEAT.md +5 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/customer-success/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/deals/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/projects/pipeline/PROJECT.md +7 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/skills/discovery-call-brief/SKILL.md +14 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/skills/icp-scoring/SKILL.md +20 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/tasks/pipeline-hygiene/TASK.md +11 -0
- package/src/assets/starter-packs/sources/revenue-gtm-b2b/tasks/weekly-revenue-review/TASK.md +11 -0
- package/src/lib/agent-issue-permissions.ts +56 -0
- package/src/lib/builtin-bopo-skills/bopodev-control-plane.md +7 -0
- package/src/lib/instance-paths.ts +5 -0
- package/src/realtime/office-space.ts +7 -0
- package/src/routes/agents.ts +23 -1
- package/src/routes/assistant.ts +40 -1
- package/src/routes/companies.ts +227 -15
- package/src/routes/issues.ts +82 -3
- package/src/routes/observability.ts +222 -0
- package/src/routes/plugins.ts +393 -103
- package/src/routes/{loops.ts → routines.ts} +72 -76
- package/src/scripts/onboard-seed.ts +2 -0
- package/src/server.ts +3 -1
- package/src/services/company-assistant-context-snapshot.ts +4 -2
- package/src/services/company-assistant-service.ts +17 -15
- package/src/services/company-file-archive-service.ts +81 -6
- package/src/services/company-file-import-service.ts +221 -31
- package/src/services/company-knowledge-file-service.ts +361 -0
- package/src/services/company-skill-file-service.ts +151 -2
- package/src/services/governance-service.ts +58 -3
- package/src/services/heartbeat-service/heartbeat-run.ts +7 -0
- package/src/services/plugin-artifact-installer.ts +115 -0
- package/src/services/plugin-artifact-store.ts +28 -0
- package/src/services/plugin-capability-policy.ts +31 -0
- package/src/services/plugin-jobs-service.ts +74 -0
- package/src/services/plugin-manifest-loader.ts +78 -3
- package/src/services/plugin-rpc.ts +102 -0
- package/src/services/plugin-runtime.ts +240 -209
- package/src/services/plugin-worker-host.ts +167 -0
- package/src/services/starter-pack-registry.ts +68 -0
- package/src/services/template-apply-service.ts +3 -1
- package/src/services/template-catalog.ts +29 -0
- package/src/services/work-loop-service/work-loop-service.ts +18 -18
- package/src/shutdown/graceful-shutdown.ts +3 -1
- package/src/validation/issue-routes.ts +19 -2
- package/src/worker/scheduler.ts +21 -1
- 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;
|