@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
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
@@ -0,0 +1,7 @@
1
+ # @orthacms/copilot-server
2
+
3
+ Part of [Ortha CMS](https://github.com/ortha-source/ortha-cms).
4
+
5
+ ```sh
6
+ npm install @orthacms/copilot-server
7
+ ```
@@ -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
+ }