@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ortha CMS contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { CopilotPlugin } from './lib/utils/copilot-plugin';
|
|
2
|
+
export type { CopilotPluginOptions, CopilotServerPluginDefinition } from './lib/utils/copilot-plugin';
|
|
3
|
+
export { CopilotModule } from './lib/copilot.module';
|
|
4
|
+
export type { CopilotModuleOptions } from './lib/copilot.module';
|
|
5
|
+
export { COPILOT_CONFIG, COPILOT_RUN_LIMITS, COPILOT_SKILL_REGISTRY, InjectCopilotConfig } from './lib/copilot.tokens';
|
|
6
|
+
export type { CopilotPluginConfig } from './lib/types/copilot-config';
|
|
7
|
+
export { buildModelRegistry } from './lib/infrastructure/model-registry';
|
|
8
|
+
export type { ProviderRegistration } from './lib/infrastructure/model-registry';
|
|
9
|
+
export { ProposalApplierRegistry } from './lib/chat/application/proposal-applier.registry';
|
|
10
|
+
export { copilotAppliersRegistrar } from './lib/chat/application/appliers-registrar';
|
|
11
|
+
export { RunEngine, CopilotDisabledError, UnknownModelChoiceError } from './lib/chat/application/run-engine.service';
|
|
12
|
+
export type { StartRunInput } from './lib/chat/application/run-engine.service';
|
|
13
|
+
export { CapabilityProfileService } from './lib/chat/application/capability-profile.service';
|
|
14
|
+
export { ConversationRepository } from './lib/chat/infrastructure/persistence/conversation.repository';
|
|
15
|
+
export type { ConversationView, MessageView, ToolCallRecord } from './lib/chat/infrastructure/persistence/conversation.repository';
|
|
16
|
+
export { buildSystemPrompt, SYSTEM_PROMPT_VERSION } from './lib/chat/application/system-prompt';
|
|
17
|
+
export type { SurfaceContext, SystemPromptInput } from './lib/chat/application/system-prompt';
|
|
18
|
+
export { SkillCatalogService, SkillResolutionError } from './lib/skills/application/skill-catalog.service';
|
|
19
|
+
export type { SkillSummary } from './lib/skills/application/skill-catalog.service';
|
|
20
|
+
export { SkillRepository } from './lib/skills/infrastructure/persistence/skill.repository';
|
|
21
|
+
export type { SkillRecord } from './lib/skills/infrastructure/persistence/skill.repository';
|
|
22
|
+
export * from './lib/chat/infrastructure/schema';
|
|
23
|
+
export * from './lib/skills/infrastructure/schema';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EACR,oBAAoB,EACpB,6BAA6B,EAChC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACH,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAMhF,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAG3F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AAKrF,OAAO,EACH,SAAS,EACT,oBAAoB,EACpB,uBAAuB,EAC1B,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,+DAA+D,CAAC;AACvG,YAAY,EACR,gBAAgB,EAChB,WAAW,EACX,cAAc,EACjB,MAAM,+DAA+D,CAAC;AACvE,OAAO,EACH,iBAAiB,EACjB,qBAAqB,EACxB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACR,cAAc,EACd,iBAAiB,EACpB,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EACH,mBAAmB,EACnB,oBAAoB,EACvB,MAAM,gDAAgD,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAC3F,YAAY,EAAE,WAAW,EAAE,MAAM,0DAA0D,CAAC;AAG5F,cAAc,kCAAkC,CAAC;AACjD,cAAc,oCAAoC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkillRepository = exports.SkillResolutionError = exports.SkillCatalogService = exports.SYSTEM_PROMPT_VERSION = exports.buildSystemPrompt = exports.ConversationRepository = exports.CapabilityProfileService = exports.UnknownModelChoiceError = exports.CopilotDisabledError = exports.RunEngine = exports.copilotAppliersRegistrar = exports.ProposalApplierRegistry = exports.buildModelRegistry = exports.InjectCopilotConfig = exports.COPILOT_SKILL_REGISTRY = exports.COPILOT_RUN_LIMITS = exports.COPILOT_CONFIG = exports.CopilotModule = exports.CopilotPlugin = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
var copilot_plugin_1 = require("./lib/utils/copilot-plugin");
|
|
6
|
+
Object.defineProperty(exports, "CopilotPlugin", { enumerable: true, get: function () { return copilot_plugin_1.CopilotPlugin; } });
|
|
7
|
+
var copilot_module_1 = require("./lib/copilot.module");
|
|
8
|
+
Object.defineProperty(exports, "CopilotModule", { enumerable: true, get: function () { return copilot_module_1.CopilotModule; } });
|
|
9
|
+
var copilot_tokens_1 = require("./lib/copilot.tokens");
|
|
10
|
+
Object.defineProperty(exports, "COPILOT_CONFIG", { enumerable: true, get: function () { return copilot_tokens_1.COPILOT_CONFIG; } });
|
|
11
|
+
Object.defineProperty(exports, "COPILOT_RUN_LIMITS", { enumerable: true, get: function () { return copilot_tokens_1.COPILOT_RUN_LIMITS; } });
|
|
12
|
+
Object.defineProperty(exports, "COPILOT_SKILL_REGISTRY", { enumerable: true, get: function () { return copilot_tokens_1.COPILOT_SKILL_REGISTRY; } });
|
|
13
|
+
Object.defineProperty(exports, "InjectCopilotConfig", { enumerable: true, get: function () { return copilot_tokens_1.InjectCopilotConfig; } });
|
|
14
|
+
var model_registry_1 = require("./lib/infrastructure/model-registry");
|
|
15
|
+
Object.defineProperty(exports, "buildModelRegistry", { enumerable: true, get: function () { return model_registry_1.buildModelRegistry; } });
|
|
16
|
+
// Tools are no longer registered here. A binding plugin registers with the
|
|
17
|
+
// shared `ToolRegistry` from `@orthacms/tools-server` — the same catalogue the
|
|
18
|
+
// MCP endpoint serves — and marks a copilot-only tool `surfaces: ['copilot']`
|
|
19
|
+
// (ADR-0006 §2).
|
|
20
|
+
var proposal_applier_registry_1 = require("./lib/chat/application/proposal-applier.registry");
|
|
21
|
+
Object.defineProperty(exports, "ProposalApplierRegistry", { enumerable: true, get: function () { return proposal_applier_registry_1.ProposalApplierRegistry; } });
|
|
22
|
+
// The sibling one-liner for the plugins that own writes. A plugin binding
|
|
23
|
+
// propose tools must register the appliers for the kinds they produce.
|
|
24
|
+
var appliers_registrar_1 = require("./lib/chat/application/appliers-registrar");
|
|
25
|
+
Object.defineProperty(exports, "copilotAppliersRegistrar", { enumerable: true, get: function () { return appliers_registrar_1.copilotAppliersRegistrar; } });
|
|
26
|
+
// The run engine and its collaborators, exported for tests and for a future
|
|
27
|
+
// non-HTTP surface (a job runner in phase 5) that needs the loop without the
|
|
28
|
+
// controller.
|
|
29
|
+
var run_engine_service_1 = require("./lib/chat/application/run-engine.service");
|
|
30
|
+
Object.defineProperty(exports, "RunEngine", { enumerable: true, get: function () { return run_engine_service_1.RunEngine; } });
|
|
31
|
+
Object.defineProperty(exports, "CopilotDisabledError", { enumerable: true, get: function () { return run_engine_service_1.CopilotDisabledError; } });
|
|
32
|
+
Object.defineProperty(exports, "UnknownModelChoiceError", { enumerable: true, get: function () { return run_engine_service_1.UnknownModelChoiceError; } });
|
|
33
|
+
var capability_profile_service_1 = require("./lib/chat/application/capability-profile.service");
|
|
34
|
+
Object.defineProperty(exports, "CapabilityProfileService", { enumerable: true, get: function () { return capability_profile_service_1.CapabilityProfileService; } });
|
|
35
|
+
var conversation_repository_1 = require("./lib/chat/infrastructure/persistence/conversation.repository");
|
|
36
|
+
Object.defineProperty(exports, "ConversationRepository", { enumerable: true, get: function () { return conversation_repository_1.ConversationRepository; } });
|
|
37
|
+
var system_prompt_1 = require("./lib/chat/application/system-prompt");
|
|
38
|
+
Object.defineProperty(exports, "buildSystemPrompt", { enumerable: true, get: function () { return system_prompt_1.buildSystemPrompt; } });
|
|
39
|
+
Object.defineProperty(exports, "SYSTEM_PROMPT_VERSION", { enumerable: true, get: function () { return system_prompt_1.SYSTEM_PROMPT_VERSION; } });
|
|
40
|
+
// --- skills ---
|
|
41
|
+
var skill_catalog_service_1 = require("./lib/skills/application/skill-catalog.service");
|
|
42
|
+
Object.defineProperty(exports, "SkillCatalogService", { enumerable: true, get: function () { return skill_catalog_service_1.SkillCatalogService; } });
|
|
43
|
+
Object.defineProperty(exports, "SkillResolutionError", { enumerable: true, get: function () { return skill_catalog_service_1.SkillResolutionError; } });
|
|
44
|
+
var skill_repository_1 = require("./lib/skills/infrastructure/persistence/skill.repository");
|
|
45
|
+
Object.defineProperty(exports, "SkillRepository", { enumerable: true, get: function () { return skill_repository_1.SkillRepository; } });
|
|
46
|
+
// The Drizzle tables this plugin owns and migrates.
|
|
47
|
+
tslib_1.__exportStar(require("./lib/chat/infrastructure/schema"), exports);
|
|
48
|
+
tslib_1.__exportStar(require("./lib/skills/infrastructure/schema"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Provider, type Type } from '@nestjs/common';
|
|
2
|
+
import type { ProposalApplier } from '@orthacms/copilot-domain';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the DI provider that registers `appliers` with the copilot's proposal
|
|
5
|
+
* registry at bootstrap. The sibling of `copilotToolsRegistrar`, and the same
|
|
6
|
+
* factory shape for the same reason: an explicit `inject` list has no reflected
|
|
7
|
+
* parameter type to get wrong, so an optional dependency cannot silently
|
|
8
|
+
* resolve to `undefined` and leave the plugin's writes unappliable.
|
|
9
|
+
*
|
|
10
|
+
* A plugin that binds propose tools **must** also register the appliers for the
|
|
11
|
+
* kinds those tools produce. Forgetting shows up only when a human clicks
|
|
12
|
+
* Accept — the proposal is refused with "this deployment cannot carry that
|
|
13
|
+
* change out" — so the two belong in the same module block, next to each other.
|
|
14
|
+
*/
|
|
15
|
+
export declare function copilotAppliersRegistrar(label: string, ...appliers: Type<ProposalApplier>[]): Provider;
|
|
16
|
+
//# sourceMappingURL=appliers-registrar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appliers-registrar.d.ts","sourceRoot":"","sources":["../../../../src/lib/chat/application/appliers-registrar.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,QAAQ,EACb,KAAK,IAAI,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA4BhE;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,MAAM,EACb,GAAG,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,GACrC,QAAQ,CAYV"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.copilotAppliersRegistrar = copilotAppliersRegistrar;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const proposal_applier_registry_1 = require("./proposal-applier.registry");
|
|
6
|
+
/** Registers a plugin's proposal appliers with the copilot at bootstrap. */
|
|
7
|
+
class AppliersBootstrapper {
|
|
8
|
+
label;
|
|
9
|
+
registry;
|
|
10
|
+
appliers;
|
|
11
|
+
logger = new common_1.Logger(AppliersBootstrapper.name);
|
|
12
|
+
constructor(label, registry, appliers) {
|
|
13
|
+
this.label = label;
|
|
14
|
+
this.registry = registry;
|
|
15
|
+
this.appliers = appliers;
|
|
16
|
+
}
|
|
17
|
+
onApplicationBootstrap() {
|
|
18
|
+
// A deployment that doesn't register `CopilotPlugin` is normal, and
|
|
19
|
+
// every binding plugin must boot without it.
|
|
20
|
+
if (!this.registry) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const applier of this.appliers) {
|
|
24
|
+
this.registry.register(applier);
|
|
25
|
+
}
|
|
26
|
+
this.logger.log(`Registered ${this.label} proposal appliers with the copilot.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds the DI provider that registers `appliers` with the copilot's proposal
|
|
31
|
+
* registry at bootstrap. The sibling of `copilotToolsRegistrar`, and the same
|
|
32
|
+
* factory shape for the same reason: an explicit `inject` list has no reflected
|
|
33
|
+
* parameter type to get wrong, so an optional dependency cannot silently
|
|
34
|
+
* resolve to `undefined` and leave the plugin's writes unappliable.
|
|
35
|
+
*
|
|
36
|
+
* A plugin that binds propose tools **must** also register the appliers for the
|
|
37
|
+
* kinds those tools produce. Forgetting shows up only when a human clicks
|
|
38
|
+
* Accept — the proposal is refused with "this deployment cannot carry that
|
|
39
|
+
* change out" — so the two belong in the same module block, next to each other.
|
|
40
|
+
*/
|
|
41
|
+
function copilotAppliersRegistrar(label, ...appliers) {
|
|
42
|
+
return {
|
|
43
|
+
provide: `COPILOT_APPLIERS_REGISTRAR_${label.toUpperCase()}`,
|
|
44
|
+
useFactory: (registry, ...resolved) => new AppliersBootstrapper(label, registry, resolved),
|
|
45
|
+
inject: [
|
|
46
|
+
{ token: proposal_applier_registry_1.ProposalApplierRegistry, optional: true },
|
|
47
|
+
...appliers
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { PermissionsService } from '@orthacms/identity-server';
|
|
2
|
+
import { ToolRegistry, type ToolContext, type ToolDefinition } from '@orthacms/tools-server';
|
|
3
|
+
import { type CapabilityProfile } from '@orthacms/copilot-domain';
|
|
4
|
+
/** A run's authority: the profile the model is offered, and the tool context. */
|
|
5
|
+
export interface RunAuthority {
|
|
6
|
+
/** The tools offered this run, and what was withheld. */
|
|
7
|
+
profile: CapabilityProfile<ToolDefinition>;
|
|
8
|
+
/** What a tool call is handed — reused for every call in the run. */
|
|
9
|
+
context: ToolContext;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the tool set one run may use.
|
|
13
|
+
*
|
|
14
|
+
* **The catalogue is the shared `ToolRegistry`** (ADR-0006 §2) — the same
|
|
15
|
+
* instance the MCP endpoint serves — narrowed to the `copilot` surface. What
|
|
16
|
+
* stays copilot-specific is the pure `resolveCapabilityProfile` in
|
|
17
|
+
* `copilot-domain` and the `withheld` reasons it returns. Keeping that rule
|
|
18
|
+
* pure is what makes "a viewer is offered no write tools" a unit test rather
|
|
19
|
+
* than an e2e hope.
|
|
20
|
+
*
|
|
21
|
+
* **The caller's grants are the whole decision**
|
|
22
|
+
* ([ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)).
|
|
23
|
+
* There used to be a second input — the workspace's auto-apply policy, read
|
|
24
|
+
* here per run — and it is gone along with the table behind it. One resolution
|
|
25
|
+
* per run, one rule.
|
|
26
|
+
*
|
|
27
|
+
* **Nothing here is cached.** [ADR-0005](../../../../../../docs/adr/0005-copilot-authority-model.md) §2
|
|
28
|
+
* requires the profile be recomputed per run: permissions can be revoked
|
|
29
|
+
* mid-thread, and a long conversation must not carry stale authority. The cost
|
|
30
|
+
* is one indexed read per run, which the ADR accepts explicitly.
|
|
31
|
+
*/
|
|
32
|
+
export declare class CapabilityProfileService {
|
|
33
|
+
private readonly permissions;
|
|
34
|
+
private readonly tools;
|
|
35
|
+
constructor(permissions: PermissionsService, tools: ToolRegistry);
|
|
36
|
+
/** The authority for a run by `user` in `workspaceId`. */
|
|
37
|
+
resolve(user: {
|
|
38
|
+
id: string;
|
|
39
|
+
email: string;
|
|
40
|
+
roleId: string;
|
|
41
|
+
}, workspaceId: string, signal?: AbortSignal): Promise<RunAuthority>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=capability-profile.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-profile.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/chat/application/capability-profile.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAEH,YAAY,EAEZ,KAAK,WAAW,EAChB,KAAK,cAAc,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEH,KAAK,iBAAiB,EAEzB,MAAM,0BAA0B,CAAC;AAElC,iFAAiF;AACjF,MAAM,WAAW,YAAY;IACzB,yDAAyD;IACzD,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC3C,qEAAqE;IACrE,OAAO,EAAE,WAAW,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBACa,wBAAwB;IAE7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,WAAW,EAAE,kBAAkB,EAC/B,KAAK,EAAE,YAAY;IAGxC,0DAA0D;IACpD,OAAO,CACT,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EACnD,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,YAAY,CAAC;CAkC3B"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CapabilityProfileService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const identity_server_1 = require("@orthacms/identity-server");
|
|
7
|
+
const tools_server_1 = require("@orthacms/tools-server");
|
|
8
|
+
const copilot_domain_1 = require("@orthacms/copilot-domain");
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the tool set one run may use.
|
|
11
|
+
*
|
|
12
|
+
* **The catalogue is the shared `ToolRegistry`** (ADR-0006 §2) — the same
|
|
13
|
+
* instance the MCP endpoint serves — narrowed to the `copilot` surface. What
|
|
14
|
+
* stays copilot-specific is the pure `resolveCapabilityProfile` in
|
|
15
|
+
* `copilot-domain` and the `withheld` reasons it returns. Keeping that rule
|
|
16
|
+
* pure is what makes "a viewer is offered no write tools" a unit test rather
|
|
17
|
+
* than an e2e hope.
|
|
18
|
+
*
|
|
19
|
+
* **The caller's grants are the whole decision**
|
|
20
|
+
* ([ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)).
|
|
21
|
+
* There used to be a second input — the workspace's auto-apply policy, read
|
|
22
|
+
* here per run — and it is gone along with the table behind it. One resolution
|
|
23
|
+
* per run, one rule.
|
|
24
|
+
*
|
|
25
|
+
* **Nothing here is cached.** [ADR-0005](../../../../../../docs/adr/0005-copilot-authority-model.md) §2
|
|
26
|
+
* requires the profile be recomputed per run: permissions can be revoked
|
|
27
|
+
* mid-thread, and a long conversation must not carry stale authority. The cost
|
|
28
|
+
* is one indexed read per run, which the ADR accepts explicitly.
|
|
29
|
+
*/
|
|
30
|
+
let CapabilityProfileService = class CapabilityProfileService {
|
|
31
|
+
permissions;
|
|
32
|
+
tools;
|
|
33
|
+
constructor(permissions, tools) {
|
|
34
|
+
this.permissions = permissions;
|
|
35
|
+
this.tools = tools;
|
|
36
|
+
}
|
|
37
|
+
/** The authority for a run by `user` in `workspaceId`. */
|
|
38
|
+
async resolve(user, workspaceId, signal) {
|
|
39
|
+
const granted = new Set(await this.permissions.forRole(user.roleId));
|
|
40
|
+
// `kind: 'user'` is what separates a run from an MCP call in every
|
|
41
|
+
// handler that cares — and `userId` is the *same* id here, because the
|
|
42
|
+
// copilot has no identity of its own and a run acts as the person
|
|
43
|
+
// driving it (ADR-0005 §1).
|
|
44
|
+
const actor = {
|
|
45
|
+
kind: 'user',
|
|
46
|
+
id: user.id,
|
|
47
|
+
displayName: user.email,
|
|
48
|
+
grantedPermissions: granted,
|
|
49
|
+
userId: user.id
|
|
50
|
+
};
|
|
51
|
+
const context = {
|
|
52
|
+
...(0, tools_server_1.createToolContext)(actor, workspaceId),
|
|
53
|
+
...(signal ? { signal } : {})
|
|
54
|
+
};
|
|
55
|
+
const copilotActor = {
|
|
56
|
+
userId: user.id,
|
|
57
|
+
grantedPermissions: granted
|
|
58
|
+
};
|
|
59
|
+
const profile = (0, copilot_domain_1.resolveCapabilityProfile)({
|
|
60
|
+
// The registry authorizes; this decides what to *offer*. Passing
|
|
61
|
+
// the whole surface rather than `visibleTo` keeps the withheld
|
|
62
|
+
// reasons — "you lack content:update" is what the settings page
|
|
63
|
+
// shows, and a pre-filtered list cannot say it.
|
|
64
|
+
tools: this.tools.forSurface('copilot'),
|
|
65
|
+
actor: copilotActor
|
|
66
|
+
});
|
|
67
|
+
return { profile, context };
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
exports.CapabilityProfileService = CapabilityProfileService;
|
|
71
|
+
exports.CapabilityProfileService = CapabilityProfileService = tslib_1.__decorate([
|
|
72
|
+
(0, common_1.Injectable)(),
|
|
73
|
+
tslib_1.__metadata("design:paramtypes", [identity_server_1.PermissionsService,
|
|
74
|
+
tools_server_1.ToolRegistry])
|
|
75
|
+
], CapabilityProfileService);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Database } from '@orthacms/database';
|
|
2
|
+
import { type ContentCatalog } from '@orthacms/workspaces-server';
|
|
3
|
+
/**
|
|
4
|
+
* The content-type summaries the system prompt is built from — `name — label
|
|
5
|
+
* (kind)` for each type the open workspace was actually granted.
|
|
6
|
+
*
|
|
7
|
+
* Two deliberate choices about where this reads from:
|
|
8
|
+
*
|
|
9
|
+
* - **The catalogue comes through `CONTENT_CATALOG`, not `content-server`.**
|
|
10
|
+
* That port already exists for exactly this shape of question, and it is
|
|
11
|
+
* owned by `workspaces-server`, which this package already depends on for
|
|
12
|
+
* `WorkspaceGuard`. Importing `content-server` here would put the copilot at
|
|
13
|
+
* the bottom of the package graph, which `docs/design/copilot.md` §4 rules
|
|
14
|
+
* out. Injected `@Optional()`: a deployment with no content plugin gets an
|
|
15
|
+
* empty list and a copilot that says so, rather than a boot failure.
|
|
16
|
+
* - **The grants come from `workspace_content` directly**, mirroring
|
|
17
|
+
* `content-server`'s own `WorkspaceGrantsQuery`. That table is workspaces-
|
|
18
|
+
* owned and its schema is deliberately re-exported; inverting it into another
|
|
19
|
+
* port would mean workspaces depending on copilot.
|
|
20
|
+
*
|
|
21
|
+
* Scoping to grants matters: the prompt must not name a type the workspace
|
|
22
|
+
* cannot reach, or the model will confidently offer to search something every
|
|
23
|
+
* tool call will then refuse.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ContentTypeSummaryService {
|
|
26
|
+
private readonly db;
|
|
27
|
+
private readonly catalogue;
|
|
28
|
+
constructor(db: Database, catalogue?: ContentCatalog | null);
|
|
29
|
+
/** Summaries for the types `workspaceId` was granted, in catalogue order. */
|
|
30
|
+
summaries(workspaceId: string): Promise<string[]>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=content-type-summary.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type-summary.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/chat/application/content-type-summary.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAGH,KAAK,cAAc,EACtB,MAAM,6BAA6B,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,yBAAyB;IAEZ,OAAO,CAAC,QAAQ,CAAC,EAAE;IAGrC,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAHS,EAAE,EAAE,QAAQ,EAG9B,SAAS,GAAE,cAAc,GAAG,IAAW;IAG5D,6EAA6E;IACvE,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAsB1D"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentTypeSummaryService = 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 workspaces_server_1 = require("@orthacms/workspaces-server");
|
|
9
|
+
/**
|
|
10
|
+
* The content-type summaries the system prompt is built from — `name — label
|
|
11
|
+
* (kind)` for each type the open workspace was actually granted.
|
|
12
|
+
*
|
|
13
|
+
* Two deliberate choices about where this reads from:
|
|
14
|
+
*
|
|
15
|
+
* - **The catalogue comes through `CONTENT_CATALOG`, not `content-server`.**
|
|
16
|
+
* That port already exists for exactly this shape of question, and it is
|
|
17
|
+
* owned by `workspaces-server`, which this package already depends on for
|
|
18
|
+
* `WorkspaceGuard`. Importing `content-server` here would put the copilot at
|
|
19
|
+
* the bottom of the package graph, which `docs/design/copilot.md` §4 rules
|
|
20
|
+
* out. Injected `@Optional()`: a deployment with no content plugin gets an
|
|
21
|
+
* empty list and a copilot that says so, rather than a boot failure.
|
|
22
|
+
* - **The grants come from `workspace_content` directly**, mirroring
|
|
23
|
+
* `content-server`'s own `WorkspaceGrantsQuery`. That table is workspaces-
|
|
24
|
+
* owned and its schema is deliberately re-exported; inverting it into another
|
|
25
|
+
* port would mean workspaces depending on copilot.
|
|
26
|
+
*
|
|
27
|
+
* Scoping to grants matters: the prompt must not name a type the workspace
|
|
28
|
+
* cannot reach, or the model will confidently offer to search something every
|
|
29
|
+
* tool call will then refuse.
|
|
30
|
+
*/
|
|
31
|
+
let ContentTypeSummaryService = class ContentTypeSummaryService {
|
|
32
|
+
db;
|
|
33
|
+
catalogue;
|
|
34
|
+
constructor(db, catalogue = null) {
|
|
35
|
+
this.db = db;
|
|
36
|
+
this.catalogue = catalogue;
|
|
37
|
+
}
|
|
38
|
+
/** Summaries for the types `workspaceId` was granted, in catalogue order. */
|
|
39
|
+
async summaries(workspaceId) {
|
|
40
|
+
if (!this.catalogue) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const rows = await this.db
|
|
44
|
+
.select({ slug: workspaces_server_1.workspaceContent.slug })
|
|
45
|
+
.from(workspaces_server_1.workspaceContent)
|
|
46
|
+
.where((0, drizzle_orm_1.eq)(workspaces_server_1.workspaceContent.workspaceId, workspaceId));
|
|
47
|
+
const granted = new Set(rows.map((row) => row.slug));
|
|
48
|
+
// An empty grant set means "no access", never "no filtering" — the
|
|
49
|
+
// same rule WorkspaceGrantsQuery documents. Getting this backwards
|
|
50
|
+
// would describe every type in the deployment to every workspace.
|
|
51
|
+
return this.catalogue
|
|
52
|
+
.list()
|
|
53
|
+
.filter((type) => granted.has(type.name))
|
|
54
|
+
.map((type) => `${type.name} — ${type.label ?? type.name} (${type.kind})`);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
exports.ContentTypeSummaryService = ContentTypeSummaryService;
|
|
58
|
+
exports.ContentTypeSummaryService = ContentTypeSummaryService = tslib_1.__decorate([
|
|
59
|
+
(0, common_1.Injectable)(),
|
|
60
|
+
tslib_1.__param(0, (0, database_1.InjectDatabase)()),
|
|
61
|
+
tslib_1.__param(1, (0, common_1.Optional)()),
|
|
62
|
+
tslib_1.__param(1, (0, common_1.Inject)(workspaces_server_1.CONTENT_CATALOG)),
|
|
63
|
+
tslib_1.__metadata("design:paramtypes", [Object, Object])
|
|
64
|
+
], ContentTypeSummaryService);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ProposalRepository, type ProposalView } from '../infrastructure/persistence/proposal.repository';
|
|
2
|
+
import { ProposalApplierRegistry } from './proposal-applier.registry';
|
|
3
|
+
/** Who the change is made by, and where. */
|
|
4
|
+
export interface Applicant {
|
|
5
|
+
userId: string;
|
|
6
|
+
/** The actor's email — frozen onto the audit event the write raises. */
|
|
7
|
+
email: string;
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
}
|
|
10
|
+
/** Why a change could not be carried out. */
|
|
11
|
+
export type ApplyRefusal =
|
|
12
|
+
/** Someone already applied it. */
|
|
13
|
+
'already-decided'
|
|
14
|
+
/** No plugin claimed this proposal's kind — a wiring bug, not a user error. */
|
|
15
|
+
| 'no-applier'
|
|
16
|
+
/** The applier ran and failed; the proposal stays pending. */
|
|
17
|
+
| 'apply-failed';
|
|
18
|
+
/** The outcome of an apply. */
|
|
19
|
+
export type ApplyOutcome = {
|
|
20
|
+
ok: true;
|
|
21
|
+
proposal: ProposalView;
|
|
22
|
+
} | {
|
|
23
|
+
ok: false;
|
|
24
|
+
reason: ApplyRefusal;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Applies a proposal through the plugin that owns it.
|
|
29
|
+
*
|
|
30
|
+
* **There is no human step any more**
|
|
31
|
+
* ([ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)).
|
|
32
|
+
* This used to be the accept boundary — `accept`, `reject`, and a re-resolution
|
|
33
|
+
* of the capability profile deciding whether the clicker could have proposed
|
|
34
|
+
* the change themselves. All three are gone: the engine calls {@link apply} the
|
|
35
|
+
* moment a `propose` tool returns, and the only authority check is the one the
|
|
36
|
+
* offer and the tool call already made against the caller's own grants.
|
|
37
|
+
*
|
|
38
|
+
* What survives, and why each still earns its place:
|
|
39
|
+
*
|
|
40
|
+
* - **Applying runs the ordinary use-case.** This service never writes the
|
|
41
|
+
* change itself; it hands the proposal to the plugin that owns it. Same
|
|
42
|
+
* validation, same revision, same activity row, with the human as actor. That
|
|
43
|
+
* is what makes a copilot change indistinguishable from a hand-made one in
|
|
44
|
+
* the audit log — and it is what "undoable, never invisible" now rests on
|
|
45
|
+
* entirely, since nothing pauses to be looked at first.
|
|
46
|
+
* - **The status flips first, and only once.** `decide` updates with a
|
|
47
|
+
* `status = 'pending'` predicate, so the applier is unreachable twice for the
|
|
48
|
+
* same row. That still matters with no reviewers in the picture: a model that
|
|
49
|
+
* re-proposes an identical change, or a retried run, must not write twice.
|
|
50
|
+
* - **A failed apply reopens the row** with the message recorded. Nobody will
|
|
51
|
+
* retry it, so this is a receipt saying the change did not happen — the run
|
|
52
|
+
* engine reads it back and tells the model to say so rather than claim
|
|
53
|
+
* success.
|
|
54
|
+
*/
|
|
55
|
+
export declare class DecideProposalService {
|
|
56
|
+
private readonly proposals;
|
|
57
|
+
private readonly appliers;
|
|
58
|
+
private readonly logger;
|
|
59
|
+
constructor(proposals: ProposalRepository, appliers: ProposalApplierRegistry);
|
|
60
|
+
/**
|
|
61
|
+
* Applies a freshly drafted proposal.
|
|
62
|
+
*
|
|
63
|
+
* No permission check of its own, and that is not an omission: the
|
|
64
|
+
* capability profile offered the tool at the start of the run, and
|
|
65
|
+
* `executeTool` re-authorized it against a freshly resolved session
|
|
66
|
+
* immediately before this proposal existed. Re-resolving a third time in
|
|
67
|
+
* the same millisecond would only add a query.
|
|
68
|
+
*/
|
|
69
|
+
apply(proposal: ProposalView, by: Applicant): Promise<ApplyOutcome>;
|
|
70
|
+
/**
|
|
71
|
+
* Flips the status, then hands the change to its owner.
|
|
72
|
+
*
|
|
73
|
+
* The order matters: the `pending` predicate on the update is what makes
|
|
74
|
+
* the apply happen at most once, so it has to win the race *before* the
|
|
75
|
+
* write runs. A failure afterwards returns the row to `pending` with the
|
|
76
|
+
* reason; the alternative — apply first, record after — can apply twice.
|
|
77
|
+
*/
|
|
78
|
+
private applyThroughOwner;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=decide-proposal.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide-proposal.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/chat/application/decide-proposal.service.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,kBAAkB,EAClB,KAAK,YAAY,EACpB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,MAAM,YAAY;AACpB,kCAAkC;AAChC,iBAAiB;AACnB,+EAA+E;GAC7E,YAAY;AACd,8DAA8D;GAC5D,cAAc,CAAC;AAErB,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAClB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBACa,qBAAqB;IAI1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJ7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;gBAG5C,SAAS,EAAE,kBAAkB,EAC7B,QAAQ,EAAE,uBAAuB;IAGtD;;;;;;;;OAQG;IACG,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBzE;;;;;;;OAOG;YACW,iBAAiB;CAmDlC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var DecideProposalService_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DecideProposalService = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const proposal_repository_1 = require("../infrastructure/persistence/proposal.repository");
|
|
8
|
+
const proposal_applier_registry_1 = require("./proposal-applier.registry");
|
|
9
|
+
/**
|
|
10
|
+
* Applies a proposal through the plugin that owns it.
|
|
11
|
+
*
|
|
12
|
+
* **There is no human step any more**
|
|
13
|
+
* ([ADR-0009](../../../../../../docs/adr/0009-copilot-applies-directly.md)).
|
|
14
|
+
* This used to be the accept boundary — `accept`, `reject`, and a re-resolution
|
|
15
|
+
* of the capability profile deciding whether the clicker could have proposed
|
|
16
|
+
* the change themselves. All three are gone: the engine calls {@link apply} the
|
|
17
|
+
* moment a `propose` tool returns, and the only authority check is the one the
|
|
18
|
+
* offer and the tool call already made against the caller's own grants.
|
|
19
|
+
*
|
|
20
|
+
* What survives, and why each still earns its place:
|
|
21
|
+
*
|
|
22
|
+
* - **Applying runs the ordinary use-case.** This service never writes the
|
|
23
|
+
* change itself; it hands the proposal to the plugin that owns it. Same
|
|
24
|
+
* validation, same revision, same activity row, with the human as actor. That
|
|
25
|
+
* is what makes a copilot change indistinguishable from a hand-made one in
|
|
26
|
+
* the audit log — and it is what "undoable, never invisible" now rests on
|
|
27
|
+
* entirely, since nothing pauses to be looked at first.
|
|
28
|
+
* - **The status flips first, and only once.** `decide` updates with a
|
|
29
|
+
* `status = 'pending'` predicate, so the applier is unreachable twice for the
|
|
30
|
+
* same row. That still matters with no reviewers in the picture: a model that
|
|
31
|
+
* re-proposes an identical change, or a retried run, must not write twice.
|
|
32
|
+
* - **A failed apply reopens the row** with the message recorded. Nobody will
|
|
33
|
+
* retry it, so this is a receipt saying the change did not happen — the run
|
|
34
|
+
* engine reads it back and tells the model to say so rather than claim
|
|
35
|
+
* success.
|
|
36
|
+
*/
|
|
37
|
+
let DecideProposalService = DecideProposalService_1 = class DecideProposalService {
|
|
38
|
+
proposals;
|
|
39
|
+
appliers;
|
|
40
|
+
logger = new common_1.Logger(DecideProposalService_1.name);
|
|
41
|
+
constructor(proposals, appliers) {
|
|
42
|
+
this.proposals = proposals;
|
|
43
|
+
this.appliers = appliers;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Applies a freshly drafted proposal.
|
|
47
|
+
*
|
|
48
|
+
* No permission check of its own, and that is not an omission: the
|
|
49
|
+
* capability profile offered the tool at the start of the run, and
|
|
50
|
+
* `executeTool` re-authorized it against a freshly resolved session
|
|
51
|
+
* immediately before this proposal existed. Re-resolving a third time in
|
|
52
|
+
* the same millisecond would only add a query.
|
|
53
|
+
*/
|
|
54
|
+
async apply(proposal, by) {
|
|
55
|
+
const applier = this.appliers.get(proposal.kind);
|
|
56
|
+
if (!applier) {
|
|
57
|
+
// A deployment wiring bug rather than a user error, so it is logged
|
|
58
|
+
// loudly and the row is left pending — the change is still valid,
|
|
59
|
+
// and it becomes applicable again the moment the binder is fixed.
|
|
60
|
+
this.logger.error(`No applier registered for proposal kind "${proposal.kind}"; ` +
|
|
61
|
+
`proposal ${proposal.id} was not applied.`);
|
|
62
|
+
return refuse('no-applier', 'This kind of change cannot be applied by this deployment.');
|
|
63
|
+
}
|
|
64
|
+
return this.applyThroughOwner(proposal, applier, by);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Flips the status, then hands the change to its owner.
|
|
68
|
+
*
|
|
69
|
+
* The order matters: the `pending` predicate on the update is what makes
|
|
70
|
+
* the apply happen at most once, so it has to win the race *before* the
|
|
71
|
+
* write runs. A failure afterwards returns the row to `pending` with the
|
|
72
|
+
* reason; the alternative — apply first, record after — can apply twice.
|
|
73
|
+
*/
|
|
74
|
+
async applyThroughOwner(proposal, applier, by) {
|
|
75
|
+
const claimed = await this.proposals.decide(proposal.id, by.workspaceId, 'accepted', by.userId);
|
|
76
|
+
if (!claimed) {
|
|
77
|
+
return refuse('already-decided', 'This change was already applied.');
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const result = await applier.apply({ target: proposal.target, patch: proposal.patch }, {
|
|
81
|
+
userId: by.userId,
|
|
82
|
+
actorEmail: by.email,
|
|
83
|
+
workspaceId: by.workspaceId,
|
|
84
|
+
runId: proposal.runId
|
|
85
|
+
});
|
|
86
|
+
// A second write rather than folding the result into the status
|
|
87
|
+
// transition: that transition only matches a `pending` row, and
|
|
88
|
+
// this one is now `accepted` by design — the claim is what makes
|
|
89
|
+
// the apply happen at most once.
|
|
90
|
+
const finished = await this.proposals.recordResult(proposal.id, by.workspaceId, { ...result });
|
|
91
|
+
return { ok: true, proposal: finished ?? claimed };
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
const message = error instanceof Error && error.message
|
|
95
|
+
? error.message
|
|
96
|
+
: 'The change could not be applied.';
|
|
97
|
+
this.logger.warn(`Applying proposal ${proposal.id} (${proposal.kind}) failed: ${message}`);
|
|
98
|
+
await this.proposals.reopen(proposal.id, by.workspaceId, message);
|
|
99
|
+
return refuse('apply-failed', message);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
exports.DecideProposalService = DecideProposalService;
|
|
104
|
+
exports.DecideProposalService = DecideProposalService = DecideProposalService_1 = tslib_1.__decorate([
|
|
105
|
+
(0, common_1.Injectable)(),
|
|
106
|
+
tslib_1.__metadata("design:paramtypes", [proposal_repository_1.ProposalRepository,
|
|
107
|
+
proposal_applier_registry_1.ProposalApplierRegistry])
|
|
108
|
+
], DecideProposalService);
|
|
109
|
+
/** A refusal, with the message the run engine reports to the model. */
|
|
110
|
+
function refuse(reason, message) {
|
|
111
|
+
return { ok: false, reason, message };
|
|
112
|
+
}
|