@orthacms/copilot-server 0.0.0-reserve.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.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/index.d.ts +24 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +48 -0
  6. package/dist/lib/chat/application/appliers-registrar.d.ts +16 -0
  7. package/dist/lib/chat/application/appliers-registrar.d.ts.map +1 -0
  8. package/dist/lib/chat/application/appliers-registrar.js +50 -0
  9. package/dist/lib/chat/application/capability-profile.service.d.ts +43 -0
  10. package/dist/lib/chat/application/capability-profile.service.d.ts.map +1 -0
  11. package/dist/lib/chat/application/capability-profile.service.js +75 -0
  12. package/dist/lib/chat/application/content-type-summary.service.d.ts +32 -0
  13. package/dist/lib/chat/application/content-type-summary.service.d.ts.map +1 -0
  14. package/dist/lib/chat/application/content-type-summary.service.js +64 -0
  15. package/dist/lib/chat/application/decide-proposal.service.d.ts +80 -0
  16. package/dist/lib/chat/application/decide-proposal.service.d.ts.map +1 -0
  17. package/dist/lib/chat/application/decide-proposal.service.js +112 -0
  18. package/dist/lib/chat/application/dto/create-run.dto.d.ts +138 -0
  19. package/dist/lib/chat/application/dto/create-run.dto.d.ts.map +1 -0
  20. package/dist/lib/chat/application/dto/create-run.dto.js +253 -0
  21. package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts +20 -0
  22. package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts.map +1 -0
  23. package/dist/lib/chat/application/dto/decide-tool-permission.dto.js +44 -0
  24. package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts +18 -0
  25. package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts.map +1 -0
  26. package/dist/lib/chat/application/dto/extend-tool-permission.dto.js +33 -0
  27. package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts +18 -0
  28. package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts.map +1 -0
  29. package/dist/lib/chat/application/dto/list-conversations-query.dto.js +39 -0
  30. package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts +15 -0
  31. package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts.map +1 -0
  32. package/dist/lib/chat/application/dto/list-proposals-query.dto.js +41 -0
  33. package/dist/lib/chat/application/dto/update-conversation.dto.d.ts +68 -0
  34. package/dist/lib/chat/application/dto/update-conversation.dto.d.ts.map +1 -0
  35. package/dist/lib/chat/application/dto/update-conversation.dto.js +115 -0
  36. package/dist/lib/chat/application/proposal-applier.registry.d.ts +27 -0
  37. package/dist/lib/chat/application/proposal-applier.registry.d.ts.map +1 -0
  38. package/dist/lib/chat/application/proposal-applier.registry.js +62 -0
  39. package/dist/lib/chat/application/run-engine.service.d.ts +243 -0
  40. package/dist/lib/chat/application/run-engine.service.d.ts.map +1 -0
  41. package/dist/lib/chat/application/run-engine.service.js +1058 -0
  42. package/dist/lib/chat/application/summarize-tool-output.d.ts +15 -0
  43. package/dist/lib/chat/application/summarize-tool-output.d.ts.map +1 -0
  44. package/dist/lib/chat/application/summarize-tool-output.js +61 -0
  45. package/dist/lib/chat/application/system-prompt.d.ts +81 -0
  46. package/dist/lib/chat/application/system-prompt.d.ts.map +1 -0
  47. package/dist/lib/chat/application/system-prompt.js +477 -0
  48. package/dist/lib/chat/application/tool-permission.broker.d.ts +118 -0
  49. package/dist/lib/chat/application/tool-permission.broker.d.ts.map +1 -0
  50. package/dist/lib/chat/application/tool-permission.broker.js +221 -0
  51. package/dist/lib/chat/http/controllers/create-run.controller.d.ts +30 -0
  52. package/dist/lib/chat/http/controllers/create-run.controller.d.ts.map +1 -0
  53. package/dist/lib/chat/http/controllers/create-run.controller.js +159 -0
  54. package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts +22 -0
  55. package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts.map +1 -0
  56. package/dist/lib/chat/http/controllers/get-conversation.controller.js +50 -0
  57. package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts +20 -0
  58. package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts.map +1 -0
  59. package/dist/lib/chat/http/controllers/list-conversations.controller.js +47 -0
  60. package/dist/lib/chat/http/controllers/list-models.controller.d.ts +35 -0
  61. package/dist/lib/chat/http/controllers/list-models.controller.d.ts.map +1 -0
  62. package/dist/lib/chat/http/controllers/list-models.controller.js +48 -0
  63. package/dist/lib/chat/http/controllers/proposals.controller.d.ts +43 -0
  64. package/dist/lib/chat/http/controllers/proposals.controller.d.ts.map +1 -0
  65. package/dist/lib/chat/http/controllers/proposals.controller.js +98 -0
  66. package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts +57 -0
  67. package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts.map +1 -0
  68. package/dist/lib/chat/http/controllers/tool-permission.controller.js +116 -0
  69. package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts +37 -0
  70. package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts.map +1 -0
  71. package/dist/lib/chat/http/controllers/update-conversation.controller.js +108 -0
  72. package/dist/lib/chat/http/sse-stream.d.ts +41 -0
  73. package/dist/lib/chat/http/sse-stream.d.ts.map +1 -0
  74. package/dist/lib/chat/http/sse-stream.js +95 -0
  75. package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts +159 -0
  76. package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts.map +1 -0
  77. package/dist/lib/chat/infrastructure/persistence/conversation.repository.js +249 -0
  78. package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts +13 -0
  79. package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts.map +1 -0
  80. package/dist/lib/chat/infrastructure/persistence/derive-title.js +35 -0
  81. package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts +86 -0
  82. package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts.map +1 -0
  83. package/dist/lib/chat/infrastructure/persistence/proposal.repository.js +152 -0
  84. package/dist/lib/chat/infrastructure/schema/conversations.d.ts +189 -0
  85. package/dist/lib/chat/infrastructure/schema/conversations.d.ts.map +1 -0
  86. package/dist/lib/chat/infrastructure/schema/conversations.js +100 -0
  87. package/dist/lib/chat/infrastructure/schema/external-refs.d.ts +67 -0
  88. package/dist/lib/chat/infrastructure/schema/external-refs.d.ts.map +1 -0
  89. package/dist/lib/chat/infrastructure/schema/external-refs.js +28 -0
  90. package/dist/lib/chat/infrastructure/schema/index.d.ts +5 -0
  91. package/dist/lib/chat/infrastructure/schema/index.d.ts.map +1 -0
  92. package/dist/lib/chat/infrastructure/schema/index.js +12 -0
  93. package/dist/lib/chat/infrastructure/schema/messages.d.ts +264 -0
  94. package/dist/lib/chat/infrastructure/schema/messages.d.ts.map +1 -0
  95. package/dist/lib/chat/infrastructure/schema/messages.js +96 -0
  96. package/dist/lib/chat/infrastructure/schema/proposals.d.ts +328 -0
  97. package/dist/lib/chat/infrastructure/schema/proposals.d.ts.map +1 -0
  98. package/dist/lib/chat/infrastructure/schema/proposals.js +87 -0
  99. package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts +203 -0
  100. package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts.map +1 -0
  101. package/dist/lib/chat/infrastructure/schema/tool-calls.js +50 -0
  102. package/dist/lib/copilot.module.d.ts +30 -0
  103. package/dist/lib/copilot.module.d.ts.map +1 -0
  104. package/dist/lib/copilot.module.js +146 -0
  105. package/dist/lib/copilot.tokens.d.ts +34 -0
  106. package/dist/lib/copilot.tokens.d.ts.map +1 -0
  107. package/dist/lib/copilot.tokens.js +38 -0
  108. package/dist/lib/infrastructure/model-registry.d.ts +22 -0
  109. package/dist/lib/infrastructure/model-registry.d.ts.map +1 -0
  110. package/dist/lib/infrastructure/model-registry.js +54 -0
  111. package/dist/lib/skills/application/dto/create-skill.dto.d.ts +36 -0
  112. package/dist/lib/skills/application/dto/create-skill.dto.d.ts.map +1 -0
  113. package/dist/lib/skills/application/dto/create-skill.dto.js +106 -0
  114. package/dist/lib/skills/application/dto/update-skill.dto.d.ts +28 -0
  115. package/dist/lib/skills/application/dto/update-skill.dto.d.ts.map +1 -0
  116. package/dist/lib/skills/application/dto/update-skill.dto.js +96 -0
  117. package/dist/lib/skills/application/skill-catalog.service.d.ts +97 -0
  118. package/dist/lib/skills/application/skill-catalog.service.d.ts.map +1 -0
  119. package/dist/lib/skills/application/skill-catalog.service.js +157 -0
  120. package/dist/lib/skills/http/controllers/list-skills.controller.d.ts +19 -0
  121. package/dist/lib/skills/http/controllers/list-skills.controller.d.ts.map +1 -0
  122. package/dist/lib/skills/http/controllers/list-skills.controller.js +50 -0
  123. package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts +64 -0
  124. package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts.map +1 -0
  125. package/dist/lib/skills/http/controllers/manage-skills.controller.js +182 -0
  126. package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts +78 -0
  127. package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts.map +1 -0
  128. package/dist/lib/skills/infrastructure/persistence/skill.repository.js +116 -0
  129. package/dist/lib/skills/infrastructure/schema/index.d.ts +2 -0
  130. package/dist/lib/skills/infrastructure/schema/index.d.ts.map +1 -0
  131. package/dist/lib/skills/infrastructure/schema/index.js +6 -0
  132. package/dist/lib/skills/infrastructure/schema/skills.d.ts +212 -0
  133. package/dist/lib/skills/infrastructure/schema/skills.d.ts.map +1 -0
  134. package/dist/lib/skills/infrastructure/schema/skills.js +78 -0
  135. package/dist/lib/types/copilot-config.d.ts +55 -0
  136. package/dist/lib/types/copilot-config.d.ts.map +1 -0
  137. package/dist/lib/types/copilot-config.js +2 -0
  138. package/dist/lib/utils/copilot-plugin.d.ts +66 -0
  139. package/dist/lib/utils/copilot-plugin.d.ts.map +1 -0
  140. package/dist/lib/utils/copilot-plugin.js +87 -0
  141. package/migrations/0000_copilot_chat.sql +48 -0
  142. package/migrations/0001_proposals.sql +34 -0
  143. package/migrations/0002_drop_workspace_policies.sql +1 -0
  144. package/migrations/0003_conversation_allowed_tools.sql +1 -0
  145. package/migrations/0004_message_attachments.sql +1 -0
  146. package/migrations/0005_skills.sql +19 -0
  147. package/migrations/0006_conversation_model_choice.sql +1 -0
  148. package/migrations/meta/0000_snapshot.json +390 -0
  149. package/migrations/meta/0001_snapshot.json +657 -0
  150. package/migrations/meta/0002_snapshot.json +610 -0
  151. package/migrations/meta/0003_snapshot.json +617 -0
  152. package/migrations/meta/0004_snapshot.json +623 -0
  153. package/migrations/meta/0005_snapshot.json +771 -0
  154. package/migrations/meta/0006_snapshot.json +777 -0
  155. package/migrations/meta/_journal.json +55 -0
  156. package/package.json +46 -0
