@lssm/lib.contracts 0.0.0-canary-20251217062943 → 0.0.0-canary-20251217072406
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-config/app-config.feature.js +53 -1
- package/dist/app-config/contracts.d.ts +50 -50
- package/dist/app-config/contracts.js +396 -1
- package/dist/app-config/docs/app-config.docblock.js +22 -220
- package/dist/app-config/events.js +168 -1
- package/dist/app-config/index.js +8 -1
- package/dist/app-config/lifecycle-contracts.js +441 -1
- package/dist/app-config/runtime.js +617 -1
- package/dist/app-config/spec.js +36 -1
- package/dist/app-config/validation.js +538 -1
- package/dist/capabilities/docs/capabilities.docblock.js +22 -1
- package/dist/capabilities/openbanking.js +92 -1
- package/dist/capabilities.js +50 -1
- package/dist/client/index.js +9 -1
- package/dist/client/react/drivers/rn-reusables.js +21 -1
- package/dist/client/react/drivers/shadcn.js +11 -1
- package/dist/client/react/feature-render.js +43 -1
- package/dist/client/react/form-render.js +298 -1
- package/dist/client/react/index.js +8 -1
- package/dist/contract-registry/index.js +3 -1
- package/dist/contract-registry/schemas.js +61 -1
- package/dist/contracts-adapter-hydration.js +41 -1
- package/dist/contracts-adapter-input.js +77 -1
- package/dist/data-views/docs/data-views.docblock.js +22 -1
- package/dist/data-views/query-generator.js +48 -1
- package/dist/data-views/runtime.js +39 -1
- package/dist/data-views.js +35 -1
- package/dist/docs/PUBLISHING.docblock.js +17 -76
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +17 -350
- package/dist/docs/index.js +33 -1
- package/dist/docs/meta.docs.js +15 -2
- package/dist/docs/presentations.js +77 -1
- package/dist/docs/registry.js +51 -1
- package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +17 -383
- package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +17 -68
- package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +17 -140
- package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +17 -86
- package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +17 -1
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +25 -2
- package/dist/docs/tech/contracts/README.docblock.js +21 -1
- package/dist/docs/tech/contracts/create-subscription.docblock.js +21 -1
- package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +21 -180
- package/dist/docs/tech/contracts/migrations.docblock.js +21 -1
- package/dist/docs/tech/contracts/openapi-export.docblock.js +22 -2
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +19 -60
- package/dist/docs/tech/contracts/overlays.docblock.js +21 -68
- package/dist/docs/tech/contracts/tests.docblock.js +21 -132
- package/dist/docs/tech/contracts/themes.docblock.js +21 -1
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +21 -106
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +17 -213
- package/dist/docs/tech/llm/llm-integration.docblock.js +74 -5
- package/dist/docs/tech/mcp-endpoints.docblock.js +38 -1
- package/dist/docs/tech/presentation-runtime.docblock.js +17 -1
- package/dist/docs/tech/schema/README.docblock.js +21 -262
- package/dist/docs/tech/studio/learning-events.docblock.js +49 -1
- package/dist/docs/tech/studio/learning-journeys.docblock.js +25 -2
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +24 -2
- package/dist/docs/tech/studio/project-access-teams.docblock.js +26 -16
- package/dist/docs/tech/studio/project-routing.docblock.js +68 -1
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +23 -2
- package/dist/docs/tech/studio/team-invitations.docblock.js +41 -36
- package/dist/docs/tech/studio/workspace-ops.docblock.js +48 -1
- package/dist/docs/tech/studio/workspaces.docblock.js +24 -2
- package/dist/docs/tech/telemetry-ingest.docblock.js +37 -3
- package/dist/docs/tech/templates/runtime.docblock.js +21 -1
- package/dist/docs/tech/vscode-extension.docblock.js +37 -3
- package/dist/docs/tech/workflows/overview.docblock.js +21 -1
- package/dist/docs/tech-contracts.docs.js +19 -2
- package/dist/events.js +12 -1
- package/dist/experiments/docs/experiments.docblock.js +22 -128
- package/dist/experiments/evaluator.js +101 -1
- package/dist/experiments/spec.js +33 -1
- package/dist/features.js +68 -1
- package/dist/forms/docs/forms.docblock.js +22 -1
- package/dist/forms.js +119 -1
- package/dist/index.js +107 -1
- package/dist/install.js +40 -1
- package/dist/integrations/contracts.d.ts +102 -102
- package/dist/integrations/contracts.js +388 -1
- package/dist/integrations/docs/integrations.docblock.js +95 -1
- package/dist/integrations/health.js +69 -1
- package/dist/integrations/index.js +23 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +66 -66
- package/dist/integrations/openbanking/contracts/accounts.js +237 -1
- package/dist/integrations/openbanking/contracts/balances.d.ts +34 -34
- package/dist/integrations/openbanking/contracts/balances.js +167 -1
- package/dist/integrations/openbanking/contracts/index.js +12 -1
- package/dist/integrations/openbanking/contracts/transactions.d.ts +48 -48
- package/dist/integrations/openbanking/contracts/transactions.js +218 -1
- package/dist/integrations/openbanking/guards.js +32 -1
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/openbanking/models.js +242 -1
- package/dist/integrations/openbanking/openbanking.feature.js +68 -1
- package/dist/integrations/openbanking/telemetry.js +39 -1
- package/dist/integrations/providers/elevenlabs.js +56 -1
- package/dist/integrations/providers/gcs-storage.js +79 -1
- package/dist/integrations/providers/gmail.js +91 -1
- package/dist/integrations/providers/google-calendar.js +70 -1
- package/dist/integrations/providers/impls/elevenlabs-voice.js +95 -1
- package/dist/integrations/providers/impls/gcs-storage.js +88 -1
- package/dist/integrations/providers/impls/gmail-inbound.js +200 -1
- package/dist/integrations/providers/impls/gmail-outbound.js +104 -5
- package/dist/integrations/providers/impls/google-calendar.js +154 -1
- package/dist/integrations/providers/impls/index.js +16 -1
- package/dist/integrations/providers/impls/mistral-embedding.js +41 -1
- package/dist/integrations/providers/impls/mistral-llm.js +247 -1
- package/dist/integrations/providers/impls/postmark-email.js +55 -1
- package/dist/integrations/providers/impls/powens-client.js +171 -1
- package/dist/integrations/providers/impls/powens-openbanking.js +218 -1
- package/dist/integrations/providers/impls/provider-factory.js +142 -1
- package/dist/integrations/providers/impls/qdrant-vector.js +69 -1
- package/dist/integrations/providers/impls/stripe-payments.js +202 -1
- package/dist/integrations/providers/impls/twilio-sms.js +58 -1
- package/dist/integrations/providers/index.js +13 -1
- package/dist/integrations/providers/mistral.js +72 -1
- package/dist/integrations/providers/postmark.js +72 -1
- package/dist/integrations/providers/powens.js +120 -1
- package/dist/integrations/providers/qdrant.js +77 -1
- package/dist/integrations/providers/registry.js +34 -1
- package/dist/integrations/providers/stripe.js +87 -1
- package/dist/integrations/providers/twilio-sms.js +65 -1
- package/dist/integrations/runtime.js +186 -1
- package/dist/integrations/secrets/aws-secret-manager.js +231 -1
- package/dist/integrations/secrets/env-secret-provider.js +81 -1
- package/dist/integrations/secrets/gcp-secret-manager.js +229 -1
- package/dist/integrations/secrets/index.js +8 -1
- package/dist/integrations/secrets/manager.js +103 -1
- package/dist/integrations/secrets/provider.js +58 -1
- package/dist/integrations/secrets/scaleway-secret-manager.js +247 -1
- package/dist/integrations/spec.js +39 -1
- package/dist/jobs/define-job.js +16 -1
- package/dist/jobs/gcp-cloud-tasks.js +53 -1
- package/dist/jobs/gcp-pubsub.js +39 -1
- package/dist/jobs/handlers/gmail-sync-handler.js +9 -1
- package/dist/jobs/handlers/index.js +12 -1
- package/dist/jobs/handlers/ping-handler.js +15 -1
- package/dist/jobs/handlers/storage-document-handler.js +14 -1
- package/dist/jobs/index.js +4 -1
- package/dist/jobs/memory-queue.js +71 -1
- package/dist/jobs/queue.js +33 -1
- package/dist/jobs/scaleway-sqs-queue.js +153 -1
- package/dist/jsonschema.d.ts +3 -3
- package/dist/jsonschema.js +32 -1
- package/dist/knowledge/contracts.d.ts +66 -66
- package/dist/knowledge/contracts.js +317 -1
- package/dist/knowledge/docs/knowledge.docblock.js +22 -138
- package/dist/knowledge/index.js +10 -1
- package/dist/knowledge/ingestion/document-processor.js +54 -1
- package/dist/knowledge/ingestion/embedding-service.js +25 -1
- package/dist/knowledge/ingestion/gmail-adapter.js +50 -5
- package/dist/knowledge/ingestion/index.js +7 -1
- package/dist/knowledge/ingestion/storage-adapter.js +26 -1
- package/dist/knowledge/ingestion/vector-indexer.js +32 -1
- package/dist/knowledge/query/index.js +3 -1
- package/dist/knowledge/query/service.js +64 -2
- package/dist/knowledge/runtime.js +49 -1
- package/dist/knowledge/spaces/email-threads.js +38 -1
- package/dist/knowledge/spaces/financial-docs.js +38 -1
- package/dist/knowledge/spaces/financial-overview.js +42 -1
- package/dist/knowledge/spaces/index.js +8 -1
- package/dist/knowledge/spaces/product-canon.js +38 -1
- package/dist/knowledge/spaces/support-faq.js +41 -1
- package/dist/knowledge/spaces/uploaded-docs.js +38 -1
- package/dist/knowledge/spec.js +39 -1
- package/dist/llm/exporters.js +541 -8
- package/dist/llm/index.js +4 -1
- package/dist/llm/prompts.js +246 -56
- package/dist/markdown.js +116 -3
- package/dist/migrations.js +33 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/onboarding-base.js +196 -1
- package/dist/openapi.js +75 -1
- package/dist/openbanking/docs/openbanking.docblock.js +22 -109
- package/dist/ownership.js +40 -1
- package/dist/policy/docs/policy.docblock.js +22 -1
- package/dist/policy/engine.js +223 -1
- package/dist/policy/opa-adapter.js +71 -1
- package/dist/policy/spec.js +33 -1
- package/dist/presentations/docs/presentations-conventions.docblock.js +21 -7
- package/dist/presentations.backcompat.js +47 -1
- package/dist/presentations.d.ts +3 -3
- package/dist/presentations.js +66 -1
- package/dist/presentations.v2.js +278 -6
- package/dist/prompt.js +10 -1
- package/dist/promptRegistry.js +34 -1
- package/dist/regenerator/docs/regenerator.docblock.js +22 -184
- package/dist/regenerator/executor.js +86 -1
- package/dist/regenerator/index.js +6 -1
- package/dist/regenerator/service.js +92 -1
- package/dist/regenerator/sinks.js +32 -1
- package/dist/regenerator/utils.js +51 -1
- package/dist/registry.js +208 -1
- package/dist/resources.js +47 -1
- package/dist/schema/dist/EnumType.js +2 -1
- package/dist/schema/dist/FieldType.js +49 -1
- package/dist/schema/dist/ScalarTypeEnum.js +236 -1
- package/dist/schema/dist/SchemaModel.js +39 -1
- package/dist/schema/dist/entity/defineEntity.js +1 -1
- package/dist/schema/dist/entity/index.js +2 -1
- package/dist/schema/dist/entity/types.js +1 -1
- package/dist/schema/dist/index.js +6 -1
- package/dist/schema-to-markdown.js +214 -10
- package/dist/server/graphql-pothos.js +128 -1
- package/dist/server/index.js +10 -1
- package/dist/server/mcp/createMcpServer.js +28 -1
- package/dist/server/mcp/registerPresentations.js +151 -1
- package/dist/server/mcp/registerPrompts.js +36 -2
- package/dist/server/mcp/registerResources.js +35 -1
- package/dist/server/mcp/registerTools.js +22 -1
- package/dist/server/provider-mcp.js +3 -1
- package/dist/server/rest-elysia.js +20 -1
- package/dist/server/rest-express.js +39 -1
- package/dist/server/rest-generic.js +125 -1
- package/dist/server/rest-next-app.js +38 -1
- package/dist/server/rest-next-mcp.js +45 -1
- package/dist/server/rest-next-pages.js +25 -1
- package/dist/spec.js +35 -1
- package/dist/telemetry/anomaly.js +48 -1
- package/dist/telemetry/docs/telemetry.docblock.js +22 -139
- package/dist/telemetry/index.js +5 -1
- package/dist/telemetry/spec.js +69 -1
- package/dist/telemetry/tracker.js +76 -1
- package/dist/tests/index.js +4 -1
- package/dist/tests/runner.js +150 -1
- package/dist/tests/spec.js +33 -1
- package/dist/themes.js +39 -1
- package/dist/workflow/adapters/db-adapter.js +83 -1
- package/dist/workflow/adapters/file-adapter.js +11 -1
- package/dist/workflow/adapters/index.js +5 -1
- package/dist/workflow/adapters/memory-store.js +58 -1
- package/dist/workflow/expression.js +98 -1
- package/dist/workflow/index.js +9 -1
- package/dist/workflow/runner.js +337 -1
- package/dist/workflow/sla-monitor.js +47 -1
- package/dist/workflow/spec.js +32 -1
- package/dist/workflow/validation.js +175 -1
- package/package.json +11 -4
package/dist/presentations.v2.js
CHANGED
|
@@ -1,7 +1,279 @@
|
|
|
1
|
-
import{schemaToMarkdown
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
`);case`code_block`:{let t=a(e.content);return t?`\`\`\`\n${t}\n\`\`\``:``}case`horizontal_rule`:return`---`;case`hard_break`:return`
|
|
5
|
-
`;case`text`:return i(e);default:return e.text?i(e):``}}function c(e){if(typeof e==`string`)return e;if(e&&typeof e==`object`&&`html`in e){let t=String(e.html);return r.turndown(t)}let t=e;if(t?.type===`doc`||t?.content)return(t.content??[]).map(e=>s(e)).filter(Boolean).join(`
|
|
1
|
+
import { schemaToMarkdown } from "./schema-to-markdown.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import TurndownService from "turndown";
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
//#region src/presentations.v2.ts
|
|
6
|
+
/**
|
|
7
|
+
* Pluggable transform engine that renders descriptors to various targets
|
|
8
|
+
* and runs validators (e.g., basic metadata checks, PII redaction policies).
|
|
9
|
+
*/
|
|
10
|
+
const turndown = new TurndownService();
|
|
11
|
+
function renderTextNode(node) {
|
|
12
|
+
const text = node.text ?? "";
|
|
13
|
+
if (!node.marks || node.marks.length === 0) return text;
|
|
14
|
+
return node.marks.reduce((acc, mark) => {
|
|
15
|
+
switch (mark.type) {
|
|
16
|
+
case "bold": return `**${acc}**`;
|
|
17
|
+
case "italic": return `*${acc}*`;
|
|
18
|
+
case "underline": return `__${acc}__`;
|
|
19
|
+
case "strike": return `~~${acc}~~`;
|
|
20
|
+
case "code": return `\`${acc}\``;
|
|
21
|
+
case "link": {
|
|
22
|
+
const href = mark.attrs?.href ?? "";
|
|
23
|
+
return href ? `[${acc}](${href})` : acc;
|
|
24
|
+
}
|
|
25
|
+
default: return acc;
|
|
26
|
+
}
|
|
27
|
+
}, text);
|
|
28
|
+
}
|
|
29
|
+
function renderInline(nodes) {
|
|
30
|
+
if (!nodes?.length) return "";
|
|
31
|
+
return nodes.map((child) => renderNode(child)).join("");
|
|
32
|
+
}
|
|
33
|
+
function renderList(nodes, ordered = false) {
|
|
34
|
+
if (!nodes?.length) return "";
|
|
35
|
+
let counter = 1;
|
|
36
|
+
return nodes.map((item) => {
|
|
37
|
+
const body = renderInline(item.content ?? []);
|
|
38
|
+
if (!body) return "";
|
|
39
|
+
return `${ordered ? `${counter++}. ` : "- "}${body}`;
|
|
40
|
+
}).filter(Boolean).join("\n");
|
|
41
|
+
}
|
|
42
|
+
function renderNode(node) {
|
|
43
|
+
switch (node.type) {
|
|
44
|
+
case "doc": return renderInline(node.content);
|
|
45
|
+
case "paragraph": {
|
|
46
|
+
const text = renderInline(node.content);
|
|
47
|
+
return text.trim().length ? text : "";
|
|
48
|
+
}
|
|
49
|
+
case "heading": {
|
|
50
|
+
const level = Math.min(Math.max(node.attrs?.level ?? 1, 1), 6);
|
|
51
|
+
return `${"#".repeat(level)} ${renderInline(node.content)}`.trim();
|
|
52
|
+
}
|
|
53
|
+
case "bullet_list": return renderList(node.content, false);
|
|
54
|
+
case "ordered_list": return renderList(node.content, true);
|
|
55
|
+
case "list_item": return renderInline(node.content);
|
|
56
|
+
case "blockquote": return renderInline(node.content).split("\n").map((line) => `> ${line}`).join("\n");
|
|
57
|
+
case "code_block": {
|
|
58
|
+
const body = renderInline(node.content);
|
|
59
|
+
return body ? `\`\`\`\n${body}\n\`\`\`` : "";
|
|
60
|
+
}
|
|
61
|
+
case "horizontal_rule": return "---";
|
|
62
|
+
case "hard_break": return "\n";
|
|
63
|
+
case "text": return renderTextNode(node);
|
|
64
|
+
default:
|
|
65
|
+
if (node.text) return renderTextNode(node);
|
|
66
|
+
return "";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function blockNoteToMarkdown(docJson) {
|
|
70
|
+
if (typeof docJson === "string") return docJson;
|
|
71
|
+
if (docJson && typeof docJson === "object" && "html" in docJson) {
|
|
72
|
+
const html = String(docJson.html);
|
|
73
|
+
return turndown.turndown(html);
|
|
74
|
+
}
|
|
75
|
+
const root = docJson;
|
|
76
|
+
if (root?.type === "doc" || root?.content) return (root.content ?? []).map((n) => renderNode(n)).filter(Boolean).join("\n\n").trim();
|
|
77
|
+
try {
|
|
78
|
+
return JSON.stringify(docJson, null, 2);
|
|
79
|
+
} catch {
|
|
80
|
+
return String(docJson);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
var TransformEngine = class {
|
|
84
|
+
renderers = /* @__PURE__ */ new Map();
|
|
85
|
+
validators = [];
|
|
86
|
+
register(renderer) {
|
|
87
|
+
const arr = this.renderers.get(renderer.target) ?? [];
|
|
88
|
+
arr.push(renderer);
|
|
89
|
+
this.renderers.set(renderer.target, arr);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Register a renderer that will be tried BEFORE existing renderers for the same target.
|
|
94
|
+
* Useful for custom renderers that should take priority over default ones.
|
|
95
|
+
*/
|
|
96
|
+
prependRegister(renderer) {
|
|
97
|
+
const arr = this.renderers.get(renderer.target) ?? [];
|
|
98
|
+
arr.unshift(renderer);
|
|
99
|
+
this.renderers.set(renderer.target, arr);
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
addValidator(v) {
|
|
103
|
+
this.validators.push(v);
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
async render(target, desc, ctx) {
|
|
107
|
+
if (!desc.targets.includes(target)) throw new Error(`Target ${target} not declared for ${desc.meta.name}.v${desc.meta.version}`);
|
|
108
|
+
for (const v of this.validators) await v.validate(desc, target, ctx);
|
|
109
|
+
const arr = this.renderers.get(target) ?? [];
|
|
110
|
+
for (const r of arr) try {
|
|
111
|
+
return await r.render(desc, ctx);
|
|
112
|
+
} catch (_e) {}
|
|
113
|
+
throw new Error(`No renderer available for ${target}`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/** Create a TransformEngine instance with default markdown/json/xml renderers. */
|
|
117
|
+
function createDefaultTransformEngine() {
|
|
118
|
+
const engine = new TransformEngine();
|
|
119
|
+
const applyPii = (desc, obj) => {
|
|
120
|
+
const clone = JSON.parse(JSON.stringify(obj));
|
|
121
|
+
const paths = desc.policy?.pii ?? [];
|
|
122
|
+
const setAtPath = (root, path) => {
|
|
123
|
+
const segs = path.replace(/^\//, "").replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
124
|
+
let cur = root;
|
|
125
|
+
for (let i = 0; i < segs.length - 1; i++) {
|
|
126
|
+
const k = segs[i];
|
|
127
|
+
if (cur && typeof cur === "object" && k in cur) cur = cur[k];
|
|
128
|
+
else return;
|
|
129
|
+
}
|
|
130
|
+
const last = segs[segs.length - 1];
|
|
131
|
+
if (cur && typeof cur === "object" && last && last in cur) cur[last] = "[REDACTED]";
|
|
132
|
+
};
|
|
133
|
+
for (const p of paths) setAtPath(clone, p);
|
|
134
|
+
return clone;
|
|
135
|
+
};
|
|
136
|
+
engine.register({
|
|
137
|
+
target: "markdown",
|
|
138
|
+
async render(desc, ctx) {
|
|
139
|
+
let data = ctx?.data;
|
|
140
|
+
if (!data && ctx?.fetchData) data = await ctx.fetchData();
|
|
141
|
+
if (desc.source.type === "component" && desc.source.props && data !== void 0) {
|
|
142
|
+
const isArray = Array.isArray(data);
|
|
143
|
+
const isSimpleObject = !isArray && typeof data === "object" && data !== null && !Object.values(data).some((v) => Array.isArray(v) || typeof v === "object" && v !== null);
|
|
144
|
+
if (isArray || isSimpleObject) return {
|
|
145
|
+
mimeType: "text/markdown",
|
|
146
|
+
body: schemaToMarkdown(desc.source.props, data, {
|
|
147
|
+
title: desc.meta.description ?? desc.meta.name,
|
|
148
|
+
description: `${desc.meta.name} v${desc.meta.version}`
|
|
149
|
+
})
|
|
150
|
+
};
|
|
151
|
+
throw new Error(`Complex data structure for ${desc.meta.name} - expecting custom renderer`);
|
|
152
|
+
}
|
|
153
|
+
if (desc.source.type === "blocknotejs") {
|
|
154
|
+
const redacted = applyPii(desc, { text: blockNoteToMarkdown(desc.source.docJson) });
|
|
155
|
+
return {
|
|
156
|
+
mimeType: "text/markdown",
|
|
157
|
+
body: String(redacted.text)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (desc.source.type === "component" && data !== void 0) throw new Error(`No schema (source.props) available for ${desc.meta.name} - expecting custom renderer`);
|
|
161
|
+
if (desc.source.type === "component") return {
|
|
162
|
+
mimeType: "text/markdown",
|
|
163
|
+
body: `${`# ${desc.meta.name} v${desc.meta.version}`}${desc.meta.description ? `\n\n${desc.meta.description}` : ""}${desc.meta.tags && desc.meta.tags.length ? `\n\nTags: ${desc.meta.tags.join(", ")}` : ""}${desc.meta.owners && desc.meta.owners.length ? `\n\nOwners: ${desc.meta.owners.join(", ")}` : ""}${`\n\nComponent: \`${desc.source.componentKey}\``}${desc.policy?.pii?.length ? `\n\nRedacted paths: ${desc.policy.pii.map((p) => `\`${p}\``).join(", ")}` : ""}`
|
|
164
|
+
};
|
|
165
|
+
throw new Error("unsupported");
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
engine.register({
|
|
169
|
+
target: "application/json",
|
|
170
|
+
async render(desc) {
|
|
171
|
+
const payload = applyPii(desc, {
|
|
172
|
+
meta: desc.meta,
|
|
173
|
+
source: desc.source
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
mimeType: "application/json",
|
|
177
|
+
body: JSON.stringify(payload, null, 2)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
engine.register({
|
|
182
|
+
target: "application/xml",
|
|
183
|
+
async render(desc) {
|
|
184
|
+
const json = applyPii(desc, {
|
|
185
|
+
meta: desc.meta,
|
|
186
|
+
source: desc.source
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
mimeType: "application/xml",
|
|
190
|
+
body: `<presentation name="${desc.meta.name}" version="${desc.meta.version}"><json>${encodeURIComponent(JSON.stringify(json))}</json></presentation>`
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
return engine;
|
|
195
|
+
}
|
|
196
|
+
/** Register a default React target renderer that returns a serializable descriptor. */
|
|
197
|
+
function registerDefaultReactRenderer(engine) {
|
|
198
|
+
engine.register({
|
|
199
|
+
target: "react",
|
|
200
|
+
async render(desc) {
|
|
201
|
+
if (desc.source.type === "component") {
|
|
202
|
+
const props = desc.source.props ? desc.source.props.getZod().safeParse({}).success ? {} : void 0 : void 0;
|
|
203
|
+
return {
|
|
204
|
+
kind: "react_component",
|
|
205
|
+
componentKey: desc.source.componentKey,
|
|
206
|
+
props
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
kind: "blocknotejs",
|
|
211
|
+
docJson: desc.source.docJson,
|
|
212
|
+
blockConfig: desc.source.blockConfig
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return engine;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Add basic validators (e.g., meta.description presence) to the engine.
|
|
220
|
+
*/
|
|
221
|
+
function registerBasicValidation(engine) {
|
|
222
|
+
engine.addValidator({ validate(desc) {
|
|
223
|
+
if (!desc.meta.description || desc.meta.description.length < 3) throw new Error(`Presentation ${desc.meta.name}.v${desc.meta.version} missing meta.description`);
|
|
224
|
+
} });
|
|
225
|
+
return engine;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Register a React-to-markdown renderer that renders React components to HTML
|
|
229
|
+
* and converts them to markdown using turndown.
|
|
230
|
+
* This renderer takes priority over the default metadata-only renderer.
|
|
231
|
+
*/
|
|
232
|
+
function registerReactToMarkdownRenderer(engine, componentMap) {
|
|
233
|
+
const turndownService = new TurndownService({
|
|
234
|
+
headingStyle: "atx",
|
|
235
|
+
codeBlockStyle: "fenced",
|
|
236
|
+
bulletListMarker: "-"
|
|
237
|
+
});
|
|
238
|
+
turndownService.addRule("link", {
|
|
239
|
+
filter: "a",
|
|
240
|
+
replacement: (content, node) => {
|
|
241
|
+
const href = node.href;
|
|
242
|
+
if (href && content) return `[${content}](${href})`;
|
|
243
|
+
return content || "";
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
engine.prependRegister({
|
|
247
|
+
target: "markdown",
|
|
248
|
+
async render(desc, ctx) {
|
|
249
|
+
if (desc.source.type !== "component") throw new Error("React-to-markdown renderer only handles component presentations");
|
|
250
|
+
const { renderToStaticMarkup } = await import("react-dom/server");
|
|
251
|
+
const Component = componentMap[desc.source.componentKey];
|
|
252
|
+
if (!Component) throw new Error(`Component ${desc.source.componentKey} not found in componentMap`);
|
|
253
|
+
let html;
|
|
254
|
+
try {
|
|
255
|
+
html = renderToStaticMarkup(React.createElement(Component, desc.source.props ? {} : void 0));
|
|
256
|
+
} catch (error) {
|
|
257
|
+
throw new Error(`Failed to render component ${desc.source.componentKey}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
258
|
+
}
|
|
259
|
+
let markdown;
|
|
260
|
+
try {
|
|
261
|
+
markdown = turndownService.turndown(html);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw new Error(`Failed to convert HTML to markdown: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
264
|
+
}
|
|
265
|
+
if (desc.policy?.pii && desc.policy.pii.length > 0) return {
|
|
266
|
+
mimeType: "text/markdown",
|
|
267
|
+
body: markdown.replace(/\[REDACTED\]/g, "[REDACTED]")
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
mimeType: "text/markdown",
|
|
271
|
+
body: markdown
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
return engine;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
export { TransformEngine, createDefaultTransformEngine, registerBasicValidation, registerDefaultReactRenderer, registerReactToMarkdownRenderer };
|
package/dist/prompt.js
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
import"zod";
|
|
1
|
+
import "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/prompt.ts
|
|
4
|
+
/** Identity helper that preserves generic inference when declaring prompts. */
|
|
5
|
+
function definePrompt(spec) {
|
|
6
|
+
return spec;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { definePrompt };
|
package/dist/promptRegistry.js
CHANGED
|
@@ -1 +1,34 @@
|
|
|
1
|
-
import"zod";
|
|
1
|
+
import "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/promptRegistry.ts
|
|
4
|
+
var PromptRegistry = class {
|
|
5
|
+
prompts = /* @__PURE__ */ new Map();
|
|
6
|
+
/** Register a prompt. Throws on duplicate name+version. */
|
|
7
|
+
register(p) {
|
|
8
|
+
const key = `${p.meta.name}.v${p.meta.version}`;
|
|
9
|
+
if (this.prompts.has(key)) throw new Error(`Duplicate prompt ${key}`);
|
|
10
|
+
this.prompts.set(key, p);
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
/** List all registered prompts. */
|
|
14
|
+
list() {
|
|
15
|
+
return [...this.prompts.values()];
|
|
16
|
+
}
|
|
17
|
+
/** Get prompt by name; when version omitted, returns highest version. */
|
|
18
|
+
get(name, version) {
|
|
19
|
+
if (version != null) return this.prompts.get(`${name}.v${version}`);
|
|
20
|
+
let candidate;
|
|
21
|
+
let max = -Infinity;
|
|
22
|
+
for (const [k, p] of this.prompts.entries()) {
|
|
23
|
+
if (!k.startsWith(`${name}.v`)) continue;
|
|
24
|
+
if (p.meta.version > max) {
|
|
25
|
+
max = p.meta.version;
|
|
26
|
+
candidate = p;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return candidate;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { PromptRegistry };
|
|
@@ -1,184 +1,22 @@
|
|
|
1
|
-
import{registerDocBlocks
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
### Key types
|
|
24
|
-
|
|
25
|
-
\`\`\`ts
|
|
26
|
-
export interface RegenerationContext {
|
|
27
|
-
id: string;
|
|
28
|
-
blueprint: AppBlueprintSpec;
|
|
29
|
-
tenantConfig: TenantAppConfig;
|
|
30
|
-
resolved: ResolvedAppConfig;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface RegeneratorRule {
|
|
34
|
-
id: string;
|
|
35
|
-
description: string;
|
|
36
|
-
evaluate(
|
|
37
|
-
context: RegenerationContext,
|
|
38
|
-
signals: RegeneratorSignal[]
|
|
39
|
-
): Promise<SpecChangeProposal[]>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface SpecChangeProposal {
|
|
43
|
-
id: string;
|
|
44
|
-
title: string;
|
|
45
|
-
summary: string;
|
|
46
|
-
confidence: 'low' | 'medium' | 'high';
|
|
47
|
-
target: ProposalTarget;
|
|
48
|
-
actions: ProposalAction[];
|
|
49
|
-
blockers?: ProposalBlocker[];
|
|
50
|
-
signalIds: string[];
|
|
51
|
-
createdAt: Date;
|
|
52
|
-
}
|
|
53
|
-
\`\`\`
|
|
54
|
-
|
|
55
|
-
- Signals are normalized envelopes: telemetry (\`count\`, anomaly score), errors, and behavior trends.
|
|
56
|
-
- Proposals reference blueprint or tenant specs via \`ProposalTarget\`.
|
|
57
|
-
- Actions encode what the automation should perform (update blueprint, run tests/migrations, trigger regeneration).
|
|
58
|
-
|
|
59
|
-
### Providing signals
|
|
60
|
-
|
|
61
|
-
Implement \`TelemetrySignalProvider\`, \`ErrorSignalProvider\`, or \`BehaviorSignalProvider\`:
|
|
62
|
-
|
|
63
|
-
\`\`\`ts
|
|
64
|
-
const service = new RegeneratorService({
|
|
65
|
-
contexts,
|
|
66
|
-
adapters: {
|
|
67
|
-
telemetry: new PosthogTelemetryAdapter(),
|
|
68
|
-
errors: new SentryErrorAdapter(),
|
|
69
|
-
},
|
|
70
|
-
rules: [new WorkflowFailureRule(), new DataViewUsageRule()],
|
|
71
|
-
sink: new ProposalQueueSink(),
|
|
72
|
-
pollIntervalMs: 60_000,
|
|
73
|
-
});
|
|
74
|
-
\`\`\`
|
|
75
|
-
|
|
76
|
-
Adapters receive the full \`RegenerationContext\`, making it easy to scope queries per tenant/app.
|
|
77
|
-
|
|
78
|
-
### Authoring rules
|
|
79
|
-
|
|
80
|
-
Rules focus on signals → proposals:
|
|
81
|
-
|
|
82
|
-
\`\`\`ts
|
|
83
|
-
class WorkflowFailureRule implements RegeneratorRule {
|
|
84
|
-
id = 'workflow-failure';
|
|
85
|
-
description = 'Suggest splitting workflows that exceed failure thresholds';
|
|
86
|
-
|
|
87
|
-
async evaluate(context, signals) {
|
|
88
|
-
const failures = signals.filter(
|
|
89
|
-
(signal) =>
|
|
90
|
-
signal.type === 'telemetry' &&
|
|
91
|
-
signal.signal.eventName === 'workflow.failure' &&
|
|
92
|
-
signal.signal.count >= 10
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
if (failures.length === 0) return [];
|
|
96
|
-
|
|
97
|
-
return [
|
|
98
|
-
{
|
|
99
|
-
id: \`\${this.id}-\${context.id}\`,
|
|
100
|
-
title: 'Split onboarding workflow',
|
|
101
|
-
summary: 'Step 3 fails consistently; propose dedicated remediation branch.',
|
|
102
|
-
confidence: 'medium',
|
|
103
|
-
rationale: ['Failure count ≥ 10 within last window'],
|
|
104
|
-
target: {
|
|
105
|
-
specType: 'workflow',
|
|
106
|
-
reference: { name: 'onboarding.workflow', version: 1 },
|
|
107
|
-
tenantScoped: true,
|
|
108
|
-
},
|
|
109
|
-
actions: [
|
|
110
|
-
{ kind: 'update_tenant_config', summary: 'Add alternate fallback path' },
|
|
111
|
-
{ kind: 'run_tests', tests: ['workflows/onboarding.spec.ts'] },
|
|
112
|
-
],
|
|
113
|
-
signalIds: failures.map((f) => f.signal.eventName),
|
|
114
|
-
createdAt: new Date(),
|
|
115
|
-
},
|
|
116
|
-
];
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
\`\`\`
|
|
120
|
-
|
|
121
|
-
### Reviewing proposals
|
|
122
|
-
|
|
123
|
-
Proposals flow to a \`ProposalSink\` (queue, DB, messaging bus). The Studio will surface:
|
|
124
|
-
|
|
125
|
-
1. Signal evidence (telemetry counts, error metadata)
|
|
126
|
-
2. Proposed spec diffs and required actions (tests/migrations)
|
|
127
|
-
3. Approval workflow (approve → write spec diff → run automation)
|
|
128
|
-
|
|
129
|
-
### CLI driver
|
|
130
|
-
|
|
131
|
-
Run the regenerator daemon from the CLI:
|
|
132
|
-
|
|
133
|
-
\`\`\`bash
|
|
134
|
-
bunx contracts regenerator ./app.blueprint.ts ./tenant.config.ts ./regenerator.rules.ts auto \\
|
|
135
|
-
--executor ./regenerator.executor.ts \\
|
|
136
|
-
--poll-interval 60000 \\
|
|
137
|
-
--batch-duration 300000 \\
|
|
138
|
-
--dry-run
|
|
139
|
-
\`\`\`
|
|
140
|
-
|
|
141
|
-
- Expects modules exporting default \`AppBlueprintSpec\`, \`TenantAppConfig\`, and one or more \`RegenerationRule\`s.
|
|
142
|
-
- Pass a sink module path, or use the special \`auto\` value with \`--executor <module>\` to instantiate an \`ExecutorProposalSink\`.
|
|
143
|
-
- Executor modules can export a \`ProposalExecutor\` instance, a factory, or a plain dependency object for the executor constructor. Optional exports: \`sinkOptions\`, \`logger\`, \`onResult\`, \`dryRun\`.
|
|
144
|
-
- Optionally provide \`--contexts ./contexts.ts\` to load custom context arrays (advanced multi-tenant scenarios).
|
|
145
|
-
- Use \`--dry-run\` to preview actions without mutating specs/configs, and \`--once\` for CI smoke tests.
|
|
146
|
-
|
|
147
|
-
### Proposal executor
|
|
148
|
-
|
|
149
|
-
\`ProposalExecutor\` + \`ExecutorProposalSink\` orchestrate follow-up actions once a proposal is approved:
|
|
150
|
-
|
|
151
|
-
- Interfaces for applying blueprint or tenant-config updates (\`BlueprintUpdater\`, \`TenantConfigUpdater\`).
|
|
152
|
-
- Hooks for running contract tests and migrations (\`TestExecutor\`, \`MigrationExecutor\`).
|
|
153
|
-
- Optional trigger to recompose the runtime (\`RegenerationTrigger\`).
|
|
154
|
-
- Built-in \`dryRun\` mode to preview outcomes.
|
|
155
|
-
- Pluggable result logging/forwarding via \`ExecutorSinkOptions\`.
|
|
156
|
-
|
|
157
|
-
\`\`\`ts
|
|
158
|
-
import {
|
|
159
|
-
ProposalExecutor,
|
|
160
|
-
ExecutorProposalSink,
|
|
161
|
-
} from '@lssm/lib.contracts/regenerator';
|
|
162
|
-
|
|
163
|
-
const executor = new ProposalExecutor({
|
|
164
|
-
tenantConfigUpdater,
|
|
165
|
-
testExecutor,
|
|
166
|
-
migrationExecutor,
|
|
167
|
-
regenerationTrigger,
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const sink = new ExecutorProposalSink(executor, {
|
|
171
|
-
dryRun: false,
|
|
172
|
-
onResult: ({ result }) => console.log(result.status),
|
|
173
|
-
});
|
|
174
|
-
\`\`\`
|
|
175
|
-
|
|
176
|
-
Execution results include per-action status (\`success\`, \`skipped\`, \`failed\`) plus aggregated proposal status (\`success\`, \`partial\`, \`failed\`). Missing dependencies mark actions as \`skipped\`, making it easy to plug into partial automation flows today and extend later.
|
|
177
|
-
|
|
178
|
-
### Next steps
|
|
179
|
-
|
|
180
|
-
- Build adapters for existing telemetry/error providers.
|
|
181
|
-
- Encode canonical rules (workflow failure, feature under-use, high latency).
|
|
182
|
-
- Integrate with App Studio proposal inbox and automate acceptance (write spec diff, run tests, queue migrations).
|
|
183
|
-
|
|
184
|
-
`}];e(t);export{t as tech_contracts_regenerator_DocBlocks};
|
|
1
|
+
import { registerDocBlocks } from "../../docs/registry.js";
|
|
2
|
+
import "../../registry.js";
|
|
3
|
+
|
|
4
|
+
//#region src/regenerator/docs/regenerator.docblock.ts
|
|
5
|
+
const tech_contracts_regenerator_DocBlocks = [{
|
|
6
|
+
id: "docs.tech.contracts.regenerator",
|
|
7
|
+
title: "Regenerator Service",
|
|
8
|
+
summary: "The Regenerator daemon observes telemetry, error, and behavior streams, then suggests spec-level changes (not code patches) that can be reviewed and applied through the App Studio.",
|
|
9
|
+
kind: "reference",
|
|
10
|
+
visibility: "public",
|
|
11
|
+
route: "/docs/tech/contracts/regenerator",
|
|
12
|
+
tags: [
|
|
13
|
+
"tech",
|
|
14
|
+
"contracts",
|
|
15
|
+
"regenerator"
|
|
16
|
+
],
|
|
17
|
+
body: "## Regenerator Service\n\nThe Regenerator daemon observes telemetry, error, and behavior streams, then suggests spec-level changes (not code patches) that can be reviewed and applied through the App Studio.\n\n- Runtime entrypoint: `packages/libs/contracts/src/regenerator/service.ts`\n- Types/interfaces: `packages/libs/contracts/src/regenerator/types.ts`\n- Signal adapters: `packages/libs/contracts/src/regenerator/adapters.ts`\n\n### Architecture\n\n```text\nSignal Adapters ──► RegeneratorService ──► Rules ──► ProposalSink\n ▲ │\n │ ▼\n Telemetry / Errors / Behavior Spec change proposals\n```\n\n1. **Signal adapters** pull batches of telemetry, error logs, or behavior metrics for each `RegenerationContext`.\n2. `RegeneratorService` schedules polling (`resolveAppConfig` + `composeAppConfig` provide context).\n3. **Rules** implement domain heuristics and emit `SpecChangeProposal` objects.\n4. **Proposal sinks** persist or forward proposals for human review.\n\n### Key types\n\n```ts\nexport interface RegenerationContext {\n id: string;\n blueprint: AppBlueprintSpec;\n tenantConfig: TenantAppConfig;\n resolved: ResolvedAppConfig;\n}\n\nexport interface RegeneratorRule {\n id: string;\n description: string;\n evaluate(\n context: RegenerationContext,\n signals: RegeneratorSignal[]\n ): Promise<SpecChangeProposal[]>;\n}\n\nexport interface SpecChangeProposal {\n id: string;\n title: string;\n summary: string;\n confidence: 'low' | 'medium' | 'high';\n target: ProposalTarget;\n actions: ProposalAction[];\n blockers?: ProposalBlocker[];\n signalIds: string[];\n createdAt: Date;\n}\n```\n\n- Signals are normalized envelopes: telemetry (`count`, anomaly score), errors, and behavior trends.\n- Proposals reference blueprint or tenant specs via `ProposalTarget`.\n- Actions encode what the automation should perform (update blueprint, run tests/migrations, trigger regeneration).\n\n### Providing signals\n\nImplement `TelemetrySignalProvider`, `ErrorSignalProvider`, or `BehaviorSignalProvider`:\n\n```ts\nconst service = new RegeneratorService({\n contexts,\n adapters: {\n telemetry: new PosthogTelemetryAdapter(),\n errors: new SentryErrorAdapter(),\n },\n rules: [new WorkflowFailureRule(), new DataViewUsageRule()],\n sink: new ProposalQueueSink(),\n pollIntervalMs: 60_000,\n});\n```\n\nAdapters receive the full `RegenerationContext`, making it easy to scope queries per tenant/app.\n\n### Authoring rules\n\nRules focus on signals → proposals:\n\n```ts\nclass WorkflowFailureRule implements RegeneratorRule {\n id = 'workflow-failure';\n description = 'Suggest splitting workflows that exceed failure thresholds';\n\n async evaluate(context, signals) {\n const failures = signals.filter(\n (signal) =>\n signal.type === 'telemetry' &&\n signal.signal.eventName === 'workflow.failure' &&\n signal.signal.count >= 10\n );\n\n if (failures.length === 0) return [];\n\n return [\n {\n id: `${this.id}-${context.id}`,\n title: 'Split onboarding workflow',\n summary: 'Step 3 fails consistently; propose dedicated remediation branch.',\n confidence: 'medium',\n rationale: ['Failure count ≥ 10 within last window'],\n target: {\n specType: 'workflow',\n reference: { name: 'onboarding.workflow', version: 1 },\n tenantScoped: true,\n },\n actions: [\n { kind: 'update_tenant_config', summary: 'Add alternate fallback path' },\n { kind: 'run_tests', tests: ['workflows/onboarding.spec.ts'] },\n ],\n signalIds: failures.map((f) => f.signal.eventName),\n createdAt: new Date(),\n },\n ];\n }\n}\n```\n\n### Reviewing proposals\n\nProposals flow to a `ProposalSink` (queue, DB, messaging bus). The Studio will surface:\n\n1. Signal evidence (telemetry counts, error metadata)\n2. Proposed spec diffs and required actions (tests/migrations)\n3. Approval workflow (approve → write spec diff → run automation)\n\n### CLI driver\n\nRun the regenerator daemon from the CLI:\n\n```bash\nbunx contracts regenerator ./app.blueprint.ts ./tenant.config.ts ./regenerator.rules.ts auto \\\n --executor ./regenerator.executor.ts \\\n --poll-interval 60000 \\\n --batch-duration 300000 \\\n --dry-run\n```\n\n- Expects modules exporting default `AppBlueprintSpec`, `TenantAppConfig`, and one or more `RegenerationRule`s.\n- Pass a sink module path, or use the special `auto` value with `--executor <module>` to instantiate an `ExecutorProposalSink`.\n- Executor modules can export a `ProposalExecutor` instance, a factory, or a plain dependency object for the executor constructor. Optional exports: `sinkOptions`, `logger`, `onResult`, `dryRun`.\n- Optionally provide `--contexts ./contexts.ts` to load custom context arrays (advanced multi-tenant scenarios).\n- Use `--dry-run` to preview actions without mutating specs/configs, and `--once` for CI smoke tests.\n\n### Proposal executor\n\n`ProposalExecutor` + `ExecutorProposalSink` orchestrate follow-up actions once a proposal is approved:\n\n- Interfaces for applying blueprint or tenant-config updates (`BlueprintUpdater`, `TenantConfigUpdater`).\n- Hooks for running contract tests and migrations (`TestExecutor`, `MigrationExecutor`).\n- Optional trigger to recompose the runtime (`RegenerationTrigger`).\n- Built-in `dryRun` mode to preview outcomes.\n- Pluggable result logging/forwarding via `ExecutorSinkOptions`.\n\n```ts\nimport {\n ProposalExecutor,\n ExecutorProposalSink,\n} from '@lssm/lib.contracts/regenerator';\n\nconst executor = new ProposalExecutor({\n tenantConfigUpdater,\n testExecutor,\n migrationExecutor,\n regenerationTrigger,\n});\n\nconst sink = new ExecutorProposalSink(executor, {\n dryRun: false,\n onResult: ({ result }) => console.log(result.status),\n});\n```\n\nExecution results include per-action status (`success`, `skipped`, `failed`) plus aggregated proposal status (`success`, `partial`, `failed`). Missing dependencies mark actions as `skipped`, making it easy to plug into partial automation flows today and extend later.\n\n### Next steps\n\n- Build adapters for existing telemetry/error providers.\n- Encode canonical rules (workflow failure, feature under-use, high latency).\n- Integrate with App Studio proposal inbox and automate acceptance (write spec diff, run tests, queue migrations).\n\n"
|
|
18
|
+
}];
|
|
19
|
+
registerDocBlocks(tech_contracts_regenerator_DocBlocks);
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { tech_contracts_regenerator_DocBlocks };
|
|
@@ -1 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/regenerator/executor.ts
|
|
2
|
+
var ProposalExecutor = class {
|
|
3
|
+
constructor(deps = {}) {
|
|
4
|
+
this.deps = deps;
|
|
5
|
+
}
|
|
6
|
+
async execute(context, proposal, options = {}) {
|
|
7
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
8
|
+
const actionResults = [];
|
|
9
|
+
for (const [index, action] of proposal.actions.entries()) {
|
|
10
|
+
const result = await this.executeAction({
|
|
11
|
+
index,
|
|
12
|
+
action,
|
|
13
|
+
context,
|
|
14
|
+
proposal,
|
|
15
|
+
options
|
|
16
|
+
});
|
|
17
|
+
actionResults.push(result);
|
|
18
|
+
}
|
|
19
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
20
|
+
const summaryStatus = summarizeStatus(actionResults);
|
|
21
|
+
return {
|
|
22
|
+
proposalId: proposal.id,
|
|
23
|
+
contextId: context.id,
|
|
24
|
+
startedAt,
|
|
25
|
+
finishedAt,
|
|
26
|
+
status: summaryStatus,
|
|
27
|
+
actions: actionResults
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async executeAction({ index, action, context, proposal, options }) {
|
|
31
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
32
|
+
const dryRun = options.dryRun ?? false;
|
|
33
|
+
const complete = (status, params = {}) => ({
|
|
34
|
+
index,
|
|
35
|
+
action,
|
|
36
|
+
status,
|
|
37
|
+
startedAt,
|
|
38
|
+
finishedAt: /* @__PURE__ */ new Date(),
|
|
39
|
+
reason: params.reason,
|
|
40
|
+
output: params.output,
|
|
41
|
+
error: params.error
|
|
42
|
+
});
|
|
43
|
+
if (dryRun) return complete("skipped", { reason: "dry_run" });
|
|
44
|
+
try {
|
|
45
|
+
switch (action.kind) {
|
|
46
|
+
case "update_blueprint": {
|
|
47
|
+
const updater = this.deps.blueprintUpdater;
|
|
48
|
+
if (!updater) return complete("skipped", { reason: "missing_blueprint_updater" });
|
|
49
|
+
return complete("success", { output: await updater.applyBlueprintUpdate(context, proposal, action) });
|
|
50
|
+
}
|
|
51
|
+
case "update_tenant_config": {
|
|
52
|
+
const updater = this.deps.tenantConfigUpdater;
|
|
53
|
+
if (!updater) return complete("skipped", { reason: "missing_tenant_config_updater" });
|
|
54
|
+
return complete("success", { output: await updater.applyTenantConfigUpdate(context, proposal, action) });
|
|
55
|
+
}
|
|
56
|
+
case "run_tests": {
|
|
57
|
+
const executor = this.deps.testExecutor;
|
|
58
|
+
if (!executor) return complete("skipped", { reason: "missing_test_executor" });
|
|
59
|
+
return complete("success", { output: await executor.runTests(context, proposal, action) });
|
|
60
|
+
}
|
|
61
|
+
case "run_migrations": {
|
|
62
|
+
const executor = this.deps.migrationExecutor;
|
|
63
|
+
if (!executor) return complete("skipped", { reason: "missing_migration_executor" });
|
|
64
|
+
return complete("success", { output: await executor.runMigrations(context, proposal, action) });
|
|
65
|
+
}
|
|
66
|
+
case "trigger_regeneration": {
|
|
67
|
+
const trigger = this.deps.regenerationTrigger;
|
|
68
|
+
if (!trigger) return complete("skipped", { reason: "missing_regeneration_trigger" });
|
|
69
|
+
return complete("success", { output: await trigger.triggerRegeneration(context, proposal, action) });
|
|
70
|
+
}
|
|
71
|
+
default: return complete("skipped", { reason: "unknown_action" });
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return complete("failed", { error: error instanceof Error ? error : new Error(String(error)) });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function summarizeStatus(actionResults) {
|
|
79
|
+
if (actionResults.some((result) => result.status === "failed")) return "failed";
|
|
80
|
+
if (actionResults.some((result) => result.status === "success") && actionResults.some((result) => result.status === "skipped")) return "partial";
|
|
81
|
+
if (actionResults.every((result) => result.status === "skipped")) return "partial";
|
|
82
|
+
return "success";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { ProposalExecutor };
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
import{behaviorToEnvelope
|
|
1
|
+
import { behaviorToEnvelope, errorToEnvelope, telemetryToEnvelope } from "./utils.js";
|
|
2
|
+
import { RegeneratorService } from "./service.js";
|
|
3
|
+
import { ProposalExecutor } from "./executor.js";
|
|
4
|
+
import { ExecutorProposalSink } from "./sinks.js";
|
|
5
|
+
|
|
6
|
+
export { ExecutorProposalSink, ProposalExecutor, RegeneratorService, behaviorToEnvelope, errorToEnvelope, telemetryToEnvelope };
|