@prodero/curator 0.0.0-stage → 0.2.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 (148) hide show
  1. package/ARCHITECTURE.md +298 -0
  2. package/CHANGELOG.md +33 -0
  3. package/CONTRIBUTING.md +9 -0
  4. package/LICENSE +21 -0
  5. package/README.md +93 -2
  6. package/SECURITY.md +7 -0
  7. package/bin/prodero +7 -0
  8. package/dist/cli.js +266 -0
  9. package/dist/context-instructions.js +2 -0
  10. package/dist/contracts.js +51 -0
  11. package/dist/conversation-presentation.js +297 -0
  12. package/dist/core/agent-instructions.js +52 -0
  13. package/dist/core/applicability-label.js +11 -0
  14. package/dist/core/applicability.js +143 -0
  15. package/dist/core/bootstrap.js +129 -0
  16. package/dist/core/consolidation.js +315 -0
  17. package/dist/core/constants.js +21 -0
  18. package/dist/core/context-allocation.js +54 -0
  19. package/dist/core/context-snapshot.js +12 -0
  20. package/dist/core/context.js +489 -0
  21. package/dist/core/curation-clauses.js +68 -0
  22. package/dist/core/curation-evidence.js +98 -0
  23. package/dist/core/curation-graphical.js +117 -0
  24. package/dist/core/curation-question.js +28 -0
  25. package/dist/core/curation-review-presentation.js +4 -0
  26. package/dist/core/curation-review-state.js +62 -0
  27. package/dist/core/curation-review.js +573 -0
  28. package/dist/core/curation-revision.js +106 -0
  29. package/dist/core/curation-semantic-contract.js +242 -0
  30. package/dist/core/curation-semantic-jobs.js +340 -0
  31. package/dist/core/diagnostics.js +17 -0
  32. package/dist/core/format.js +114 -0
  33. package/dist/core/ids.js +6 -0
  34. package/dist/core/imports.js +169 -0
  35. package/dist/core/index.js +93 -0
  36. package/dist/core/instruction-review.js +86 -0
  37. package/dist/core/integrity-files.js +174 -0
  38. package/dist/core/intelligence.js +95 -0
  39. package/dist/core/knowledge-analysis.js +46 -0
  40. package/dist/core/knowledge-authority.js +143 -0
  41. package/dist/core/knowledge-curation.js +316 -0
  42. package/dist/core/knowledge-engine.js +475 -0
  43. package/dist/core/knowledge-graph.js +192 -0
  44. package/dist/core/knowledge-lifecycle.js +212 -0
  45. package/dist/core/knowledge-management.js +113 -0
  46. package/dist/core/knowledge-migration.js +84 -0
  47. package/dist/core/knowledge-policy.js +38 -0
  48. package/dist/core/knowledge-provenance.js +90 -0
  49. package/dist/core/knowledge-write-policy.js +85 -0
  50. package/dist/core/language.js +14 -0
  51. package/dist/core/local-preferences.js +76 -0
  52. package/dist/core/matching.js +6 -0
  53. package/dist/core/memory-index.js +241 -0
  54. package/dist/core/memory-intelligence.js +288 -0
  55. package/dist/core/memory-link-repair.js +70 -0
  56. package/dist/core/memory-operations.js +122 -0
  57. package/dist/core/memory-pressure.js +212 -0
  58. package/dist/core/memory-sync-curator.js +82 -0
  59. package/dist/core/memory-sync.js +558 -0
  60. package/dist/core/memory-transformation-bundle.js +163 -0
  61. package/dist/core/memory-transformation-proposal.js +135 -0
  62. package/dist/core/memory-transformation.js +108 -0
  63. package/dist/core/memory.js +186 -0
  64. package/dist/core/migrations.js +569 -0
  65. package/dist/core/npm-update.js +289 -0
  66. package/dist/core/path-scope.js +27 -0
  67. package/dist/core/plugin-files.js +116 -0
  68. package/dist/core/project-root.js +39 -0
  69. package/dist/core/project.js +634 -0
  70. package/dist/core/promotion.js +279 -0
  71. package/dist/core/reconciliation.js +61 -0
  72. package/dist/core/secrets.js +67 -0
  73. package/dist/core/semantic-safety.js +33 -0
  74. package/dist/core/session-index.js +116 -0
  75. package/dist/core/session-review.js +150 -0
  76. package/dist/core/sessions.js +289 -0
  77. package/dist/core/settings.js +94 -0
  78. package/dist/core/skill-curation.js +239 -0
  79. package/dist/core/skill-polish.js +41 -0
  80. package/dist/core/skills.js +387 -0
  81. package/dist/core/storage.js +462 -0
  82. package/dist/core/sync-transaction.js +290 -0
  83. package/dist/core/telemetry.js +64 -0
  84. package/dist/core/templates.js +53 -0
  85. package/dist/core/types.js +2 -0
  86. package/dist/core/update.js +326 -0
  87. package/dist/curation-review-adapter.js +92 -0
  88. package/dist/diagnostic-boundary.js +55 -0
  89. package/dist/filesystem/permissions.js +39 -0
  90. package/dist/hosts/adapters.js +119 -0
  91. package/dist/hosts/files.js +133 -0
  92. package/dist/hosts/manager.js +150 -0
  93. package/dist/hosts/public-entry.js +47 -0
  94. package/dist/hosts/runtime-command.js +66 -0
  95. package/dist/hosts/runtime.js +139 -0
  96. package/dist/hosts/wizard.js +114 -0
  97. package/dist/knowledge-table.js +38 -0
  98. package/dist/mcp-development.js +69 -0
  99. package/dist/mcp-workspace.js +141 -0
  100. package/dist/memory-presentation.js +182 -0
  101. package/dist/memory-sync-operation.js +88 -0
  102. package/dist/plugins/api.js +2 -0
  103. package/dist/plugins/context.js +20 -0
  104. package/dist/plugins/mcp.js +72 -0
  105. package/dist/plugins/registry.js +106 -0
  106. package/dist/presentation-cards.js +32 -0
  107. package/dist/presentation-server.js +94 -0
  108. package/dist/presentation-trace.js +174 -0
  109. package/dist/presentation.js +443 -0
  110. package/dist/providers/mcp-sampling.js +45 -0
  111. package/dist/server.js +664 -0
  112. package/dist/settings-definition.js +22 -0
  113. package/dist/skill-instructions.js +2 -0
  114. package/dist/status-presentation.js +20 -0
  115. package/dist/text-layout.js +278 -0
  116. package/dist/update-command.js +53 -0
  117. package/dist/update-instructions.js +4 -0
  118. package/dist-ui/index.html +216 -0
  119. package/docs/APPLICABILITY.md +151 -0
  120. package/docs/COMPATIBILITY.md +68 -0
  121. package/docs/CONTEXT-SELECTION-V2.md +61 -0
  122. package/docs/CURATION-APP-REVIEW.md +156 -0
  123. package/docs/CURATION-CLAUSE-REFINEMENT.md +45 -0
  124. package/docs/IMPORTER-CURATION.md +142 -0
  125. package/docs/KNOWLEDGE-AUTHORITY.md +165 -0
  126. package/docs/KNOWLEDGE-SCHEMA-V2.md +150 -0
  127. package/docs/MIGRATIONS.md +103 -0
  128. package/docs/PRIVACY.md +28 -0
  129. package/docs/RECOVERY.md +58 -0
  130. package/docs/RELEASING.md +98 -0
  131. package/docs/hosts.md +152 -0
  132. package/docs/images/prodero-context-ready-cropped.png +0 -0
  133. package/docs/images/prodero-overview-cropped.png +0 -0
  134. package/docs/images/prodero-session-learned-cropped.png +0 -0
  135. package/docs/plugins.md +83 -0
  136. package/docs/ui-themes.md +49 -0
  137. package/instructions/AGENTS.md +39 -0
  138. package/package.json +92 -4
  139. package/plugins/migrate_ai_studio/README.md +101 -0
  140. package/plugins/migrate_ai_studio/index.cjs +396 -0
  141. package/plugins/migrate_ai_studio/instructions/audit.md +25 -0
  142. package/plugins/migrate_ai_studio/instructions/classify.md +41 -0
  143. package/plugins/migrate_ai_studio/instructions/migrate.md +34 -0
  144. package/plugins/migrate_ai_studio/instructions/verify.md +20 -0
  145. package/plugins/migrate_ai_studio/plugin.json +11 -0
  146. package/plugins/migrate_ai_studio/schema.cjs +20 -0
  147. package/plugins/migrate_ai_studio/ui/dist/index.html +77 -0
  148. package/prodero.release.json +5 -0