@@ -0,0 +1,64 @@
1
+ import { type PublicUser } from '@orthacms/identity-server';
2
+ import { SkillCatalogService, type SkillSummary } from '../../application/skill-catalog.service';
3
+ import { SkillRepository, type SkillRecord } from '../../infrastructure/persistence/skill.repository';
4
+ import { CreateSkillDto } from '../../application/dto/create-skill.dto';
5
+ import { UpdateSkillDto } from '../../application/dto/update-skill.dto';
6
+ /**
7
+ * Authoring skills — `GET /:id`, `POST`, `PATCH /:id`, `DELETE /:id` under
8
+ * `/api/copilot/skills`.
9
+ *
10
+ * **Every route here requires `copilot:skills:manage`, and that is the whole
11
+ * security posture of the feature.** A skill's `instructions` are prompt text
12
+ * that runs for every member of the workspace, so writing one is authoring part
13
+ * of the system prompt rather than authoring content
14
+ * ([ADR-0010](../../../../../../../docs/adr/0010-copilot-skills.md)). The key is
15
+ * admin-only in `SYSTEM_ROLES`; a contributor can use every skill and write
16
+ * none.
17
+ *
18
+ * `GET /:id` is here rather than beside the list route because it is the only
19
+ * read that carries the body, and the manage page is the only thing that needs
20
+ * one. `OriginGuard` on the three writes, as everywhere else that changes
21
+ * state.
22
+ *
23
+ * A skill that is not this workspace's is a **404, not a 403** — the repository
24
+ * filters on the workspace and reports "not found" either way, so an id cannot
25
+ * be probed for existence.
26
+ */
27
+ export declare class ManageSkillsController {
28
+ private readonly skills;
29
+ private readonly catalog;
30
+ constructor(skills: SkillRepository, catalog: SkillCatalogService);
31
+ /**
32
+ * Every skill the manage page lists — code skills (read-only) and all of
33
+ * the workspace's rows, disabled ones included.
34
+ *
35
+ * A second listing route rather than a flag on the public one, because the
36
+ * two answer different questions and have different permissions: "what may
37
+ * I attach?" is `copilot:use`, "what exists here?" is an admin's view.
38
+ */
39
+ manageList(workspaceId: string): Promise<SkillSummary[]>;
40
+ read(id: string, workspaceId: string): Promise<SkillRecord>;
41
+ create(body: CreateSkillDto, user: PublicUser, workspaceId: string): Promise<SkillRecord>;
42
+ update(id: string, body: UpdateSkillDto, workspaceId: string): Promise<SkillRecord>;
43
+ /**
44
+ * Deletes a skill.
45
+ *
46
+ * A real delete, unlike a conversation's — a skill is configuration rather
47
+ * than the receipt for a change somebody's content already took, and every
48
+ * turn that ran with it holds its own name/title snapshot, so the
49
+ * transcript survives.
50
+ */
51
+ remove(id: string, workspaceId: string): Promise<void>;
52
+ /**
53
+ * Refuses a name a code skill or another row already holds.
54
+ *
55
+ * A code skill's name is refused **here**, at the write, rather than left
56
+ * to `mergeSkills` at read time: the merge drops the shadowed row silently,
57
+ * which is the right thing to do when a deploy takes a name over but a
58
+ * terrible thing to do to someone who has just typed one — they would see a
59
+ * saved skill that never runs. The unique index behind this covers the
60
+ * concurrent case; this covers the legible one.
61
+ */
62
+ private assertNameFree;
63
+ }
64
+ //# sourceMappingURL=manage-skills.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manage-skills.controller.d.ts","sourceRoot":"","sources":["../../../../../src/lib/skills/http/controllers/manage-skills.controller.ts"],"names":[],"mappings":"AAiBA,OAAO,EAMH,KAAK,UAAU,EAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,mBAAmB,EACnB,KAAK,YAAY,EACpB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACH,eAAe,EACf,KAAK,WAAW,EACnB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAGa,sBAAsB;IAE3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,mBAAmB;IAGjD;;;;;;;OAOG;IAGG,UAAU,CACQ,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,YAAY,EAAE,CAAC;IAOpB,IAAI,CACsB,EAAE,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,WAAW,CAAC;IAYjB,MAAM,CACA,IAAI,EAAE,cAAc,EACb,IAAI,EAAE,UAAU,EACX,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,WAAW,CAAC;IAmBjB,MAAM,CACoB,EAAE,EAAE,MAAM,EAC9B,IAAI,EAAE,cAAc,EACR,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,WAAW,CAAC;IAoBvB;;;;;;;OAOG;IAKG,MAAM,CACoB,EAAE,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACxC,OAAO,CAAC,IAAI,CAAC;IAOhB;;;;;;;;;OASG;YACW,cAAc;CAiB/B"}
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ManageSkillsController = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const swagger_1 = require("@nestjs/swagger");
7
+ const identity_server_1 = require("@orthacms/identity-server");
8
+ const workspaces_server_1 = require("@orthacms/workspaces-server");
9
+ const skill_catalog_service_1 = require("../../application/skill-catalog.service");
10
+ const skill_repository_1 = require("../../infrastructure/persistence/skill.repository");
11
+ const create_skill_dto_1 = require("../../application/dto/create-skill.dto");
12
+ const update_skill_dto_1 = require("../../application/dto/update-skill.dto");
13
+ /**
14
+ * Authoring skills — `GET /:id`, `POST`, `PATCH /:id`, `DELETE /:id` under
15
+ * `/api/copilot/skills`.
16
+ *
17
+ * **Every route here requires `copilot:skills:manage`, and that is the whole
18
+ * security posture of the feature.** A skill's `instructions` are prompt text
19
+ * that runs for every member of the workspace, so writing one is authoring part
20
+ * of the system prompt rather than authoring content
21
+ * ([ADR-0010](../../../../../../../docs/adr/0010-copilot-skills.md)). The key is
22
+ * admin-only in `SYSTEM_ROLES`; a contributor can use every skill and write
23
+ * none.
24
+ *
25
+ * `GET /:id` is here rather than beside the list route because it is the only
26
+ * read that carries the body, and the manage page is the only thing that needs
27
+ * one. `OriginGuard` on the three writes, as everywhere else that changes
28
+ * state.
29
+ *
30
+ * A skill that is not this workspace's is a **404, not a 403** — the repository
31
+ * filters on the workspace and reports "not found" either way, so an id cannot
32
+ * be probed for existence.
33
+ */
34
+ let ManageSkillsController = class ManageSkillsController {
35
+ skills;
36
+ catalog;
37
+ constructor(skills, catalog) {
38
+ this.skills = skills;
39
+ this.catalog = catalog;
40
+ }
41
+ /**
42
+ * Every skill the manage page lists — code skills (read-only) and all of
43
+ * the workspace's rows, disabled ones included.
44
+ *
45
+ * A second listing route rather than a flag on the public one, because the
46
+ * two answer different questions and have different permissions: "what may
47
+ * I attach?" is `copilot:use`, "what exists here?" is an admin's view.
48
+ */
49
+ async manageList(workspaceId) {
50
+ return this.catalog.manageList(workspaceId);
51
+ }
52
+ async read(id, workspaceId) {
53
+ const skill = await this.skills.find(id, workspaceId);
54
+ if (!skill) {
55
+ throw new common_1.NotFoundException('Skill not found.');
56
+ }
57
+ return skill;
58
+ }
59
+ async create(body, user, workspaceId) {
60
+ await this.assertNameFree(body.name, workspaceId);
61
+ return this.skills.create({
62
+ workspaceId,
63
+ name: body.name,
64
+ title: body.title,
65
+ description: body.description,
66
+ instructions: body.instructions,
67
+ mode: body.mode ?? 'manual',
68
+ enabled: body.enabled ?? true,
69
+ createdBy: user.id
70
+ });
71
+ }
72
+ async update(id, body, workspaceId) {
73
+ // An empty patch cannot mean anything, and answering 200 to it would
74
+ // report success for a write that never happened. The pipe cannot catch
75
+ // this: every property is legitimately optional on its own.
76
+ if (Object.keys(body).length === 0) {
77
+ throw new common_1.BadRequestException('Provide at least one field to change.');
78
+ }
79
+ if (body.name !== undefined) {
80
+ await this.assertNameFree(body.name, workspaceId, id);
81
+ }
82
+ const updated = await this.skills.update(id, workspaceId, body);
83
+ if (!updated) {
84
+ throw new common_1.NotFoundException('Skill not found.');
85
+ }
86
+ return updated;
87
+ }
88
+ /**
89
+ * Deletes a skill.
90
+ *
91
+ * A real delete, unlike a conversation's — a skill is configuration rather
92
+ * than the receipt for a change somebody's content already took, and every
93
+ * turn that ran with it holds its own name/title snapshot, so the
94
+ * transcript survives.
95
+ */
96
+ async remove(id, workspaceId) {
97
+ const removed = await this.skills.remove(id, workspaceId);
98
+ if (!removed) {
99
+ throw new common_1.NotFoundException('Skill not found.');
100
+ }
101
+ }
102
+ /**
103
+ * Refuses a name a code skill or another row already holds.
104
+ *
105
+ * A code skill's name is refused **here**, at the write, rather than left
106
+ * to `mergeSkills` at read time: the merge drops the shadowed row silently,
107
+ * which is the right thing to do when a deploy takes a name over but a
108
+ * terrible thing to do to someone who has just typed one — they would see a
109
+ * saved skill that never runs. The unique index behind this covers the
110
+ * concurrent case; this covers the legible one.
111
+ */
112
+ async assertNameFree(name, workspaceId, exceptId) {
113
+ const taken = await this.catalog.nameTaken(name, workspaceId, exceptId);
114
+ if (taken === 'code') {
115
+ throw new common_1.ConflictException(`"${name}" is the name of a skill defined in this deployment's configuration. Choose another name.`);
116
+ }
117
+ if (taken === 'cms') {
118
+ throw new common_1.ConflictException(`This workspace already has a skill named "${name}".`);
119
+ }
120
+ }
121
+ };
122
+ exports.ManageSkillsController = ManageSkillsController;
123
+ tslib_1.__decorate([
124
+ (0, common_1.Get)('skills/manage'),
125
+ (0, swagger_1.ApiOperation)({ summary: 'List every skill, for the management page' }),
126
+ tslib_1.__param(0, (0, workspaces_server_1.CurrentWorkspace)()),
127
+ tslib_1.__metadata("design:type", Function),
128
+ tslib_1.__metadata("design:paramtypes", [String]),
129
+ tslib_1.__metadata("design:returntype", Promise)
130
+ ], ManageSkillsController.prototype, "manageList", null);
131
+ tslib_1.__decorate([
132
+ (0, common_1.Get)('skills/:id'),
133
+ (0, swagger_1.ApiOperation)({ summary: 'Read one skill, including its instructions' }),
134
+ (0, swagger_1.ApiResponse)({ status: 404, description: 'No such skill here.' }),
135
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
136
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
137
+ tslib_1.__metadata("design:type", Function),
138
+ tslib_1.__metadata("design:paramtypes", [String, String]),
139
+ tslib_1.__metadata("design:returntype", Promise)
140
+ ], ManageSkillsController.prototype, "read", null);
141
+ tslib_1.__decorate([
142
+ (0, common_1.Post)('skills'),
143
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
144
+ (0, swagger_1.ApiOperation)({ summary: 'Create a skill in this workspace' }),
145
+ (0, swagger_1.ApiResponse)({ status: 409, description: 'The name is already taken.' }),
146
+ tslib_1.__param(0, (0, common_1.Body)()),
147
+ tslib_1.__param(1, (0, identity_server_1.CurrentUser)()),
148
+ tslib_1.__param(2, (0, workspaces_server_1.CurrentWorkspace)()),
149
+ tslib_1.__metadata("design:type", Function),
150
+ tslib_1.__metadata("design:paramtypes", [create_skill_dto_1.CreateSkillDto, Object, String]),
151
+ tslib_1.__metadata("design:returntype", Promise)
152
+ ], ManageSkillsController.prototype, "create", null);
153
+ tslib_1.__decorate([
154
+ (0, common_1.Patch)('skills/:id'),
155
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
156
+ (0, swagger_1.ApiOperation)({ summary: 'Edit a skill' }),
157
+ (0, swagger_1.ApiResponse)({ status: 409, description: 'The new name is already taken.' }),
158
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
159
+ tslib_1.__param(1, (0, common_1.Body)()),
160
+ tslib_1.__param(2, (0, workspaces_server_1.CurrentWorkspace)()),
161
+ tslib_1.__metadata("design:type", Function),
162
+ tslib_1.__metadata("design:paramtypes", [String, update_skill_dto_1.UpdateSkillDto, String]),
163
+ tslib_1.__metadata("design:returntype", Promise)
164
+ ], ManageSkillsController.prototype, "update", null);
165
+ tslib_1.__decorate([
166
+ (0, common_1.Delete)('skills/:id'),
167
+ (0, common_1.UseGuards)(identity_server_1.OriginGuard),
168
+ (0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
169
+ (0, swagger_1.ApiOperation)({ summary: 'Delete a skill' }),
170
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
171
+ tslib_1.__param(1, (0, workspaces_server_1.CurrentWorkspace)()),
172
+ tslib_1.__metadata("design:type", Function),
173
+ tslib_1.__metadata("design:paramtypes", [String, String]),
174
+ tslib_1.__metadata("design:returntype", Promise)
175
+ ], ManageSkillsController.prototype, "remove", null);
176
+ exports.ManageSkillsController = ManageSkillsController = tslib_1.__decorate([
177
+ (0, common_1.UseGuards)(identity_server_1.PermissionsGuard, workspaces_server_1.WorkspaceGuard),
178
+ (0, identity_server_1.RequirePermissions)(identity_server_1.PERMISSIONS.COPILOT_SKILLS_MANAGE),
179
+ (0, common_1.Controller)('copilot'),
180
+ tslib_1.__metadata("design:paramtypes", [skill_repository_1.SkillRepository,
181
+ skill_catalog_service_1.SkillCatalogService])
182
+ ], ManageSkillsController);
@@ -0,0 +1,78 @@
1
+ import { type Database } from '@orthacms/database';
2
+ import type { Skill, SkillMode } from '@orthacms/copilot-domain';
3
+ /** A CMS skill as the manage page reads it — the row, plus its provenance. */
4
+ export interface SkillRecord extends Skill {
5
+ /** Row id. What the write routes address. */
6
+ id: string;
7
+ /** Whether it is on offer. */
8
+ enabled: boolean;
9
+ /** Who wrote it, when the account still exists. */
10
+ createdBy: string | null;
11
+ /** Row creation timestamp. */
12
+ createdAt: Date;
13
+ /** Last edit. */
14
+ updatedAt: Date;
15
+ }
16
+ /** The fields a create accepts. */
17
+ export interface CreateSkillInput {
18
+ workspaceId: string;
19
+ name: string;
20
+ title: string;
21
+ description: string;
22
+ instructions: string;
23
+ mode: SkillMode;
24
+ enabled: boolean;
25
+ createdBy: string;
26
+ }
27
+ /** The fields an update accepts — all optional, none of them the workspace. */
28
+ export interface UpdateSkillInput {
29
+ name?: string;
30
+ title?: string;
31
+ description?: string;
32
+ instructions?: string;
33
+ mode?: SkillMode;
34
+ enabled?: boolean;
35
+ }
36
+ /**
37
+ * Reads and writes CMS-authored skills.
38
+ *
39
+ * **Every method takes `workspaceId` and filters on it.** `WorkspaceGuard`
40
+ * proves the caller belongs to the workspace they named in the header; nothing
41
+ * upstream proves a *skill id* belongs to that workspace, so a valid session in
42
+ * workspace A could otherwise edit workspace B's instructions by id. Same rule,
43
+ * and same reason, as `ConversationRepository`.
44
+ */
45
+ export declare class SkillRepository {
46
+ private readonly db;
47
+ constructor(db: Database);
48
+ /**
49
+ * The workspace's skills, oldest first.
50
+ *
51
+ * `enabled` selects one of two **disjoint** sets when passed, rather than
52
+ * widening the result: the run catalogue wants only the live ones and the
53
+ * manage page wants everything, and a caller that meant "only live" would
54
+ * otherwise silently offer a skill someone deliberately switched off.
55
+ */
56
+ list(workspaceId: string, enabled?: boolean): Promise<SkillRecord[]>;
57
+ /**
58
+ * One skill, or `null` when the id is not this workspace's. Null rather
59
+ * than a throw for "not yours" as well as "no such id" — the two are
60
+ * indistinguishable to a caller, so an id cannot be probed for existence.
61
+ */
62
+ find(id: string, workspaceId: string): Promise<SkillRecord | null>;
63
+ /** Whether the workspace already has a skill under this name. */
64
+ findByName(name: string, workspaceId: string): Promise<SkillRecord | null>;
65
+ /** Writes a new skill. */
66
+ create(input: CreateSkillInput): Promise<SkillRecord>;
67
+ /**
68
+ * Applies a patch, returning the updated row — or `null` when the id is not
69
+ * this workspace's.
70
+ *
71
+ * The ownership predicate is part of the `UPDATE` rather than a read
72
+ * beforehand, so there is no check-then-write window.
73
+ */
74
+ update(id: string, workspaceId: string, patch: UpdateSkillInput): Promise<SkillRecord | null>;
75
+ /** Deletes a skill. `false` when the id is not this workspace's. */
76
+ remove(id: string, workspaceId: string): Promise<boolean>;
77
+ }
78
+ //# sourceMappingURL=skill.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.repository.d.ts","sourceRoot":"","sources":["../../../../../src/lib/skills/infrastructure/persistence/skill.repository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGjE,8EAA8E;AAC9E,MAAM,WAAW,WAAY,SAAQ,KAAK;IACtC,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8BAA8B;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,iBAAiB;IACjB,SAAS,EAAE,IAAI,CAAC;CACnB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,qBACa,eAAe;IACM,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAE3D;;;;;;;OAOG;IACG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAgB1E;;;;OAIG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAcxE,iEAAiE;IAC3D,UAAU,CACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc9B,0BAA0B;IACpB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ3D;;;;;;OAMG;IACG,MAAM,CACR,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc9B,oEAAoE;IAC9D,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAYlE"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SkillRepository = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const drizzle_orm_1 = require("drizzle-orm");
7
+ const database_1 = require("@orthacms/database");
8
+ const skills_1 = require("../schema/skills");
9
+ /**
10
+ * Reads and writes CMS-authored skills.
11
+ *
12
+ * **Every method takes `workspaceId` and filters on it.** `WorkspaceGuard`
13
+ * proves the caller belongs to the workspace they named in the header; nothing
14
+ * upstream proves a *skill id* belongs to that workspace, so a valid session in
15
+ * workspace A could otherwise edit workspace B's instructions by id. Same rule,
16
+ * and same reason, as `ConversationRepository`.
17
+ */
18
+ let SkillRepository = class SkillRepository {
19
+ db;
20
+ constructor(db) {
21
+ this.db = db;
22
+ }
23
+ /**
24
+ * The workspace's skills, oldest first.
25
+ *
26
+ * `enabled` selects one of two **disjoint** sets when passed, rather than
27
+ * widening the result: the run catalogue wants only the live ones and the
28
+ * manage page wants everything, and a caller that meant "only live" would
29
+ * otherwise silently offer a skill someone deliberately switched off.
30
+ */
31
+ async list(workspaceId, enabled) {
32
+ const rows = await this.db
33
+ .select()
34
+ .from(skills_1.copilotSkills)
35
+ .where(enabled === undefined
36
+ ? (0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId)
37
+ : (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId), (0, drizzle_orm_1.eq)(skills_1.copilotSkills.enabled, enabled)))
38
+ .orderBy((0, drizzle_orm_1.asc)(skills_1.copilotSkills.createdAt));
39
+ return rows.map(toRecord);
40
+ }
41
+ /**
42
+ * One skill, or `null` when the id is not this workspace's. Null rather
43
+ * than a throw for "not yours" as well as "no such id" — the two are
44
+ * indistinguishable to a caller, so an id cannot be probed for existence.
45
+ */
46
+ async find(id, workspaceId) {
47
+ const [row] = await this.db
48
+ .select()
49
+ .from(skills_1.copilotSkills)
50
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(skills_1.copilotSkills.id, id), (0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId)))
51
+ .limit(1);
52
+ return row ? toRecord(row) : null;
53
+ }
54
+ /** Whether the workspace already has a skill under this name. */
55
+ async findByName(name, workspaceId) {
56
+ const [row] = await this.db
57
+ .select()
58
+ .from(skills_1.copilotSkills)
59
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(skills_1.copilotSkills.name, name), (0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId)))
60
+ .limit(1);
61
+ return row ? toRecord(row) : null;
62
+ }
63
+ /** Writes a new skill. */
64
+ async create(input) {
65
+ const [row] = await this.db
66
+ .insert(skills_1.copilotSkills)
67
+ .values(input)
68
+ .returning();
69
+ return toRecord(row);
70
+ }
71
+ /**
72
+ * Applies a patch, returning the updated row — or `null` when the id is not
73
+ * this workspace's.
74
+ *
75
+ * The ownership predicate is part of the `UPDATE` rather than a read
76
+ * beforehand, so there is no check-then-write window.
77
+ */
78
+ async update(id, workspaceId, patch) {
79
+ const [row] = await this.db
80
+ .update(skills_1.copilotSkills)
81
+ .set({ ...patch, updatedAt: new Date() })
82
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(skills_1.copilotSkills.id, id), (0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId)))
83
+ .returning();
84
+ return row ? toRecord(row) : null;
85
+ }
86
+ /** Deletes a skill. `false` when the id is not this workspace's. */
87
+ async remove(id, workspaceId) {
88
+ const rows = await this.db
89
+ .delete(skills_1.copilotSkills)
90
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(skills_1.copilotSkills.id, id), (0, drizzle_orm_1.eq)(skills_1.copilotSkills.workspaceId, workspaceId)))
91
+ .returning({ id: skills_1.copilotSkills.id });
92
+ return rows.length > 0;
93
+ }
94
+ };
95
+ exports.SkillRepository = SkillRepository;
96
+ exports.SkillRepository = SkillRepository = tslib_1.__decorate([
97
+ (0, common_1.Injectable)(),
98
+ tslib_1.__param(0, (0, database_1.InjectDatabase)()),
99
+ tslib_1.__metadata("design:paramtypes", [Object])
100
+ ], SkillRepository);
101
+ /** The row, with `source` stamped — a database row is always a CMS skill. */
102
+ function toRecord(row) {
103
+ return {
104
+ id: row.id,
105
+ name: row.name,
106
+ title: row.title,
107
+ description: row.description,
108
+ instructions: row.instructions,
109
+ mode: row.mode,
110
+ enabled: row.enabled,
111
+ source: 'cms',
112
+ createdBy: row.createdBy,
113
+ createdAt: row.createdAt,
114
+ updatedAt: row.updatedAt
115
+ };
116
+ }
@@ -0,0 +1,2 @@
1
+ export { copilotSkills, copilotSkillMode } from './skills';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/skills/infrastructure/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.copilotSkillMode = exports.copilotSkills = void 0;
4
+ var skills_1 = require("./skills");
5
+ Object.defineProperty(exports, "copilotSkills", { enumerable: true, get: function () { return skills_1.copilotSkills; } });
6
+ Object.defineProperty(exports, "copilotSkillMode", { enumerable: true, get: function () { return skills_1.copilotSkillMode; } });