@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.
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/lib/chat/application/appliers-registrar.d.ts +16 -0
- package/dist/lib/chat/application/appliers-registrar.d.ts.map +1 -0
- package/dist/lib/chat/application/appliers-registrar.js +50 -0
- package/dist/lib/chat/application/capability-profile.service.d.ts +43 -0
- package/dist/lib/chat/application/capability-profile.service.d.ts.map +1 -0
- package/dist/lib/chat/application/capability-profile.service.js +75 -0
- package/dist/lib/chat/application/content-type-summary.service.d.ts +32 -0
- package/dist/lib/chat/application/content-type-summary.service.d.ts.map +1 -0
- package/dist/lib/chat/application/content-type-summary.service.js +64 -0
- package/dist/lib/chat/application/decide-proposal.service.d.ts +80 -0
- package/dist/lib/chat/application/decide-proposal.service.d.ts.map +1 -0
- package/dist/lib/chat/application/decide-proposal.service.js +112 -0
- package/dist/lib/chat/application/dto/create-run.dto.d.ts +138 -0
- package/dist/lib/chat/application/dto/create-run.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/create-run.dto.js +253 -0
- package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts +20 -0
- package/dist/lib/chat/application/dto/decide-tool-permission.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/decide-tool-permission.dto.js +44 -0
- package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts +18 -0
- package/dist/lib/chat/application/dto/extend-tool-permission.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/extend-tool-permission.dto.js +33 -0
- package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts +18 -0
- package/dist/lib/chat/application/dto/list-conversations-query.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/list-conversations-query.dto.js +39 -0
- package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts +15 -0
- package/dist/lib/chat/application/dto/list-proposals-query.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/list-proposals-query.dto.js +41 -0
- package/dist/lib/chat/application/dto/update-conversation.dto.d.ts +68 -0
- package/dist/lib/chat/application/dto/update-conversation.dto.d.ts.map +1 -0
- package/dist/lib/chat/application/dto/update-conversation.dto.js +115 -0
- package/dist/lib/chat/application/proposal-applier.registry.d.ts +27 -0
- package/dist/lib/chat/application/proposal-applier.registry.d.ts.map +1 -0
- package/dist/lib/chat/application/proposal-applier.registry.js +62 -0
- package/dist/lib/chat/application/run-engine.service.d.ts +243 -0
- package/dist/lib/chat/application/run-engine.service.d.ts.map +1 -0
- package/dist/lib/chat/application/run-engine.service.js +1058 -0
- package/dist/lib/chat/application/summarize-tool-output.d.ts +15 -0
- package/dist/lib/chat/application/summarize-tool-output.d.ts.map +1 -0
- package/dist/lib/chat/application/summarize-tool-output.js +61 -0
- package/dist/lib/chat/application/system-prompt.d.ts +81 -0
- package/dist/lib/chat/application/system-prompt.d.ts.map +1 -0
- package/dist/lib/chat/application/system-prompt.js +477 -0
- package/dist/lib/chat/application/tool-permission.broker.d.ts +118 -0
- package/dist/lib/chat/application/tool-permission.broker.d.ts.map +1 -0
- package/dist/lib/chat/application/tool-permission.broker.js +221 -0
- package/dist/lib/chat/http/controllers/create-run.controller.d.ts +30 -0
- package/dist/lib/chat/http/controllers/create-run.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/create-run.controller.js +159 -0
- package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts +22 -0
- package/dist/lib/chat/http/controllers/get-conversation.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/get-conversation.controller.js +50 -0
- package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts +20 -0
- package/dist/lib/chat/http/controllers/list-conversations.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/list-conversations.controller.js +47 -0
- package/dist/lib/chat/http/controllers/list-models.controller.d.ts +35 -0
- package/dist/lib/chat/http/controllers/list-models.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/list-models.controller.js +48 -0
- package/dist/lib/chat/http/controllers/proposals.controller.d.ts +43 -0
- package/dist/lib/chat/http/controllers/proposals.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/proposals.controller.js +98 -0
- package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts +57 -0
- package/dist/lib/chat/http/controllers/tool-permission.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/tool-permission.controller.js +116 -0
- package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts +37 -0
- package/dist/lib/chat/http/controllers/update-conversation.controller.d.ts.map +1 -0
- package/dist/lib/chat/http/controllers/update-conversation.controller.js +108 -0
- package/dist/lib/chat/http/sse-stream.d.ts +41 -0
- package/dist/lib/chat/http/sse-stream.d.ts.map +1 -0
- package/dist/lib/chat/http/sse-stream.js +95 -0
- package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts +159 -0
- package/dist/lib/chat/infrastructure/persistence/conversation.repository.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/persistence/conversation.repository.js +249 -0
- package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts +13 -0
- package/dist/lib/chat/infrastructure/persistence/derive-title.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/persistence/derive-title.js +35 -0
- package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts +86 -0
- package/dist/lib/chat/infrastructure/persistence/proposal.repository.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/persistence/proposal.repository.js +152 -0
- package/dist/lib/chat/infrastructure/schema/conversations.d.ts +189 -0
- package/dist/lib/chat/infrastructure/schema/conversations.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/conversations.js +100 -0
- package/dist/lib/chat/infrastructure/schema/external-refs.d.ts +67 -0
- package/dist/lib/chat/infrastructure/schema/external-refs.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/external-refs.js +28 -0
- package/dist/lib/chat/infrastructure/schema/index.d.ts +5 -0
- package/dist/lib/chat/infrastructure/schema/index.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/index.js +12 -0
- package/dist/lib/chat/infrastructure/schema/messages.d.ts +264 -0
- package/dist/lib/chat/infrastructure/schema/messages.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/messages.js +96 -0
- package/dist/lib/chat/infrastructure/schema/proposals.d.ts +328 -0
- package/dist/lib/chat/infrastructure/schema/proposals.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/proposals.js +87 -0
- package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts +203 -0
- package/dist/lib/chat/infrastructure/schema/tool-calls.d.ts.map +1 -0
- package/dist/lib/chat/infrastructure/schema/tool-calls.js +50 -0
- package/dist/lib/copilot.module.d.ts +30 -0
- package/dist/lib/copilot.module.d.ts.map +1 -0
- package/dist/lib/copilot.module.js +146 -0
- package/dist/lib/copilot.tokens.d.ts +34 -0
- package/dist/lib/copilot.tokens.d.ts.map +1 -0
- package/dist/lib/copilot.tokens.js +38 -0
- package/dist/lib/infrastructure/model-registry.d.ts +22 -0
- package/dist/lib/infrastructure/model-registry.d.ts.map +1 -0
- package/dist/lib/infrastructure/model-registry.js +54 -0
- package/dist/lib/skills/application/dto/create-skill.dto.d.ts +36 -0
- package/dist/lib/skills/application/dto/create-skill.dto.d.ts.map +1 -0
- package/dist/lib/skills/application/dto/create-skill.dto.js +106 -0
- package/dist/lib/skills/application/dto/update-skill.dto.d.ts +28 -0
- package/dist/lib/skills/application/dto/update-skill.dto.d.ts.map +1 -0
- package/dist/lib/skills/application/dto/update-skill.dto.js +96 -0
- package/dist/lib/skills/application/skill-catalog.service.d.ts +97 -0
- package/dist/lib/skills/application/skill-catalog.service.d.ts.map +1 -0
- package/dist/lib/skills/application/skill-catalog.service.js +157 -0
- package/dist/lib/skills/http/controllers/list-skills.controller.d.ts +19 -0
- package/dist/lib/skills/http/controllers/list-skills.controller.d.ts.map +1 -0
- package/dist/lib/skills/http/controllers/list-skills.controller.js +50 -0
- package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts +64 -0
- package/dist/lib/skills/http/controllers/manage-skills.controller.d.ts.map +1 -0
- package/dist/lib/skills/http/controllers/manage-skills.controller.js +182 -0
- package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts +78 -0
- package/dist/lib/skills/infrastructure/persistence/skill.repository.d.ts.map +1 -0
- package/dist/lib/skills/infrastructure/persistence/skill.repository.js +116 -0
- package/dist/lib/skills/infrastructure/schema/index.d.ts +2 -0
- package/dist/lib/skills/infrastructure/schema/index.d.ts.map +1 -0
- package/dist/lib/skills/infrastructure/schema/index.js +6 -0
- package/dist/lib/skills/infrastructure/schema/skills.d.ts +212 -0
- package/dist/lib/skills/infrastructure/schema/skills.d.ts.map +1 -0
- package/dist/lib/skills/infrastructure/schema/skills.js +78 -0
- package/dist/lib/types/copilot-config.d.ts +55 -0
- package/dist/lib/types/copilot-config.d.ts.map +1 -0
- package/dist/lib/types/copilot-config.js +2 -0
- package/dist/lib/utils/copilot-plugin.d.ts +66 -0
- package/dist/lib/utils/copilot-plugin.d.ts.map +1 -0
- package/dist/lib/utils/copilot-plugin.js +87 -0
- package/migrations/0000_copilot_chat.sql +48 -0
- package/migrations/0001_proposals.sql +34 -0
- package/migrations/0002_drop_workspace_policies.sql +1 -0
- package/migrations/0003_conversation_allowed_tools.sql +1 -0
- package/migrations/0004_message_attachments.sql +1 -0
- package/migrations/0005_skills.sql +19 -0
- package/migrations/0006_conversation_model_choice.sql +1 -0
- package/migrations/meta/0000_snapshot.json +390 -0
- package/migrations/meta/0001_snapshot.json +657 -0
- package/migrations/meta/0002_snapshot.json +610 -0
- package/migrations/meta/0003_snapshot.json +617 -0
- package/migrations/meta/0004_snapshot.json +623 -0
- package/migrations/meta/0005_snapshot.json +771 -0
- package/migrations/meta/0006_snapshot.json +777 -0
- package/migrations/meta/_journal.json +55 -0
- 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 @@
|
|
|
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; } });
|