package/dist/cli.js ADDED
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { pathToFileURL } from "node:url";
4
+ import { captureLocalStdioContext } from "./mcp-workspace.js";
5
+ import { planProjectMigration, applyProjectMigration } from "./core/migrations.js";
6
+ import { buildViewModel, renderText } from "./presentation.js";
7
+ import { runMemorySync } from './core/memory-sync.js';
8
+ import { machineIntegrations } from "./hosts/manager.js";
9
+ import { installWizard } from "./hosts/wizard.js";
10
+ import { runtimeCommand } from "./hosts/runtime-command.js";
11
+ import { buildMemoryTransformationBundle } from "./core/memory-transformation-bundle.js";
12
+ import { getMemoryIntelligencePlan } from "./core/memory-intelligence.js";
13
+ import { publicDiagnostic } from "./core/diagnostics.js";
14
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
+ import { createServer } from "./server.js";
16
+ import { getProjectStatus, initializeProject, prepareProject, recallProject, PRODERO_VERSION, resolveProjectContext, syncProject, } from "./core/project.js";
17
+ import { cliProjectRoot, explicitProjectRoot } from "./core/project-root.js";
18
+ import { renderMachineStatus, renderProjectStatus, renderStatusFailure, statusFailure } from "./status-presentation.js";
19
+ import { updateCommand } from "./update-command.js";
20
+ import { checkForUpdate } from "./core/update.js";
21
+ const help = `Prodero ${PRODERO_VERSION}
22
+
23
+ Usage: prodero <command> [--root /absolute/project]
24
+ mcp, --stdio Start MCP in the host workspace; --dev loads the saved development runtime
25
+ migrate [status] Review or apply the project knowledge update with backup
26
+ init Initialize the selected project
27
+ install Open the interactive agent installation wizard
28
+ runtime <mode> --host HOST Switch one agent between package and dev (runtime --help)
29
+ uninstall [host] [--all] Remove managed host integration; preserve projects
30
+ status [--json] Show readable machine integrations; --json for scripts
31
+ status --root PATH [--json] Show existing project status without maintenance
32
+ memory-bundle <id> Inspect one read-only transformation bundle (JSON)
33
+ memory-plan Inspect deterministic memory candidates (read-only JSON)
34
+ sync Start/resume Curate Memory (JSON; continue through MCP)
35
+ sync-sessions Low-level deterministic closed-session recovery
36
+ recall <query> Recall project knowledge without a session
37
+ context [query] Inspect retrieved context
38
+ prepare [task] Prepare context and start a session
39
+ check-update Show installed/latest npm version and update instruction
40
+ update [version] [--yes] Update this npm installation from the terminal
41
+ help, --help Show this help
42
+ --version Show the installed version
43
+
44
+ --root accepts an absolute existing directory, as --root PATH or --root=PATH.
45
+ Without --root, project commands require a Git or initialized Prodero ancestor.
46
+ MCP uses negotiated host roots or supported local host launch context. --root is an optional hard boundary.`;
47
+ function parse(argv) {
48
+ let command, root, query;
49
+ let helpRequested = false, all = false, dev = false, json = false, checkout, host;
50
+ const commands = new Set(["install", "uninstall", "mcp", "--stdio", "init", "migrate", "status", "memory-plan", "memory-bundle", "sync", "sync-sessions", "context", "recall", "prepare", "check-update", "update", "help", "--version"]);
51
+ for (let i = 0; i < argv.length; i++) {
52
+ const arg = argv[i];
53
+ if (arg === "--help" || arg === "-h") {
54
+ helpRequested = true;
55
+ continue;
56
+ }
57
+ if (arg === "--json") {
58
+ if (json)
59
+ throw new Error("Specify --json only once.");
60
+ json = true;
61
+ continue;
62
+ }
63
+ if (arg === "--dev") {
64
+ if (dev)
65
+ throw new Error("Specify --dev only once.");
66
+ dev = true;
67
+ continue;
68
+ }
69
+ if (arg === "--checkout") {
70
+ if (checkout !== undefined)
71
+ throw new Error("Specify --checkout only once.");
72
+ checkout = argv[++i];
73
+ if (!checkout || checkout.startsWith("--"))
74
+ throw new Error("--checkout requires a directory.");
75
+ continue;
76
+ }
77
+ if (arg === "--all") {
78
+ if (all)
79
+ throw new Error("Specify --all only once.");
80
+ all = true;
81
+ continue;
82
+ }
83
+ if (arg === "--root" || arg.startsWith("--root=")) {
84
+ if (root !== undefined)
85
+ throw new Error("Specify --root only once.");
86
+ root = arg === "--root" ? argv[++i] : arg.slice(7);
87
+ if (!root || root.startsWith("--"))
88
+ throw new Error("--root requires an absolute project directory.");
89
+ }
90
+ else if (!command && commands.has(arg))
91
+ command = arg;
92
+ else if (arg.startsWith("-"))
93
+ throw new Error("Unknown flag. Run prodero --help.");
94
+ else if (!command)
95
+ throw new Error("Unknown command. Run prodero --help.");
96
+ else if (command === "install")
97
+ throw new Error("Run prodero install without arguments; choose an agent in the interactive wizard.");
98
+ else if (command === "uninstall" && host === undefined)
99
+ host = arg;
100
+ else if (["migrate", "prepare", "context", "recall", "memory-bundle"].includes(command) && query === undefined)
101
+ query = arg;
102
+ else
103
+ throw new Error("Unexpected argument. Run prodero --help.");
104
+ }
105
+ command ??= "help";
106
+ if (json && (command !== "status" || helpRequested))
107
+ throw new Error("Use --json only with status, without --help.");
108
+ if (all && command === "install")
109
+ throw new Error("Run prodero install without --all; choose an agent in the interactive wizard.");
110
+ if (all && (command !== "uninstall" || host))
111
+ throw new Error("Use --all only with uninstall and without a host name.");
112
+ if (root !== undefined && ["install", "uninstall", "help", "--version", "check-update", "update"].includes(command))
113
+ throw new Error(`--root is not used by ${command}.`);
114
+ if ((dev || checkout !== undefined) && !["mcp", "--stdio"].includes(command))
115
+ throw new Error("--dev and --checkout are only supported for MCP.");
116
+ if (checkout !== undefined && !dev)
117
+ throw new Error("--checkout requires --dev.");
118
+ return { dev, checkout, json, command: helpRequested ? "help" : command, root, query, host: all ? "all" : host };
119
+ }
120
+ async function run(localStdio) {
121
+ if (process.argv[2] === 'update') {
122
+ process.exitCode = await updateCommand(process.argv.slice(3));
123
+ return;
124
+ }
125
+ if (process.argv[2] === 'runtime') {
126
+ await runtimeCommand(process.argv.slice(3));
127
+ return;
128
+ }
129
+ const { command, root, query, host, dev, checkout, json } = parse(process.argv.slice(2));
130
+ if (command === "help") {
131
+ console.log(help);
132
+ return;
133
+ }
134
+ if (command === "--version") {
135
+ console.log(PRODERO_VERSION);
136
+ return;
137
+ }
138
+ if (command === "install") {
139
+ process.exitCode = await installWizard();
140
+ return;
141
+ }
142
+ if (command === "uninstall" || (command === "status" && root === undefined)) {
143
+ const result = await machineIntegrations(command === "status" ? "status" : command, host);
144
+ console.log(command === "status" && !json ? renderMachineStatus(result) : JSON.stringify(result, null, 2));
145
+ if (!result.ok)
146
+ process.exitCode = 1;
147
+ return;
148
+ }
149
+ if (command === "mcp" || command === "--stdio")
150
+ localStdio ??= captureLocalStdioContext();
151
+ const rootArg = command === "mcp" || command === "--stdio" ? (root === undefined ? undefined : await explicitProjectRoot(root)) : ["update", "check-update"].includes(command) ? undefined : await cliProjectRoot(root);
152
+ if (command === "--stdio" || command === "mcp") {
153
+ if (dev) {
154
+ const { startDevelopmentRuntime } = await import('./mcp-development.js');
155
+ await startDevelopmentRuntime(localStdio, { projectRoot: rootArg, checkout });
156
+ return;
157
+ }
158
+ const server = createServer({ projectRoot: rootArg, localStdio });
159
+ await server.connect(new StdioServerTransport());
160
+ return;
161
+ }
162
+ if (command === "migrate") {
163
+ if (query && query !== "status")
164
+ throw new Error("Use prodero migrate or prodero migrate status.");
165
+ let plan = await planProjectMigration(rootArg);
166
+ if (query !== "status" && (plan.safeToApply || plan.state === "recovery-required")) {
167
+ const result = await applyProjectMigration(rootArg, { approved: true, planId: plan.planId, recover: plan.state === "recovery-required" });
168
+ plan = result.plan;
169
+ }
170
+ console.log(renderText(buildViewModel({ action: "migration", root: rootArg, plan }), true));
171
+ if (plan.blocked)
172
+ process.exitCode = 1;
173
+ return;
174
+ }
175
+ if (command === "init") {
176
+ console.log(JSON.stringify(await initializeProject(rootArg), null, 2));
177
+ return;
178
+ }
179
+ if (command === "prepare") {
180
+ const plan = await planProjectMigration(rootArg);
181
+ if (plan.state !== "current") {
182
+ (plan.blocked ? console.error : console.log)(renderText(buildViewModel({ action: "migration", root: rootArg, plan, resume: { tool: "prodero_prepare", arguments: { projectRoot: rootArg, task: query } } }), true));
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ }
187
+ if (command === "status") {
188
+ const plan = await planProjectMigration(rootArg);
189
+ if (plan.state !== "current") {
190
+ const result = statusFailure(plan.diagnostic ?? `PRODERO_MIGRATION_REQUIRED: Project update is ${plan.state}.`, "project", plan);
191
+ (json ? console.log : console.error)(json ? JSON.stringify(result, null, 2) : renderStatusFailure(result));
192
+ process.exitCode = 1;
193
+ return;
194
+ }
195
+ const result = { version: PRODERO_VERSION, scope: "project", project: await getProjectStatus(rootArg, { persistCache: false }), update: await checkForUpdate() };
196
+ console.log(json ? JSON.stringify(result, null, 2) : renderProjectStatus(result));
197
+ return;
198
+ }
199
+ if (command === "memory-bundle") {
200
+ if (!query)
201
+ throw new Error("memory-bundle requires one planner candidate ID");
202
+ console.log(JSON.stringify(await buildMemoryTransformationBundle(rootArg, query)));
203
+ return;
204
+ }
205
+ if (command === "memory-plan") {
206
+ console.log(JSON.stringify(await getMemoryIntelligencePlan(rootArg), null, 2));
207
+ return;
208
+ }
209
+ if (command === "sync") {
210
+ console.log(JSON.stringify(await runMemorySync(rootArg, { action: "start" }), null, 2));
211
+ return;
212
+ }
213
+ if (command === "sync-sessions") {
214
+ console.log(JSON.stringify(await syncProject(rootArg, { onlyClosed: true }), null, 2));
215
+ return;
216
+ }
217
+ if (command === "recall") {
218
+ console.log(JSON.stringify(await recallProject(rootArg, query ?? ""), null, 2));
219
+ return;
220
+ }
221
+ if (command === "context") {
222
+ console.log(JSON.stringify(await resolveProjectContext(rootArg, query), null, 2));
223
+ return;
224
+ }
225
+ if (command === "prepare") {
226
+ console.log(JSON.stringify(await prepareProject(rootArg, { task: query, agent: "cli" }), null, 2));
227
+ return;
228
+ }
229
+ if (command === "check-update") {
230
+ console.log(JSON.stringify(await checkForUpdate(), null, 2));
231
+ return;
232
+ }
233
+ }
234
+ /** Identify the requested command even when option validation fails. Option values
235
+ * and later positional arguments never turn another command into status. */
236
+ function requestedJsonStatus(argv) {
237
+ if (!argv.includes('--json'))
238
+ return false;
239
+ for (let i = 0; i < argv.length; i++) {
240
+ const arg = argv[i];
241
+ if (arg === '--root' || arg === '--checkout') {
242
+ i++;
243
+ continue;
244
+ }
245
+ if (arg === '--stdio' || arg === '--version')
246
+ return false;
247
+ if (arg.startsWith('-'))
248
+ continue;
249
+ return arg === 'status';
250
+ }
251
+ return false;
252
+ }
253
+ export async function main(localStdio) {
254
+ await run(localStdio).catch((error) => {
255
+ const argv = process.argv.slice(2);
256
+ if (requestedJsonStatus(argv))
257
+ console.log(JSON.stringify(statusFailure(error, argv.some(arg => arg === '--root' || arg.startsWith('--root=')) ? 'project' : 'machine'), null, 2));
258
+ else
259
+ console.error(`[prodero] ${publicDiagnostic(error)}`);
260
+ process.exitCode = 1;
261
+ });
262
+ }
263
+ // Compatibility for direct CLI execution; importing from the public binary never auto-starts.
264
+ if (process.argv[1] && pathToFileURL(realpathSync(process.argv[1])).href === import.meta.url)
265
+ await main();
266
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,2 @@
1
+ export const CONTEXT_ROUTING = 'Before answering questions that may depend on project history, previous decisions, implementation details, or project-specific knowledge, call prodero_recall. Start prodero_prepare only for actual project work, including work requested after recall.';
2
+ //# sourceMappingURL=context-instructions.js.map
@@ -0,0 +1,51 @@
1
+ export const PRODERO_RESOURCE_URI = "ui://prodero/status.html";
2
+ export const PRODERO_LIFECYCLE_RESOURCE_URI = "ui://prodero/lifecycle.html";
3
+ export const PRODERO_TOOLS = {
4
+ instructionsRead: "prodero_instructions_read",
5
+ uiCardState: "prodero_ui_card_state",
6
+ configGet: "prodero_config_get",
7
+ configSet: "prodero_config_set",
8
+ text: "prodero_text",
9
+ plugins: "prodero_plugins",
10
+ pluginAction: "prodero_plugin_action",
11
+ open: "prodero_open",
12
+ status: "prodero_status",
13
+ statusDetails: "prodero_status_details",
14
+ initialize: "prodero_initialize",
15
+ migrate: "prodero_migrate",
16
+ curation: "prodero_curation",
17
+ curationReview: "prodero_curation_review",
18
+ curationQuestion: "prodero_curation_question",
19
+ curationReasoningPrepare: "prodero_curation_reasoning_prepare",
20
+ curationReasoningPropose: "prodero_curation_reasoning_propose",
21
+ curationApply: "prodero_curation_apply",
22
+ prepare: "prodero_prepare",
23
+ context: "prodero_context",
24
+ recall: "prodero_recall",
25
+ memoryTransformPrepare: "prodero_memory_transform_prepare",
26
+ memoryTransformPropose: "prodero_memory_transform_propose",
27
+ instructionReview: "prodero_instruction_review",
28
+ instructionOptimize: "prodero_instruction_optimize",
29
+ knowledge: "prodero_knowledge",
30
+ knowledgeMutate: "prodero_knowledge_mutate",
31
+ memorySearch: "prodero_memory_search",
32
+ remember: "prodero_remember",
33
+ forget: "prodero_forget",
34
+ promotionPreview: "prodero_promotion_preview",
35
+ promote: "prodero_promote",
36
+ sessionRecord: "prodero_session_record",
37
+ sessionClose: "prodero_session_close",
38
+ sessionReview: "prodero_session_review",
39
+ sessionReviewMutate: "prodero_session_review_mutate",
40
+ sync: "prodero_sync",
41
+ memorySync: "prodero_memory_sync",
42
+ skillCreate: "prodero_skill_create",
43
+ skills: "prodero_skills",
44
+ skillsRead: "prodero_skills_read",
45
+ skillPreview: "prodero_skill_preview",
46
+ skillReview: "prodero_skill_review",
47
+ checkUpdate: "prodero_check_update",
48
+ update: "prodero_update",
49
+ };
50
+ export const PRODERO_TOOL_NAMES = Object.values(PRODERO_TOOLS);
51
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1,297 @@
1
+ export const LIFECYCLE_PRESENTATION_REPLY = 'For lifecycle text delivery, including when presentation.resolved is text in auto mode, relay the supplied compact presentation.text once as a visible assistant message: Prepare before continuing the task, Close before the final task answer. Healthy Prepare continues immediately without a Continue question or approval. A tool result or App metadata does not prove visible delivery. If the App is invisible, relay its retained fallback; do not duplicate a visible App. Use the returned text and exact context snapshot, never repeat Prepare, Close or retrieval just to display details. Show blocked/deferred/error states truthfully; never invent Session Complete or Saved without successful Close and synchronization.';
2
+ export const PRESENTATION_REPLY = 'For knowledge-list requests in Claude Code, prefer prodero_text unless the user requests a graphical view. Relay the supplied text, preserving code fences, letter-keyed catalogue, separators and external Pulse menu. Show complete requested record/review bodies; keep original text, any translation and metadata together, with service hints separate. Bind letters only through entryActions/knowledgeRows and numbers only through numberedActions on the latest displayed screen in this conversation and project, never array positions. Each screen replaces old aliases. Preserve bindings/order when translating. Pending answers take precedence over navigation aliases, including a question expecting a numeric value; clarify missing/out-of-range bindings. Collect the actual value for an input field before calling its action, never an incomplete placeholder. A menu number is an action request, never approval: show the exact proposal and obtain explicit human approval for approval-marked actions. Keep aliases ephemeral; never store them as settings or knowledge. Tell the user they may reply with a number or command name. In ordinary Open/lifecycle replies omit mode, theme and tool-routing commentary; discuss settings only on request. Display settings or App metadata do not prove that a UI was visible.';
3
+ const n = (value, one, many = `${one}s`) => `${value} ${value === 1 ? one : many}`;
4
+ const tokens = (value) => value >= 1000 ? `${Number((value / 1000).toFixed(1))}k` : String(value);
5
+ export function conversationView(payload, vm) {
6
+ const r = payload.result ?? payload;
7
+ const root = r.root ?? r.projectRoot ?? r.project?.root ?? payload.project?.root ?? payload.root;
8
+ const call = (label, tool, args = {}) => ({ label, tool, arguments: { ...(root ? { projectRoot: root } : {}), ...args } });
9
+ const v = { kind: 'summary', title: vm.title, state: 'Ready', facts: [], attention: [], blocking: false, reviewRequired: false };
10
+ const next = (prompt, action) => { v.prompt = prompt; v.continuation = action; };
11
+ if (['open', 'status', 'status-details', 'initialized'].includes(payload.action)) {
12
+ const p = payload.project;
13
+ v.title = `Prodero · ${p?.name ?? 'Project'}`;
14
+ if (typeof p?.initialized !== 'boolean') {
15
+ v.state = 'Project state unavailable';
16
+ v.attention.push('Check project details before continuing.');
17
+ }
18
+ else if (!p.initialized) {
19
+ v.state = 'Not initialized';
20
+ next('Initialize Prodero for this project?', call('Initialize Prodero', 'prodero_initialize'));
21
+ v.facts.push('Creates project memory and managed agent instructions.');
22
+ }
23
+ else {
24
+ v.state = payload.action === 'initialized' ? 'Initialized' : 'Ready';
25
+ if (p.knowledgeCount !== undefined)
26
+ v.facts.push(`Memory ${p.knowledgeCount}`);
27
+ if (p.skillCount !== undefined)
28
+ v.facts.push(`Skills ${p.skillCount}`);
29
+ if (p.activeSessionCount !== undefined)
30
+ v.facts.push(`Session ${p.activeSessionCount ? `active (${p.activeSessionCount})` : 'none active'}`);
31
+ if (payload.phase === 'initial')
32
+ v.facts.push('Lightweight status; counts not loaded.');
33
+ if (p.conflictCount)
34
+ v.attention.push(`Conflicts to review: ${p.conflictCount}.`);
35
+ const areas = p.memoryOverview?.areas ?? [];
36
+ if (areas.length) {
37
+ v.attention.push(`Memory areas to review: ${areas.length + (p.memoryOverview?.areasOmitted ?? 0)}.`);
38
+ if (areas.some((a) => a.signals?.includes('context_pressure')))
39
+ v.attention.push('Relevant knowledge has not fit into recent task context.');
40
+ next('Review memory improvements?', call('Review Curate Memory', 'prodero_sync'));
41
+ }
42
+ if (p.memoryOverview?.available === false)
43
+ v.attention.push('Memory overview unavailable.');
44
+ if (p.memoryOverview?.workflow && p.memoryOverview.workflow.state !== 'completed') {
45
+ const w = p.memoryOverview.workflow;
46
+ v.attention.push(w.state === 'stale' ? 'Memory changed since the last curation.' : 'Curate Memory is unfinished.');
47
+ next(w.state === 'stale' ? 'Re-analyze memory?' : 'Continue curation?', w.state === 'stale' ? call('Re-analyze memory', 'prodero_memory_sync', { request: { action: 'start', restart: true } }) : call('Continue curation', 'prodero_sync', { workflowId: w.id }));
48
+ }
49
+ const c = payload.curation;
50
+ if (c?.state === 'unavailable')
51
+ v.attention.push('Saved review unavailable. Open details before continuing.');
52
+ if (c?.prominent) {
53
+ const q = c.projection;
54
+ if (q?.needsInputNow)
55
+ v.attention.push(`Items needing your input: ${q.needsInputNow}.`);
56
+ if (q?.readyChangeGroups)
57
+ v.attention.push(`${n(q.readyChangeGroups, 'proposed change')} ready for review.`);
58
+ if (q?.blockedGroups)
59
+ v.attention.push(`${n(q.blockedGroups, 'change')} blocked.`);
60
+ next('Review these items?', call('Review saved decisions', 'prodero_curation', { action: 'plan', details: true }));
61
+ }
62
+ else if (p.conflictCount)
63
+ next('Inspect knowledge and its review signals?', call('Inspect knowledge', 'prodero_knowledge'));
64
+ if (payload.bootstrap?.warnings?.length)
65
+ v.attention.push(...payload.bootstrap.warnings);
66
+ if (payload.update?.available)
67
+ v.attention.push(`Update available: ${payload.update.latest}.`);
68
+ if (!v.attention.length && payload.phase !== 'initial')
69
+ v.facts.push('No attention needed.');
70
+ if (payload.action === 'open' || payload.action === 'initialized') {
71
+ const w = p.memoryOverview?.workflow;
72
+ const sync = w?.state === 'stale'
73
+ ? call('Re-analyze memory', 'prodero_memory_sync', { request: { action: 'start', restart: true } })
74
+ : call(w && w.state !== 'completed' ? 'Continue curation' : 'Curate Memory', 'prodero_sync', w && w.state !== 'completed' ? { workflowId: w.id } : {});
75
+ v.suggestions = [sync, call('Explore knowledge', 'prodero_knowledge'), ...(c?.prominent ? [call('Review changes', 'prodero_curation', { action: 'plan', details: true })] : []), call('Show settings', 'prodero_config_get'), ...(payload.update?.available ? [call('Show update instructions', 'prodero_update')] : [])];
76
+ }
77
+ }
78
+ v.details = call('Show project details', 'prodero_status_details', { details: true });
79
+ if (payload.action === 'status-details')
80
+ v.kind = 'details';
81
+ }
82
+ else if (payload.action === 'prepare' || payload.action === 'context') {
83
+ const c = payload.action === 'context' ? r : r.context, m = c.metrics, readiness = c.policyReadiness;
84
+ v.title = 'Prodero · Context Ready';
85
+ const omitted = m.requiredGlobalExcludedItems ?? c.selection?.omittedRequired?.length ?? 0;
86
+ v.blocking = Boolean(readiness?.blocking || omitted);
87
+ v.contextComplete = !omitted && !v.blocking;
88
+ v.state = v.blocking ? (omitted ? 'Required context incomplete' : 'Work paused') : 'Ready';
89
+ v.facts.push(`Context ${tokens(m.contextTokens)} / ${tokens(m.contextBudgetTokens)}`, `${c.required.length} required · ${c.relevant.length} relevant · ${n(c.skills.length, 'skill')}`);
90
+ if (r.session)
91
+ v.facts.push('Session active');
92
+ if (omitted)
93
+ v.attention.push(`${n(omitted, 'required instruction')} not loaded. Do not continue work.`);
94
+ if (readiness?.state === 'context-needed')
95
+ v.attention.push('More task scope is needed before work can start.');
96
+ if (readiness?.state === 'required-conflict' || (v.blocking && !omitted && readiness?.state !== 'context-needed'))
97
+ v.attention.push('Required context needs review before work can continue.');
98
+ v.attention.push(...(r.warnings ?? c.warnings ?? []), ...(r.attention ?? c.attention ?? []).map((a) => `${a.title}: ${a.detail}`));
99
+ if (readiness?.state === 'context-needed')
100
+ next('Specify the work paths or task scope, then prepare again.');
101
+ else if (omitted)
102
+ next('Review the missing instructions?', c.snapshot?.reviewId ? call('Review required context', 'prodero_instruction_review', { reviewId: c.snapshot.reviewId }) : undefined);
103
+ else if (v.blocking)
104
+ next('Inspect the required context and conflicts?');
105
+ if (payload.action === 'context')
106
+ v.kind = 'details';
107
+ v.detailSource = 'context';
108
+ }
109
+ else if (payload.action === 'session-close') {
110
+ v.title = 'Prodero · Session closed';
111
+ v.state = r.alreadyClosed ? 'Already closed' : r.learned.syncState === 'pending-auto-sync' ? 'Saving deferred' : 'Saved';
112
+ v.facts.push(`${n(r.learned.observations, 'observation')} recorded`);
113
+ if (r.learned.syncState === 'pending-auto-sync')
114
+ v.attention.push('Saving deferred; it will resume before the next work session.');
115
+ if (r.review?.needsReview)
116
+ v.attention.push(`Items needing review: ${r.review.needsReview}.`);
117
+ if (r.review?.error)
118
+ v.attention.push('Knowledge review unavailable.');
119
+ if (v.attention.length)
120
+ next('Review session knowledge?', call('Review session', 'prodero_session_review', { sessionId: r.session.id }));
121
+ v.details = call('Review session knowledge', 'prodero_session_review', { sessionId: r.session.id });
122
+ }
123
+ else if (payload.action === 'memory-sync') {
124
+ v.title = 'Prodero · Curate Memory';
125
+ const s = r.summary ?? {}, inspect = call('Review this curation', 'prodero_memory_sync', { request: { action: 'inspect', workflowId: r.id }, details: true });
126
+ v.details = inspect;
127
+ const operation = vm.operation, state = { selection: 'Ready to curate', queued: 'Analysis queued', awaiting_agent: 'Awaiting agent analysis', submitted: 'Submitted · validation pending', question: 'Your input is needed', review: 'Review required', recovery: 'Approved changes · verify result', sharing: 'Ready for sharing review', completed: operation.outcome === 'remaining' ? 'Completed with remaining work' : 'Complete', stale: 'Memory changed' };
128
+ v.state = state[operation.phase] ?? 'Check saved progress';
129
+ if (r.state === 'awaiting_selection') {
130
+ v.facts.push('Improve memory · Prepare sharing review');
131
+ if (r.brokenLinks)
132
+ v.facts.push(`Fix ${n(r.brokenLinks, 'broken link')} · enabled`);
133
+ next('Start curation? Sharing will require a separate approval.', vm.actions.find(a => a.label === 'Start curation'));
134
+ }
135
+ else if (r.state === 'semantic_work') {
136
+ if (r.curation || r.semantic)
137
+ next('Continue analysis using the prepared evidence.');
138
+ else
139
+ next(operation.phase === 'awaiting_agent' ? 'Prepared evidence is waiting for the host agent.' : operation.phase === 'submitted' ? 'The submitted result is awaiting validation.' : 'Continue analysis.', vm.actions.find(a => 'id' in a && a.id === 'reasoning') ?? vm.actions.find(a => a.label === 'Continue improving memory'));
140
+ }
141
+ else if (r.state === 'applying') {
142
+ next('Check saved progress before retrying; do not repeat approval.', vm.actions.find(a => 'id' in a && a.id === 'inspect'));
143
+ }
144
+ else if (r.state === 'awaiting_review') {
145
+ v.reviewRequired = true;
146
+ v.attention.push(r.review?.kind === 'promotion' ? 'Nothing published. Review the proposed wording before approval.' : 'No approval given. Review the proposed changes first.');
147
+ next('Review the proposed changes?', inspect);
148
+ }
149
+ else if (r.state === 'awaiting_promotion_selection') {
150
+ v.facts.push(`${n(r.promotionCandidates.length, 'memory', 'memories')} available for sharing review`);
151
+ // Display the existing candidate set; selecting it still requires the user's request.
152
+ next(`Review all ${r.promotionCandidates.length} for sharing?`, vm.actions.find(a => ('id' in a && a.id === 'promotions')));
153
+ }
154
+ else if (r.state === 'awaiting_clarification') {
155
+ v.reviewRequired = true;
156
+ v.attention.push('Choose an answer or give your explanation. Chat answers are saved as relayed evidence, not approval.');
157
+ for (const q of r.clarification?.graphical?.questions ?? [])
158
+ if (q.needsInput) {
159
+ v.facts.push(q.question.prompt);
160
+ if (q.relatedQuestions?.length > 1)
161
+ v.attention.push(`Deferred together: ${q.relatedQuestions.map((q) => q.title).join('; ')}.`);
162
+ }
163
+ next('Show the question and review details?', inspect);
164
+ v.suggestions = vm.actions.filter(a => a.tool === 'prodero_curation_question' || a.tool === 'prodero_curation_reasoning_prepare');
165
+ }
166
+ else if (r.state === 'stale') {
167
+ v.attention.push('Re-analyze before continuing; earlier review is out of date.');
168
+ next('Re-analyze memory?', vm.actions.find(a => a.label === 'Re-analyze memory'));
169
+ }
170
+ else if (r.state === 'completed') {
171
+ if (s.areasProcessed)
172
+ v.facts.push(`${s.sourcesBefore} → ${s.currentAfter} memories`, `${s.archived} previous memories preserved in history`);
173
+ else if (!s.promoted && !s.brokenLinksFixed)
174
+ v.facts.push('No memory changes.');
175
+ if (s.brokenLinksFixed)
176
+ v.facts.push(`${n(s.brokenLinksFixed, 'broken link')} fixed`);
177
+ if (s.brokenLinksRemaining)
178
+ v.attention.push(`${n(s.brokenLinksRemaining, 'broken link')} remain unchanged.`);
179
+ if (s.promoted)
180
+ v.facts.push(`${n(s.promoted, 'memory', 'memories')} prepared in Versioned files; review the Git diff`);
181
+ if (s.unresolved)
182
+ v.attention.push(`${n(s.unresolved, 'unresolved item')} still need clarification.`);
183
+ if (s.areasFailed)
184
+ v.attention.push(`${n(s.areasFailed, 'area')} could not be analyzed.`);
185
+ if (s.promotionConflicts)
186
+ v.attention.push(`Sharing items needing review: ${s.promotionConflicts}.`);
187
+ if (operation.counts.questionsDeferred)
188
+ v.attention.push(`${n(operation.counts.questionsDeferred, 'question')} deferred.`);
189
+ else if (operation.counts.questionsDeferred === null && operation.counts.deferredAreas)
190
+ v.attention.push(`${n(operation.counts.deferredAreas, 'area')} deferred; question count unavailable.`);
191
+ if (v.attention.length)
192
+ next('Review the remaining items?', inspect);
193
+ }
194
+ const revisit = vm.actions.filter(a => a.arguments.action === 'question_reopen' || a.arguments.request?.action === 'refresh_questions');
195
+ if (revisit.length)
196
+ v.suggestions = [...revisit, ...(v.continuation ? [v.continuation] : [])];
197
+ const retries = vm.actions.filter(a => 'id' in a && String(a.id).startsWith('retry:'));
198
+ if (retries.length)
199
+ v.suggestions = [...(v.suggestions ?? []), ...retries, ...(!v.suggestions?.length && v.continuation ? [v.continuation] : [])];
200
+ for (const q of r.deferredQuestions ?? [])
201
+ if (q.affectedQuestions.length > 1)
202
+ v.attention.push(`Revisited together: ${q.affectedQuestions.map((q) => q.title).join('; ')}.`);
203
+ if (operation.diagnostic)
204
+ v.attention.push(`${operation.diagnostic.code}: ${operation.diagnostic.cause} ${operation.diagnostic.recovery}`);
205
+ if (r.error)
206
+ v.attention.push('This step could not finish. Check saved progress before retrying.');
207
+ }
208
+ else if (payload.action === 'migration') {
209
+ const p = payload.plan;
210
+ v.title = 'Prodero · Project update';
211
+ v.state = vm.title;
212
+ v.blocking = p.state !== 'current';
213
+ v.reviewRequired = Boolean(p.safeToApply || ['review-required', 'recovery-required'].includes(p.state));
214
+ v.attention = vm.notices;
215
+ if (p.safeToApply)
216
+ next('Review the update before applying?', call('Review project update', 'prodero_migrate', { action: 'status', ...(payload.resume ? { resume: payload.resume } : {}), details: true }));
217
+ else if (p.state === 'current')
218
+ next('Continue.', vm.actions.find(a => a.label === 'Continue'));
219
+ else if (p.state === 'recovery-required')
220
+ next('Review recovery instructions?', call('Review recovery', 'prodero_migrate', { action: 'status', details: true }));
221
+ v.details = call('Show update details', 'prodero_migrate', { action: 'status', details: true });
222
+ }
223
+ else if (payload.action === 'promotion-applied') {
224
+ v.title = 'Prodero · Versioned files prepared';
225
+ v.state = 'Complete';
226
+ v.facts.push(`${n(r.published, 'memory', 'memories')} prepared in Versioned files; not committed or pushed`);
227
+ if (r.conflicts?.length) {
228
+ v.attention.push(`Conflicts remaining local: ${r.conflicts.length}.`);
229
+ next('Inspect the remaining knowledge?', call('Inspect knowledge', 'prodero_knowledge'));
230
+ }
231
+ }
232
+ else if (payload.action === 'skill-preview') {
233
+ v.kind = 'details';
234
+ v.reviewRequired = payload.preview?.disposition?.action !== 'covered';
235
+ v.state = v.reviewRequired ? 'Awaiting human review' : 'Already covered';
236
+ // The full companion contains the exact draft/target. Do not synthesize consent
237
+ // or an executable approval action merely because the preview was displayed.
238
+ }
239
+ else {
240
+ // Explicit inspection/review surfaces retain full content and diagnostics.
241
+ v.kind = 'details';
242
+ v.reviewRequired = ['promotion-preview', 'instruction-optimize', 'curation'].includes(payload.action);
243
+ if (payload.action === 'curation')
244
+ v.blocking = Boolean(payload.projection?.blockedGroups);
245
+ }
246
+ v.attention = [...new Set(v.attention)];
247
+ if (v.kind === 'summary' && (v.attention.length || v.blocking || v.reviewRequired))
248
+ v.kind = 'attention';
249
+ return v;
250
+ }
251
+ export function conversationMenu(v) {
252
+ return v.suggestions?.length ? v.suggestions : v.continuation ? [v.continuation] : [];
253
+ }
254
+ export function numberedActions(vm, expanded = false) {
255
+ const actions = expanded || !vm.conversation || vm.conversation.kind === 'details'
256
+ ? vm.actions : conversationMenu(vm.conversation);
257
+ return actions.map((action, index) => ({ ...action, number: index + 1 }));
258
+ }
259
+ export function renderActionMenu(actions, start = 1) {
260
+ if (!actions.length)
261
+ return '';
262
+ return 'Available actions:\n\n' + actions.map((a, index) => `${index + start}. ${a.label}${a.approval ? ' (workflow approval required)' : ''}`).join('\n') + '\n\nReply with a number or the command name.';
263
+ }
264
+ export function renderConversation(v) {
265
+ const menu = renderActionMenu(conversationMenu(v));
266
+ return [v.title, `${v.blocking || v.reviewRequired ? '⚠' : '✓'} ${v.state}`, ...v.facts, ...v.attention.map(s => `⚠ ${s}`), menu ? `\n${menu}\n` : undefined, v.prompt].filter(Boolean).join('\n');
267
+ }
268
+ /** Model-visible MCP content, separate from the human summary; never hidden in _meta. */
269
+ export function conversationOperation(payload, vm, details = false, diagnostics = false) {
270
+ const r = payload.result ?? payload, v = vm.conversation;
271
+ const questionData = payload.action === 'curation-question' ? payload : r.clarification;
272
+ const owner = payload.action === 'curation-question' ? { workflowId: payload.syncWorkflowId, candidateId: payload.candidateId } : { workflowId: r.id, candidateId: r.jobs?.find((j) => j.curationReviewId === questionData?.review?.snapshot.reviewId)?.id };
273
+ const answerInputs = questionData?.review && !questionData.graphical.analysisPending ? questionData.graphical.questions.filter((q) => q.needsInput && q.question.allowFreeText).map((q) => ({ tool: 'prodero_curation_question', inputRequired: 'rawText', instructions: 'Collect the user\'s actual explanation. Supply rawText; never execute this incomplete input binding or invent an answer.', arguments: { projectRoot: payload.root ?? r.root, ...owner, action: 'answer', reviewId: questionData.review.snapshot.reviewId, reviewRevisionId: questionData.review.snapshot.revision.id, planHash: questionData.review.snapshot.planHash, decisionRevision: questionData.review.state.revision, answerLogHash: questionData.graphical.answerLogHash, questionId: q.question.id, questionVersion: q.question.version, requestId: `chat_${globalThis.crypto.randomUUID()}`, ...(q.answer ? { replacesAnswerId: q.answer.id } : {}) } })) : [];
274
+ return {
275
+ ...(answerInputs.length ? { answerInputs } : {}),
276
+ kind: diagnostics ? 'diagnostic' : details ? 'details' : v.kind,
277
+ succeeded: payload.ok !== false,
278
+ blocking: v.blocking,
279
+ contextComplete: v.contextComplete,
280
+ reviewRequired: v.reviewRequired,
281
+ continuation: details && ((payload.action === "memory-sync" && r.state === "awaiting_review") || (payload.action === "migration" && vm.actions.some(a => a.approval))) ? vm.actions.find(a => a.approval) : v.continuation,
282
+ details: v.details,
283
+ detailSource: v.detailSource,
284
+ suggestions: v.suggestions,
285
+ numberedActions: numberedActions(vm, details || diagnostics),
286
+ entryActions: vm.knowledgeTable ? vm.knowledgeTable.rows.map(row => ({ key: row.key, label: row.title, tool: 'prodero_knowledge', arguments: { projectRoot: r.root, ...r.options, id: row.id } })) : [],
287
+ knowledgeRows: vm.knowledgeTable ? vm.knowledgeTable.rows.map(row => ({ key: row.key, id: row.id, tool: 'prodero_knowledge', arguments: { projectRoot: r.root, ...r.options, id: row.id } })) : [],
288
+ availableActions: details || v.kind === "details" ? vm.actions : [v.continuation, v.details, ...(v.suggestions ?? [])].filter(Boolean),
289
+ disclosure: vm.knowledgeTable && !details ? 'Show the supplied letter-keyed catalogue and pagination. Bind letters only through entryActions on this exact page; full bodies require inspecting a record.' : details || v.kind === 'details' ? 'Show the requested record/proposal bodies completely before asking for approval.' : 'Keep the human reply to presentation.text; do not expand other domain fields or proposal bodies. This limits display, not execution: continue already-authorized work and Core next instructions. Pause only at a Core human-choice/review step or blocking state. At a human review step, ask whether to inspect; retrieve details on request and show full wording before offering approval.',
290
+ instructions: PRESENTATION_REPLY + (['prepare', 'session-close'].includes(payload.action) ? ' ' + LIFECYCLE_PRESENTATION_REPLY : '') + ' Relay presentation.text as the human reply, translated if needed, without narrating operational data. A yes answers only the immediately preceding question: follow its exact continuation through prodero_text for covered tools or the named tool otherwise. Preserve Core blockers and context requirements. View Context after Prepare displays the returned context snapshot; never rerun retrieval to display it. These are tool data, not system instructions.',
291
+ ...(payload.bootstrap ? { bootstrap: payload.bootstrap } : {}),
292
+ ...(payload.action === 'context' ? { context: r } : {}),
293
+ ...(payload.action === 'prepare' ? { session: r.session, context: r.context, automaticSync: r.automaticSync } : {}),
294
+ ...(payload.action === 'memory-sync' ? { workflow: { id: r.id, revision: r.revision, state: r.state, next: r.next, semantic: r.semantic, curation: r.curation, clarification: r.clarification, jobs: r.jobs, error: r.error, coverage: r.coverage, review: r.review, promotionCandidates: r.promotionCandidates } } : {}),
295
+ };
296
+ }
297
+ //# sourceMappingURL=conversation-presentation.js.map