@lssm/lib.contracts 1.11.1 → 1.41.1
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/README.md +1 -1
- package/dist/_virtual/rolldown_runtime.js +1 -0
- package/dist/app-config/app-config.feature.js +1 -0
- package/dist/app-config/contracts.js +1 -1
- package/dist/app-config/docs/app-config.docblock.js +220 -0
- package/dist/app-config/events.js +1 -1
- package/dist/app-config/index.js +1 -1
- package/dist/app-config/lifecycle-contracts.js +1 -1
- package/dist/capabilities/docs/capabilities.docblock.js +1 -0
- package/dist/contract-registry/index.js +1 -0
- package/dist/contract-registry/schemas.js +1 -0
- package/dist/contract-registry/types.js +0 -0
- package/dist/data-views/docs/data-views.docblock.js +1 -0
- package/dist/docs/PUBLISHING.docblock.js +76 -0
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +350 -0
- package/dist/docs/index.js +1 -0
- package/dist/docs/meta.docs.js +13 -0
- package/dist/docs/presentations.js +1 -0
- package/dist/docs/registry.js +1 -0
- package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +383 -0
- package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +68 -0
- package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +140 -0
- package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +86 -0
- package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +1 -0
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +58 -0
- package/dist/docs/tech/contracts/README.docblock.js +1 -0
- package/dist/docs/tech/contracts/create-subscription.docblock.js +1 -0
- package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +180 -0
- package/dist/docs/tech/contracts/migrations.docblock.js +1 -0
- package/dist/docs/tech/contracts/openapi-export.docblock.js +38 -0
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +62 -0
- package/dist/docs/tech/contracts/overlays.docblock.js +68 -0
- package/dist/docs/tech/contracts/tests.docblock.js +132 -0
- package/dist/docs/tech/contracts/themes.docblock.js +1 -0
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +106 -0
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +213 -0
- package/dist/docs/tech/llm/llm-integration.docblock.js +289 -0
- package/dist/docs/tech/mcp-endpoints.docblock.js +1 -0
- package/dist/docs/tech/presentation-runtime.docblock.js +1 -0
- package/dist/docs/tech/schema/README.docblock.js +262 -0
- package/dist/docs/tech/studio/learning-events.docblock.js +1 -0
- package/dist/docs/tech/studio/learning-journeys.docblock.js +57 -0
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +63 -0
- package/dist/docs/tech/studio/project-access-teams.docblock.js +36 -0
- package/dist/docs/tech/studio/project-routing.docblock.js +1 -0
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +20 -0
- package/dist/docs/tech/studio/team-invitations.docblock.js +65 -0
- package/dist/docs/tech/studio/workspace-ops.docblock.js +1 -0
- package/dist/docs/tech/studio/workspaces.docblock.js +41 -0
- package/dist/docs/tech/telemetry-ingest.docblock.js +122 -0
- package/dist/docs/tech/templates/runtime.docblock.js +1 -0
- package/dist/docs/tech/vscode-extension.docblock.js +68 -0
- package/dist/docs/tech/workflows/overview.docblock.js +1 -0
- package/dist/docs/tech-contracts.docs.js +76 -0
- package/dist/docs/types.js +0 -0
- package/dist/events.js +1 -1
- package/dist/experiments/docs/experiments.docblock.js +128 -0
- package/dist/forms/docs/forms.docblock.js +1 -0
- package/dist/index.js +1 -1
- package/dist/install.js +1 -1
- package/dist/integrations/contracts.js +1 -1
- package/dist/integrations/docs/integrations.docblock.js +1 -0
- package/dist/integrations/index.js +1 -1
- package/dist/integrations/openbanking/contracts/accounts.js +1 -1
- package/dist/integrations/openbanking/contracts/balances.js +1 -1
- package/dist/integrations/openbanking/contracts/index.js +1 -1
- package/dist/integrations/openbanking/contracts/transactions.js +1 -1
- package/dist/integrations/openbanking/models.js +1 -1
- package/dist/integrations/openbanking/openbanking.feature.js +1 -0
- package/dist/integrations/providers/impls/index.js +1 -1
- package/dist/integrations/providers/impls/provider-factory.js +1 -1
- package/dist/integrations/providers/index.js +1 -1
- package/dist/integrations/providers/registry.js +1 -0
- package/dist/integrations/secrets/aws-secret-manager.js +1 -0
- package/dist/integrations/secrets/gcp-secret-manager.js +1 -1
- package/dist/integrations/secrets/index.js +1 -1
- package/dist/integrations/secrets/scaleway-secret-manager.js +1 -0
- package/dist/jobs/define-job.js +1 -0
- package/dist/jobs/gcp-cloud-tasks.js +1 -1
- package/dist/jobs/gcp-pubsub.js +1 -1
- package/dist/jobs/handlers/index.js +1 -1
- package/dist/jobs/handlers/ping-handler.js +1 -0
- package/dist/jobs/index.js +1 -1
- package/dist/jobs/memory-queue.js +1 -1
- package/dist/jobs/queue.js +1 -0
- package/dist/jobs/scaleway-sqs-queue.js +1 -0
- package/dist/knowledge/contracts.js +1 -1
- package/dist/knowledge/docs/knowledge.docblock.js +138 -0
- package/dist/llm/exporters.js +8 -0
- package/dist/llm/index.js +1 -0
- package/dist/llm/prompts.js +220 -0
- package/dist/llm/types.js +0 -0
- package/dist/onboarding-base.js +1 -1
- package/dist/openapi.js +1 -0
- package/dist/openbanking/docs/openbanking.docblock.js +109 -0
- package/dist/policy/docs/policy.docblock.js +1 -0
- package/dist/presentations/docs/presentations-conventions.docblock.js +8 -0
- package/dist/presentations.js +1 -1
- package/dist/presentations.v2.js +7 -1
- package/dist/prompt.js +1 -1
- package/dist/promptRegistry.js +1 -1
- package/dist/regenerator/docs/regenerator.docblock.js +184 -0
- package/dist/registry.js +1 -1
- package/dist/resources.js +1 -1
- package/dist/schema-to-markdown.js +10 -0
- package/dist/server/graphql-pothos.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/mcp/createMcpServer.js +1 -0
- package/dist/server/mcp/mcpTypes.js +0 -0
- package/dist/server/mcp/registerPresentations.js +1 -0
- package/dist/server/mcp/registerPrompts.js +3 -0
- package/dist/server/mcp/registerResources.js +1 -0
- package/dist/server/mcp/registerTools.js +1 -0
- package/dist/server/provider-mcp.js +1 -1
- package/dist/telemetry/docs/telemetry.docblock.js +139 -0
- package/package.json +354 -193
- package/dist/app-config/branding.d.ts +0 -55
- package/dist/app-config/contracts.d.ts +0 -244
- package/dist/app-config/events.d.ts +0 -122
- package/dist/app-config/index.d.ts +0 -8
- package/dist/app-config/lifecycle-contracts.d.ts +0 -382
- package/dist/app-config/lifecycle.d.ts +0 -27
- package/dist/app-config/runtime.d.ts +0 -114
- package/dist/app-config/spec.d.ts +0 -175
- package/dist/app-config/validation.d.ts +0 -47
- package/dist/capabilities/openbanking.d.ts +0 -9
- package/dist/capabilities.d.ts +0 -45
- package/dist/client/index.d.ts +0 -6
- package/dist/client/react/drivers/rn-reusables.d.ts +0 -22
- package/dist/client/react/drivers/shadcn.d.ts +0 -12
- package/dist/client/react/feature-render.d.ts +0 -20
- package/dist/client/react/form-render.d.ts +0 -91
- package/dist/client/react/index.d.ts +0 -5
- package/dist/contracts-adapter-hydration.d.ts +0 -15
- package/dist/contracts-adapter-input.d.ts +0 -10
- package/dist/data-views/query-generator.d.ts +0 -39
- package/dist/data-views/runtime.d.ts +0 -26
- package/dist/data-views.d.ts +0 -131
- package/dist/events.d.ts +0 -44
- package/dist/experiments/evaluator.d.ts +0 -37
- package/dist/experiments/spec-resolver.d.ts +0 -16
- package/dist/experiments/spec.d.ts +0 -89
- package/dist/features.d.ts +0 -87
- package/dist/forms.d.ts +0 -258
- package/dist/graphql-federation/dist/index.js +0 -1
- package/dist/index.d.ts +0 -130
- package/dist/install.d.ts +0 -76
- package/dist/integrations/binding.d.ts +0 -17
- package/dist/integrations/connection.d.ts +0 -51
- package/dist/integrations/contracts.d.ts +0 -435
- package/dist/integrations/health.d.ts +0 -21
- package/dist/integrations/index.d.ts +0 -53
- package/dist/integrations/openbanking/contracts/accounts.d.ts +0 -287
- package/dist/integrations/openbanking/contracts/balances.d.ts +0 -163
- package/dist/integrations/openbanking/contracts/index.d.ts +0 -9
- package/dist/integrations/openbanking/contracts/transactions.d.ts +0 -211
- package/dist/integrations/openbanking/guards.d.ts +0 -12
- package/dist/integrations/openbanking/models.d.ts +0 -228
- package/dist/integrations/openbanking/telemetry.d.ts +0 -15
- package/dist/integrations/providers/calendar.d.ts +0 -78
- package/dist/integrations/providers/elevenlabs.d.ts +0 -7
- package/dist/integrations/providers/email.d.ts +0 -86
- package/dist/integrations/providers/embedding.d.ts +0 -24
- package/dist/integrations/providers/gcs-storage.d.ts +0 -7
- package/dist/integrations/providers/gmail.d.ts +0 -7
- package/dist/integrations/providers/google-calendar.d.ts +0 -7
- package/dist/integrations/providers/impls/elevenlabs-voice.d.ts +0 -20
- package/dist/integrations/providers/impls/gcs-storage.d.ts +0 -24
- package/dist/integrations/providers/impls/gmail-inbound.d.ts +0 -26
- package/dist/integrations/providers/impls/gmail-outbound.d.ts +0 -18
- package/dist/integrations/providers/impls/google-calendar.d.ts +0 -23
- package/dist/integrations/providers/impls/index.d.ts +0 -15
- package/dist/integrations/providers/impls/mistral-embedding.d.ts +0 -23
- package/dist/integrations/providers/impls/mistral-llm.d.ts +0 -31
- package/dist/integrations/providers/impls/postmark-email.d.ts +0 -19
- package/dist/integrations/providers/impls/powens-client.d.ts +0 -124
- package/dist/integrations/providers/impls/powens-openbanking.d.ts +0 -27
- package/dist/integrations/providers/impls/provider-factory.d.ts +0 -26
- package/dist/integrations/providers/impls/qdrant-vector.d.ts +0 -24
- package/dist/integrations/providers/impls/stripe-payments.d.ts +0 -28
- package/dist/integrations/providers/impls/twilio-sms.d.ts +0 -20
- package/dist/integrations/providers/index.d.ts +0 -36
- package/dist/integrations/providers/llm.d.ts +0 -82
- package/dist/integrations/providers/mistral.d.ts +0 -7
- package/dist/integrations/providers/openbanking.d.ts +0 -128
- package/dist/integrations/providers/payments.d.ts +0 -109
- package/dist/integrations/providers/postmark.d.ts +0 -7
- package/dist/integrations/providers/powens.d.ts +0 -7
- package/dist/integrations/providers/qdrant.d.ts +0 -7
- package/dist/integrations/providers/sms.d.ts +0 -34
- package/dist/integrations/providers/storage.d.ts +0 -60
- package/dist/integrations/providers/stripe.d.ts +0 -7
- package/dist/integrations/providers/twilio-sms.d.ts +0 -7
- package/dist/integrations/providers/vector-store.d.ts +0 -43
- package/dist/integrations/providers/voice.d.ts +0 -34
- package/dist/integrations/runtime.d.ts +0 -99
- package/dist/integrations/secrets/env-secret-provider.d.ts +0 -31
- package/dist/integrations/secrets/gcp-secret-manager.d.ts +0 -32
- package/dist/integrations/secrets/index.d.ts +0 -5
- package/dist/integrations/secrets/manager.d.ts +0 -47
- package/dist/integrations/secrets/provider.d.ts +0 -52
- package/dist/integrations/spec.d.ts +0 -79
- package/dist/jobs/gcp-cloud-tasks.d.ts +0 -41
- package/dist/jobs/gcp-pubsub.d.ts +0 -25
- package/dist/jobs/handlers/gmail-sync-handler.d.ts +0 -9
- package/dist/jobs/handlers/index.d.ts +0 -3
- package/dist/jobs/handlers/storage-document-handler.d.ts +0 -12
- package/dist/jobs/index.d.ts +0 -7
- package/dist/jobs/memory-queue.d.ts +0 -18
- package/dist/jobs/queue.d.ts +0 -26
- package/dist/jsonschema.d.ts +0 -26
- package/dist/knowledge/binding.d.ts +0 -25
- package/dist/knowledge/contracts.d.ts +0 -316
- package/dist/knowledge/index.d.ts +0 -10
- package/dist/knowledge/ingestion/document-processor.d.ts +0 -24
- package/dist/knowledge/ingestion/embedding-service.d.ts +0 -12
- package/dist/knowledge/ingestion/gmail-adapter.d.ts +0 -18
- package/dist/knowledge/ingestion/index.d.ts +0 -6
- package/dist/knowledge/ingestion/storage-adapter.d.ts +0 -15
- package/dist/knowledge/ingestion/vector-indexer.d.ts +0 -18
- package/dist/knowledge/query/index.d.ts +0 -2
- package/dist/knowledge/query/service.d.ts +0 -29
- package/dist/knowledge/runtime.d.ts +0 -32
- package/dist/knowledge/source.d.ts +0 -32
- package/dist/knowledge/spaces/email-threads.d.ts +0 -7
- package/dist/knowledge/spaces/financial-docs.d.ts +0 -7
- package/dist/knowledge/spaces/financial-overview.d.ts +0 -7
- package/dist/knowledge/spaces/index.d.ts +0 -7
- package/dist/knowledge/spaces/product-canon.d.ts +0 -7
- package/dist/knowledge/spaces/support-faq.d.ts +0 -7
- package/dist/knowledge/spaces/uploaded-docs.d.ts +0 -7
- package/dist/knowledge/spec.d.ts +0 -52
- package/dist/markdown.d.ts +0 -21
- package/dist/migrations.d.ts +0 -52
- package/dist/onboarding-base.d.ts +0 -137
- package/dist/ownership.d.ts +0 -75
- package/dist/policy/engine.d.ts +0 -39
- package/dist/policy/opa-adapter.d.ts +0 -45
- package/dist/policy/spec.d.ts +0 -114
- package/dist/presentations.backcompat.d.ts +0 -7
- package/dist/presentations.d.ts +0 -96
- package/dist/presentations.v2.d.ts +0 -95
- package/dist/prompt.d.ts +0 -60
- package/dist/promptRegistry.d.ts +0 -15
- package/dist/regenerator/adapters.d.ts +0 -19
- package/dist/regenerator/executor.d.ts +0 -70
- package/dist/regenerator/index.d.ts +0 -7
- package/dist/regenerator/service.d.ts +0 -33
- package/dist/regenerator/sinks.d.ts +0 -26
- package/dist/regenerator/types.d.ts +0 -107
- package/dist/regenerator/utils.d.ts +0 -9
- package/dist/registry.d.ts +0 -72
- package/dist/resources.d.ts +0 -64
- package/dist/schema/dist/EnumType.js +0 -1
- package/dist/schema/dist/FieldType.js +0 -1
- package/dist/schema/dist/ScalarTypeEnum.js +0 -1
- package/dist/schema/dist/SchemaModel.js +0 -1
- package/dist/schema/dist/index.js +0 -1
- package/dist/server/graphql-pothos.d.ts +0 -31
- package/dist/server/graphql-schema-export.d.ts +0 -6
- package/dist/server/graphql-schema-export.js +0 -1
- package/dist/server/index.d.ts +0 -9
- package/dist/server/provider-mcp.d.ts +0 -51
- package/dist/server/rest-elysia.d.ts +0 -40
- package/dist/server/rest-express.d.ts +0 -16
- package/dist/server/rest-generic.d.ts +0 -32
- package/dist/server/rest-next-app.d.ts +0 -35
- package/dist/server/rest-next-mcp.d.ts +0 -11
- package/dist/server/rest-next-pages.d.ts +0 -9
- package/dist/spec.d.ts +0 -171
- package/dist/telemetry/anomaly.d.ts +0 -27
- package/dist/telemetry/index.d.ts +0 -4
- package/dist/telemetry/spec.d.ts +0 -98
- package/dist/telemetry/tracker.d.ts +0 -51
- package/dist/tests/index.d.ts +0 -3
- package/dist/tests/runner.d.ts +0 -43
- package/dist/tests/spec.d.ts +0 -89
- package/dist/themes.d.ts +0 -55
- package/dist/translations/catalog.d.ts +0 -28
- package/dist/translations/tenant.d.ts +0 -15
- package/dist/types/all.d.ts +0 -60
- package/dist/types.d.ts +0 -88
- package/dist/workflow/adapters/db-adapter.d.ts +0 -34
- package/dist/workflow/adapters/file-adapter.d.ts +0 -14
- package/dist/workflow/adapters/index.d.ts +0 -4
- package/dist/workflow/adapters/memory-store.d.ts +0 -18
- package/dist/workflow/expression.d.ts +0 -9
- package/dist/workflow/index.d.ts +0 -10
- package/dist/workflow/runner.d.ts +0 -74
- package/dist/workflow/sla-monitor.d.ts +0 -20
- package/dist/workflow/spec.d.ts +0 -99
- package/dist/workflow/state.d.ts +0 -35
- package/dist/workflow/validation.d.ts +0 -28
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import{specToAgentPrompt as e,specToFullMarkdown as t}from"./exporters.js";const n={"claude-code":`You are an expert TypeScript developer working with ContractSpec, a spec-first development framework.
|
|
2
|
+
|
|
3
|
+
Your code follows these principles:
|
|
4
|
+
- Type-safe with comprehensive TypeScript types (no \`any\`)
|
|
5
|
+
- Well-documented with JSDoc comments
|
|
6
|
+
- Production-ready with proper error handling
|
|
7
|
+
- Following SOLID principles and clean code practices
|
|
8
|
+
- Modular and testable
|
|
9
|
+
|
|
10
|
+
When implementing specs:
|
|
11
|
+
1. Validate input against the schema before processing
|
|
12
|
+
2. Handle all error cases defined in the spec
|
|
13
|
+
3. Emit events as specified in sideEffects
|
|
14
|
+
4. Respect policy constraints (auth, rate limits, PII handling)
|
|
15
|
+
5. Follow the acceptance scenarios as your implementation guide
|
|
16
|
+
|
|
17
|
+
Generate clean, idiomatic TypeScript that exactly matches the specification.`,"cursor-cli":`You are implementing features for a ContractSpec-driven codebase.
|
|
18
|
+
|
|
19
|
+
ContractSpec is a spec-first framework where specifications define:
|
|
20
|
+
- Operations (commands and queries) with typed I/O
|
|
21
|
+
- Events that operations emit
|
|
22
|
+
- Presentations for UI components
|
|
23
|
+
- Features that group related specs
|
|
24
|
+
|
|
25
|
+
When working with specs:
|
|
26
|
+
- Read the spec carefully before implementing
|
|
27
|
+
- Match the input/output types exactly
|
|
28
|
+
- Implement all error cases
|
|
29
|
+
- Follow the acceptance scenarios
|
|
30
|
+
- Respect policy constraints
|
|
31
|
+
|
|
32
|
+
Use the project's existing patterns and conventions.`,"generic-mcp":`You are a code generation assistant working with ContractSpec specifications.
|
|
33
|
+
|
|
34
|
+
ContractSpec specs define:
|
|
35
|
+
- meta: name, version, kind (command/query), description, goal, context
|
|
36
|
+
- io: input schema, output schema, error definitions
|
|
37
|
+
- policy: auth level, rate limits, feature flags, PII handling
|
|
38
|
+
- sideEffects: events to emit, analytics, audit
|
|
39
|
+
- acceptance: scenarios and examples
|
|
40
|
+
|
|
41
|
+
Your task is to generate or modify code that complies with the given specification.
|
|
42
|
+
Follow the spec exactly and handle all defined cases.`};function r(r,i,a){let o=n[i],s=t(r),c;return c=i===`claude-code`?`## Implementation Task
|
|
43
|
+
|
|
44
|
+
Implement the following ContractSpec operation:
|
|
45
|
+
|
|
46
|
+
${s}
|
|
47
|
+
|
|
48
|
+
${a?.targetPath?`**Target file:** \`${a.targetPath}\`\n`:``}
|
|
49
|
+
${a?.existingCode?`**Existing code to modify:**\n\`\`\`typescript\n${a.existingCode}\n\`\`\`\n`:``}
|
|
50
|
+
|
|
51
|
+
Generate a complete, production-ready TypeScript implementation that:
|
|
52
|
+
1. Exports a handler function matching the spec signature
|
|
53
|
+
2. Validates input using the schema
|
|
54
|
+
3. Handles all defined error cases
|
|
55
|
+
4. Emits events as specified
|
|
56
|
+
5. Includes JSDoc documentation
|
|
57
|
+
|
|
58
|
+
Provide ONLY the TypeScript code.`:i===`cursor-cli`?`Implement this ContractSpec operation.
|
|
59
|
+
|
|
60
|
+
${s}
|
|
61
|
+
|
|
62
|
+
${a?.targetPath?`Target: ${a.targetPath}\n`:``}
|
|
63
|
+
|
|
64
|
+
Requirements:
|
|
65
|
+
- TypeScript with strict types
|
|
66
|
+
- Handle all error cases
|
|
67
|
+
- Emit specified events
|
|
68
|
+
- Follow acceptance scenarios`:e(r,{taskType:`implement`,existingCode:a?.existingCode}),{agent:i,systemPrompt:o,taskPrompt:c}}function i(e,r,i){let a=i?.testFramework??`vitest`,o=`## Test Generation Task
|
|
69
|
+
|
|
70
|
+
Generate comprehensive tests for this specification:
|
|
71
|
+
|
|
72
|
+
${t(e)}
|
|
73
|
+
|
|
74
|
+
${i?.implementationCode?`**Implementation:**\n\`\`\`typescript\n${i.implementationCode}\n\`\`\`\n`:``}
|
|
75
|
+
|
|
76
|
+
**Test Framework:** ${a}
|
|
77
|
+
|
|
78
|
+
Generate tests that:
|
|
79
|
+
1. Cover all acceptance scenarios from the spec
|
|
80
|
+
2. Test all defined error cases
|
|
81
|
+
3. Verify input validation
|
|
82
|
+
4. Check event emissions
|
|
83
|
+
5. Test edge cases
|
|
84
|
+
|
|
85
|
+
Use descriptive test names: "should [behavior] when [condition]"
|
|
86
|
+
|
|
87
|
+
Provide a complete test file.`;return{agent:r,systemPrompt:n[r],taskPrompt:o}}function a(e,r,i){let a=`## Code Review Task
|
|
88
|
+
|
|
89
|
+
Review this implementation against its specification:
|
|
90
|
+
|
|
91
|
+
**Specification:**
|
|
92
|
+
${t(e)}
|
|
93
|
+
|
|
94
|
+
**Implementation:**
|
|
95
|
+
\`\`\`typescript
|
|
96
|
+
${i}
|
|
97
|
+
\`\`\`
|
|
98
|
+
|
|
99
|
+
Provide a structured review:
|
|
100
|
+
|
|
101
|
+
### Compliance Check
|
|
102
|
+
- [ ] Input types match spec
|
|
103
|
+
- [ ] Output types match spec
|
|
104
|
+
- [ ] All error cases handled
|
|
105
|
+
- [ ] Events emitted correctly
|
|
106
|
+
- [ ] Policy constraints respected
|
|
107
|
+
|
|
108
|
+
### Issues Found
|
|
109
|
+
List any issues with severity (error/warning/info)
|
|
110
|
+
|
|
111
|
+
### Suggestions
|
|
112
|
+
List improvements and recommendations
|
|
113
|
+
|
|
114
|
+
Be thorough and precise. Focus on spec compliance first, then code quality.`;return{agent:r,systemPrompt:n[r],taskPrompt:a}}function o(e,n){return{agent:`generic-mcp`,taskPrompt:`## Semantic Verification Task
|
|
115
|
+
|
|
116
|
+
Verify that this implementation fulfills the specification's intent.
|
|
117
|
+
|
|
118
|
+
**Specification:**
|
|
119
|
+
${t(e)}
|
|
120
|
+
|
|
121
|
+
**Implementation:**
|
|
122
|
+
\`\`\`typescript
|
|
123
|
+
${n}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
Analyze and respond with JSON:
|
|
127
|
+
|
|
128
|
+
\`\`\`json
|
|
129
|
+
{
|
|
130
|
+
"passed": true/false,
|
|
131
|
+
"score": 0-100,
|
|
132
|
+
"compliance": {
|
|
133
|
+
"inputTypes": { "match": true/false, "issues": [] },
|
|
134
|
+
"outputTypes": { "match": true/false, "issues": [] },
|
|
135
|
+
"errorHandling": { "coverage": "full/partial/none", "missing": [] },
|
|
136
|
+
"eventEmission": { "correct": true/false, "issues": [] },
|
|
137
|
+
"policyCompliance": { "auth": true/false, "rateLimit": true/false, "pii": true/false }
|
|
138
|
+
},
|
|
139
|
+
"scenarios": [
|
|
140
|
+
{ "name": "scenario name", "covered": true/false, "notes": "" }
|
|
141
|
+
],
|
|
142
|
+
"issues": [
|
|
143
|
+
{ "severity": "error/warning/info", "category": "type/export/import/scenario/error_handling/semantic", "message": "", "suggestion": "" }
|
|
144
|
+
],
|
|
145
|
+
"summary": "Brief summary of verification results"
|
|
146
|
+
}
|
|
147
|
+
\`\`\``}}function s(e,n){let r=e.meta,i=[],a=n?.projectRoot??`src`,o=r.name.replace(/\./g,`/`);(r.kind===`command`||r.kind===`query`)&&i.push({path:`${a}/${o}/handler.ts`,purpose:`Main handler implementation`,type:`create`},{path:`${a}/${o}/types.ts`,purpose:`Type definitions`,type:`create`},{path:`${a}/${o}/handler.test.ts`,purpose:`Handler tests`,type:`create`});let s=[],c=1;s.push({order:c++,title:`Define Types`,description:`Create TypeScript types for input, output, and internal data structures`,acceptanceCriteria:[`Input type matches spec schema exactly`,`Output type matches spec schema exactly`,`Error types defined for all error cases`]}),s.push({order:c++,title:`Implement Input Validation`,description:`Add validation logic for the input payload`,acceptanceCriteria:[`All required fields are validated`,`Type constraints are enforced`,`Validation errors return appropriate error codes`]}),s.push({order:c++,title:`Implement Core Logic`,description:`Implement the main business logic of the operation`,acceptanceCriteria:e.acceptance?.scenarios?.map(e=>e.name)??[`Operation completes successfully for valid input`]}),e.io.errors&&Object.keys(e.io.errors).length>0&&s.push({order:c++,title:`Implement Error Handling`,description:`Handle all defined error cases`,acceptanceCriteria:Object.entries(e.io.errors).map(([e,t])=>`Handle ${e}: ${t.when}`)}),e.sideEffects?.emits?.length&&s.push({order:c++,title:`Implement Event Emission`,description:`Emit events as specified`,acceptanceCriteria:e.sideEffects.emits.map(e=>`ref`in e?`Emit ${e.ref.name}.v${e.ref.version} when ${e.when}`:`Emit ${e.name}.v${e.version} when ${e.when}`)}),s.push({order:c++,title:`Write Tests`,description:`Create comprehensive test suite`,acceptanceCriteria:[`All acceptance scenarios covered`,`All error cases tested`,`Edge cases handled`,`Events verified`]});let l={policy:[],security:[],pii:[]};return l.policy.push(`Auth level: ${e.policy.auth}`),e.policy.idempotent!==void 0&&l.policy.push(`Idempotent: ${e.policy.idempotent}`),e.policy.rateLimit&&l.policy.push(`Rate limit: ${e.policy.rateLimit.rpm} rpm per ${e.policy.rateLimit.key}`),e.policy.flags?.length&&l.policy.push(`Feature flags required: ${e.policy.flags.join(`, `)}`),e.policy.escalate&&l.security.push(`Escalation required: ${e.policy.escalate}`),e.policy.pii?.length&&(l.pii=e.policy.pii),{target:{type:`spec`,name:r.name,version:r.version},context:{goal:r.goal,description:r.description,background:r.context},specMarkdown:t(e),fileStructure:i,steps:s,constraints:l,verificationChecklist:[`Input validation works for all cases`,`Output matches expected schema`,`All error cases return correct codes`,`Events are emitted with correct payloads`,`Auth requirements are enforced`,`Rate limiting is applied (if applicable)`,`PII fields are handled correctly`,`All acceptance scenarios pass`,`Tests provide adequate coverage`]}}function c(e,t){let r;return r=t===`claude-code`?`## Implementation Plan: ${e.target.name}.v${e.target.version}
|
|
148
|
+
|
|
149
|
+
### Context
|
|
150
|
+
**Goal:** ${e.context.goal}
|
|
151
|
+
|
|
152
|
+
**Background:** ${e.context.background}
|
|
153
|
+
|
|
154
|
+
### Specification
|
|
155
|
+
${e.specMarkdown}
|
|
156
|
+
|
|
157
|
+
### File Structure
|
|
158
|
+
${e.fileStructure.map(e=>`- \`${e.path}\` (${e.type}): ${e.purpose}`).join(`
|
|
159
|
+
`)}
|
|
160
|
+
|
|
161
|
+
### Implementation Steps
|
|
162
|
+
${e.steps.map(e=>`
|
|
163
|
+
#### Step ${e.order}: ${e.title}
|
|
164
|
+
${e.description}
|
|
165
|
+
|
|
166
|
+
**Acceptance Criteria:**
|
|
167
|
+
${e.acceptanceCriteria.map(e=>`- [ ] ${e}`).join(`
|
|
168
|
+
`)}
|
|
169
|
+
`).join(`
|
|
170
|
+
`)}
|
|
171
|
+
|
|
172
|
+
### Constraints
|
|
173
|
+
${e.constraints.policy.length?`**Policy:**\n${e.constraints.policy.map(e=>`- ${e}`).join(`
|
|
174
|
+
`)}\n`:``}
|
|
175
|
+
${e.constraints.security.length?`**Security:**\n${e.constraints.security.map(e=>`- ${e}`).join(`
|
|
176
|
+
`)}\n`:``}
|
|
177
|
+
${e.constraints.pii.length?`**PII Handling:**\n${e.constraints.pii.map(e=>`- ${e}`).join(`
|
|
178
|
+
`)}\n`:``}
|
|
179
|
+
|
|
180
|
+
### Verification Checklist
|
|
181
|
+
${e.verificationChecklist.map(e=>`- [ ] ${e}`).join(`
|
|
182
|
+
`)}
|
|
183
|
+
|
|
184
|
+
Implement this plan step by step.`:t===`cursor-cli`?`# ${e.target.name}.v${e.target.version}
|
|
185
|
+
|
|
186
|
+
${e.context.goal}
|
|
187
|
+
|
|
188
|
+
## Spec
|
|
189
|
+
${e.specMarkdown}
|
|
190
|
+
|
|
191
|
+
## Files to create
|
|
192
|
+
${e.fileStructure.map(e=>`${e.type}: ${e.path}`).join(`
|
|
193
|
+
`)}
|
|
194
|
+
|
|
195
|
+
## Steps
|
|
196
|
+
${e.steps.map(e=>`${e.order}. ${e.title}`).join(`
|
|
197
|
+
`)}`:`Implementation plan for ${e.target.name}.v${e.target.version}
|
|
198
|
+
|
|
199
|
+
${e.specMarkdown}
|
|
200
|
+
|
|
201
|
+
Steps:
|
|
202
|
+
${e.steps.map(e=>`${e.order}. ${e.title}: ${e.description}`).join(`
|
|
203
|
+
`)}`,{agent:t,systemPrompt:n[t],taskPrompt:r}}function l(e,n,r){return{agent:`generic-mcp`,taskPrompt:`## Fix Specification Violations
|
|
204
|
+
|
|
205
|
+
The following implementation has violations against its specification:
|
|
206
|
+
|
|
207
|
+
**Specification:**
|
|
208
|
+
${t(e)}
|
|
209
|
+
|
|
210
|
+
**Current Implementation:**
|
|
211
|
+
\`\`\`typescript
|
|
212
|
+
${n}
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
**Violations Found:**
|
|
216
|
+
${r.map((e,t)=>`${t+1}. ${e.message}${e.suggestion?`\n Suggestion: ${e.suggestion}`:``}`).join(`
|
|
217
|
+
`)}
|
|
218
|
+
|
|
219
|
+
Fix ALL violations while maintaining existing functionality.
|
|
220
|
+
Provide the corrected implementation.`}}export{n as AGENT_SYSTEM_PROMPTS,c as formatPlanForAgent,l as generateFixViolationsPrompt,s as generateImplementationPlan,r as generateImplementationPrompt,a as generateReviewPrompt,i as generateTestPrompt,o as generateVerificationPrompt};
|
|
File without changes
|
package/dist/onboarding-base.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{defineCommand as e,defineQuery as t}from"./spec.js";import{OwnersEnum as n,StabilityEnum as r}from"./ownership.js";import{ScalarTypeEnum as i,SchemaModel as a}from"@lssm/lib.schema";const o=new a({name:`SaveOnboardingDraftInput`,description:`Input for saving onboarding draft`,fields:{data:{type:i.JSON(),isOptional:!1}}}),s=new a({name:`SaveOnboardingDraftOutput`,description:`Output for saving onboarding draft`,fields:{id:{type:i.ID(),isOptional:!1},organizationId:{type:i.ID(),isOptional:!1}}}),c=e({meta:{name:`base.onboarding.saveDraft`,version:1,stability:r.Beta,owners:[n.PlatformSigil],tags:[`onboarding`,`draft`],description:`Save or update onboarding draft for active organization`,goal:`Persist onboarding progress incrementally for resumption and safety`,context:`Auto-saves every few seconds during onboarding; enables users to leave and resume`},io:{input:o,output:s},policy:{auth:`user`,escalate:null},transport:{gql:{field:`saveOnboardingDraft`},rest:{method:`POST`}}}),l=new a({name:`GetOnboardingDraftOutput`,description:`Onboarding draft payload`,fields:{id:{type:i.ID(),isOptional:!0},organizationId:{type:i.ID(),isOptional:!0},data:{type:i.JSON(),isOptional:!0},createdAt:{type:i.DateTime(),isOptional:!0},updatedAt:{type:i.DateTime(),isOptional:!0}}}),u=t({meta:{name:`base.onboarding.getDraft`,version:1,stability:r.Beta,owners:[n.PlatformSigil],tags:[`onboarding`,`draft`],description:`Get onboarding draft for active organization`,goal:`Retrieve saved onboarding progress`,context:`Called on mount to restore in-progress onboarding`},io:{input:null,output:l},policy:{auth:`user`,escalate:null},transport:{gql:{field:`getOnboardingDraft`},rest:{method:`GET`}}}),d=new a({name:`DeleteOnboardingDraftOutput`,description:`Result of delete operation`,fields:{ok:{type:i.Boolean(),isOptional:!1}}}),f=e({meta:{name:`base.onboarding.deleteDraft`,version:1,stability:r.Beta,owners:[n.PlatformSigil],tags:[`onboarding`,`draft`],description:`Delete onboarding draft for active organization`,goal:`Clear draft after completion or if user wants to restart`,context:`Called after successful onboarding or explicit user reset`},io:{input:null,output:d},policy:{auth:`user`,escalate:null},transport:{gql:{field:`deleteOnboardingDraft`},rest:{method:`POST`}}}),p=new a({name:`CompleteOnboardingBaseInput`,description:`Input for completing onboarding`,fields:{data:{type:i.JSON(),isOptional:!1}}}),m=new a({name:`CompleteOnboardingBaseOutput`,description:`Result of onboarding completion`,fields:{success:{type:i.Boolean(),isOptional:!1},userId:{type:i.ID(),isOptional:!0},organizationId:{type:i.ID(),isOptional:!0}}}),h=e({meta:{name:`base.onboarding.complete`,version:1,stability:r.Beta,owners:[n.PlatformSigil],tags:[`onboarding`],description:`Complete onboarding and finalize user/organization setup`,goal:`Transition from draft to active profile`,context:`Validates all required fields, creates/updates entities, marks onboarding complete`},io:{input:p,output:m},policy:{auth:`user`,escalate:null},transport:{gql:{field:`completeOnboarding`},rest:{method:`POST`}}});export{p as CompleteOnboardingBaseInput,m as CompleteOnboardingBaseOutput,h as CompleteOnboardingBaseSpec,f as DeleteOnboardingDraftBaseSpec,d as DeleteOnboardingDraftOutput,u as GetOnboardingDraftBaseSpec,l as GetOnboardingDraftOutput,c as SaveOnboardingDraftBaseSpec,o as SaveOnboardingDraftInput,s as SaveOnboardingDraftOutput};
|
package/dist/openapi.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defaultRestPath as e,jsonSchemaForSpec as t}from"./jsonschema.js";function n(e,t){return`${e.replace(/\./g,`_`)}_v${t}`}function r(e,t,r){return`${e}_${n(t,r)}`}function i(e,t){return(t??(e===`query`?`GET`:`POST`)).toLowerCase()}function a(t){let n=t.transport?.rest?.path??e(t.meta.name,t.meta.version);return n.startsWith(`/`)?n:`/${n}`}function o(e,o={}){let s=e.listSpecs().filter(e=>e.meta.kind===`command`||e.meta.kind===`query`).slice().sort((e,t)=>{let n=e.meta.name.localeCompare(t.meta.name);return n===0?e.meta.version-t.meta.version:n}),c={openapi:`3.1.0`,info:{title:o.title??`ContractSpec API`,version:o.version??`0.0.0`,...o.description?{description:o.description}:{}},...o.servers?{servers:o.servers}:{},paths:{},components:{schemas:{}}};for(let e of s){let o=t(e),s=i(e.meta.kind,e.transport?.rest?.method),l=a(e),u=n(e.meta.name,e.meta.version),d=c.paths[l]??={},f={operationId:u,summary:e.meta.description??e.meta.name,description:e.meta.description,tags:e.meta.tags??[],"x-contractspec":{name:e.meta.name,version:e.meta.version,kind:e.meta.kind},responses:{}};if(o.input){let t=r(`Input`,e.meta.name,e.meta.version);c.components.schemas[t]=o.input,f.requestBody={required:!0,content:{"application/json":{schema:{$ref:`#/components/schemas/${t}`}}}}}let p={};if(o.output){let t=r(`Output`,e.meta.name,e.meta.version);c.components.schemas[t]=o.output,p[200]={description:`OK`,content:{"application/json":{schema:{$ref:`#/components/schemas/${t}`}}}}}else p[200]={description:`OK`};f.responses=p,d[s]=f}return c}export{o as openApiForRegistry};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import{registerDocBlocks as e}from"../../docs/registry.js";import"../../registry.js";const t=[{id:`docs.tech.contracts.openbanking`,title:`Open Banking (Powens) Overview`,summary:`The Pocket Family Office vertical now supports read-only open banking capabilities powered by Powens. This doc summarises the contract surfaces, canonical data models, workflows, telemetry, and guardrails introduced to make Powens a first-class integration.`,kind:`reference`,visibility:`public`,route:`/docs/tech/contracts/openbanking`,tags:[`tech`,`contracts`,`openbanking`],body:`# Open Banking (Powens) Overview
|
|
2
|
+
|
|
3
|
+
The Pocket Family Office vertical now supports read-only open banking capabilities powered by Powens. This doc summarises the contract surfaces, canonical data models, workflows, telemetry, and guardrails introduced to make Powens a first-class integration.
|
|
4
|
+
|
|
5
|
+
## Integration Spec
|
|
6
|
+
|
|
7
|
+
Powens is registered under \`openbanking.powens\` with category \`open-banking\` and currently supports the BYOK ownership mode. The spec exposes three read-only capabilities:
|
|
8
|
+
|
|
9
|
+
- \`openbanking.accounts.read\`
|
|
10
|
+
- \`openbanking.transactions.read\`
|
|
11
|
+
- \`openbanking.balances.read\`
|
|
12
|
+
|
|
13
|
+
Configuration and secrets are separated:
|
|
14
|
+
|
|
15
|
+
| Config Field | Description |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| \`environment\` | Powens environment (\`sandbox\` \\| \`production\`) |
|
|
18
|
+
| \`baseUrl?\` | Optional API base URL override |
|
|
19
|
+
| \`region?\` | Optional Powens region identifier |
|
|
20
|
+
| \`pollingIntervalMs?\` | Optional custom sync cadence |
|
|
21
|
+
|
|
22
|
+
| Secret Field | Description |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| \`clientId\` | Powens OAuth client identifier |
|
|
25
|
+
| \`clientSecret\` | Powens OAuth client secret |
|
|
26
|
+
| \`apiKey?\` | Optional supplemental Powens API key |
|
|
27
|
+
| \`webhookSecret?\` | Optional webhook signing secret |
|
|
28
|
+
|
|
29
|
+
## Canonical Data Models
|
|
30
|
+
|
|
31
|
+
Canonical schemas live in \`@lssm/lib.contracts/integrations/openbanking/models\`:
|
|
32
|
+
|
|
33
|
+
- \`BankAccountRecord\` – account metadata (institution, IBAN/BIC, masked numbers, balances, sync timestamps)
|
|
34
|
+
- \`BankTransactionRecord\` – transaction ledger (amounts, categories, counterparty, status)
|
|
35
|
+
- \`AccountBalanceRecord\` – balance snapshots per account and balance type
|
|
36
|
+
|
|
37
|
+
These schemas power the vertical contracts and workflows, ensuring downstream features never use raw Powens payloads directly.
|
|
38
|
+
|
|
39
|
+
## Provider Implementation
|
|
40
|
+
|
|
41
|
+
\`PowensOpenBankingProvider\` wraps \`PowensClient\` which handles OAuth token management, request retries, and error mapping. The provider maps Powens payloads to the canonical interfaces exported from \`integrations/providers/openbanking\`.
|
|
42
|
+
|
|
43
|
+
Factory support lives in \`IntegrationProviderFactory.createOpenBankingProvider\`, which validates configuration, loads BYOK secrets, and instantiates the provider.
|
|
44
|
+
|
|
45
|
+
## Contracts
|
|
46
|
+
|
|
47
|
+
Command/query contracts exist under \`integrations/openbanking/contracts\`:
|
|
48
|
+
|
|
49
|
+
- \`openbanking.accounts.sync\` & \`openbanking.accounts.list\`
|
|
50
|
+
- \`openbanking.transactions.sync\` & \`openbanking.transactions.list\`
|
|
51
|
+
- \`openbanking.balances.refresh\` & \`openbanking.balances.get\`
|
|
52
|
+
|
|
53
|
+
The Pocket Family Office bundle also exposes \`pfo.openbanking.generate-overview\`, which aggregates balances and transactions into a derived knowledge document.
|
|
54
|
+
|
|
55
|
+
## Workflows
|
|
56
|
+
|
|
57
|
+
New workflow specs (all requiring the \`primaryOpenBanking\` slot) orchestrate the sync flows:
|
|
58
|
+
|
|
59
|
+
- \`pfo.workflow.sync-openbanking-accounts\`
|
|
60
|
+
- \`pfo.workflow.sync-openbanking-transactions\`
|
|
61
|
+
- \`pfo.workflow.refresh-openbanking-balances\`
|
|
62
|
+
- \`pfo.workflow.generate-openbanking-overview\`
|
|
63
|
+
|
|
64
|
+
Each workflow runs against the Powens provider, persists canonical records, and emits telemetry.
|
|
65
|
+
|
|
66
|
+
## Knowledge & LLM Exposure
|
|
67
|
+
|
|
68
|
+
Raw Powens payloads are never stored in knowledge spaces. Instead, \`knowledge.financial-overview\` captures derived summaries (cashflow, category breakdowns, balance trends) produced by \`pfo.openbanking.generate-overview\`. The space is \`operational\` category with 180-day retention and automation write access.
|
|
69
|
+
|
|
70
|
+
When exposing data to LLMs or analytics:
|
|
71
|
+
|
|
72
|
+
- Use derived summaries only.
|
|
73
|
+
- Redact PII fields using \`redactOpenBankingTelemetryPayload\`.
|
|
74
|
+
- Never emit IBANs, unmasked account numbers, or counterparty detail in telemetry/logs.
|
|
75
|
+
|
|
76
|
+
## Telemetry
|
|
77
|
+
|
|
78
|
+
Telemetry constants live in \`integrations/openbanking/telemetry\`. Key events:
|
|
79
|
+
|
|
80
|
+
- \`openbanking.accounts.synced\`
|
|
81
|
+
- \`openbanking.transactions.synced\`
|
|
82
|
+
- \`openbanking.balances.refreshed\`
|
|
83
|
+
- \`openbanking.overview.generated\`
|
|
84
|
+
|
|
85
|
+
All events require tenant/app/blueprint/config metadata, and sensitive properties are flagged to avoid accidental leakage.
|
|
86
|
+
|
|
87
|
+
## Guardrails
|
|
88
|
+
|
|
89
|
+
\`ensurePrimaryOpenBankingIntegration\` verifies \`primaryOpenBanking\` is bound and healthy before workflows proceed. Runtime pre-flight checks already block workflows when the connection is disconnected or in error status.
|
|
90
|
+
|
|
91
|
+
## Blueprint & Tenant Defaults
|
|
92
|
+
|
|
93
|
+
\`pocketFamilyOfficeBlueprint\` now includes:
|
|
94
|
+
|
|
95
|
+
- \`primaryOpenBanking\` slot (required, BYOK)
|
|
96
|
+
- \`openbanking.*.read\` capabilities enabled by default
|
|
97
|
+
- Workflow bindings for the new sync flows
|
|
98
|
+
|
|
99
|
+
Sample tenant bindings (\`tenant.sample.ts\`) reference \`conn-powens-primary\` and bind the new knowledge space.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
Follow this doc when extending open banking support (e.g., adding payment initiation, additional providers, or expanded analytics) to keep the integration consistent and audited.
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
`}];e(t);export{t as tech_contracts_openbanking_DocBlocks};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{registerDocBlocks as e}from"../../docs/registry.js";import"../../registry.js";const t=[{id:`docs.tech.contracts.policy`,title:`PolicySpec & PolicyEngine`,summary:"`PolicySpec` gives a declarative, typed home for access-control logic covering:",kind:`reference`,visibility:`public`,route:`/docs/tech/contracts/policy`,tags:[`tech`,`contracts`,`policy`],body:"# PolicySpec & PolicyEngine\n\n## Purpose\n\n`PolicySpec` gives a declarative, typed home for access-control logic covering:\n- **Who** can perform an action (ABAC/ReBAC style rules)\n- **What** they can access (resources + optional field-level overrides)\n- **When** special conditions apply (contextual expressions)\n- **How** PII should be handled (consent/retention hints)\n\n`PolicyEngine` evaluates one or more policies and returns an `allow`/`deny` decision, field-level outcomes, and PII metadata suitable for downstream enforcement (`SpecRegistry` → `ctx.decide`).\n\n## Location\n\n- Types & registry: `packages/libs/contracts/src/policy/spec.ts`\n- Runtime evaluation: `packages/libs/contracts/src/policy/engine.ts`\n- Tests: `packages/.../policy/engine.test.ts`\n\n## `PolicySpec`\n\n```ts\nexport interface PolicySpec {\n meta: PolicyMeta; // ownership metadata + { name, version, scope? }\n rules: PolicyRule[]; // allow/deny rules for actions\n fieldPolicies?: FieldPolicyRule[];\n pii?: { fields: string[]; consentRequired?: boolean; retentionDays?: number };\n relationships?: RelationshipDefinition[];\n consents?: ConsentDefinition[];\n rateLimits?: RateLimitDefinition[];\n opa?: { package: string; decision?: string };\n}\n```\n\n- `PolicyRule`\n - `effect`: `'allow' | 'deny'`\n - `actions`: e.g., `['read', 'write', 'delete']` (string namespace is flexible)\n - `subject`: `{ roles?: string[]; attributes?: { attr: matcher } }`\n - `resource`: `{ type: string; fields?: string[]; attributes?: {...} }`\n - `relationships`: `{ relation, objectId?, objectType? }[]` → ReBAC checks (use `objectId: '$resource'` to target the current resource)\n - `requiresConsent`: `['consent_id']` → references spec-level consent definitions\n - `flags`: feature flags that must be enabled (`DecisionContext.flags`)\n - `rateLimit`: string reference to `rateLimits` entry or inline object `{ rpm, key?, windowSeconds?, burst? }`\n - `escalate`: `'human_review' | null` to indicate manual approval\n - `conditions`: optional expression snippets evaluated against `{ subject, resource, context }`\n- `FieldPolicyRule`\n - `field`: dot-path string (e.g., `contact.email`)\n - `actions`: subset of `['read', 'write']`\n - Same `subject` / `resource` / `conditions` shape\n - Useful for redacting specific fields, even when the global action is allowed\n- `RelationshipDefinition`\n - Canonical tuples for relationship graph (`subjectType`, `relation`, `objectType`, `transitive?`)\n- `ConsentDefinition`\n - `{ id, scope, purpose, lawfulBasis?, expiresInDays?, required? }`\n- `RateLimitDefinition`\n - `{ id, rpm, key?, windowSeconds?, burst? }`\n- `PolicyRef`\n - `{ name: string; version: number }` → attach to contract specs / workflows\n\n## Registry\n\n```ts\nconst registry = new PolicyRegistry();\nregistry.register(CorePolicySpec);\nconst spec = registry.get('core.default', 1);\n```\n\nGuarantees uniqueness per `(name, version)` and exposes helpers to resolve highest versions.\n\n## Engine\n\n```ts\nconst engine = new PolicyEngine(policyRegistry);\n\nconst decision = engine.decide({\n action: 'read',\n subject: { roles: ['admin'] },\n resource: { type: 'resident', fields: ['contact.email'] },\n policies: [{ name: 'core.default', version: 1 }],\n});\n/*\n{\n effect: 'allow',\n reason: 'core.default',\n fieldDecisions: [{ field: 'contact.email', effect: 'allow' }],\n pii: { fields: ['contact.email'], consentRequired: true }\n}\n*/\n```\n\n- First matching **deny** wins; otherwise the first **allow** is returned.\n- Field policies are aggregated across referenced policies:\n - Later denies override earlier allows for a given field.\n - Returned as `fieldDecisions` to simplify downstream masking.\n- PII metadata is surfaced when defined to help adapt logging/telemetry.\n\n### Expression Support\n\nConditions accept small JS snippets (e.g., `subject.attributes.orgId === context.orgId`). The engine runs them in a constrained scope (`subject`, `resource`, `context`) without access to global state.\n\n### ReBAC & Relationships\n\n- Provide relationship tuples via `PolicySpec.relationships` for documentation/validation.\n- Reference them inside rules with `relationships: [{ relation: 'manager_of', objectType: 'resident', objectId: '$resource' }]`.\n- The execution context must populate `subject.relationships` (`[{ relation, object, objectType }]`) for the engine to evaluate ReBAC guards.\n\n### Consent & Rate Limits\n\n- Declare reusable consent definitions under `consents`. Rules list the IDs they require; if a user session lacks the consent (`DecisionContext.consents`), the engine returns `effect: 'deny'` with `reason: 'consent_required'` and enumerates missing consents.\n- Attach rate limits either inline or via `rateLimits` references. When a rule matches, the engine surfaces `{ rpm, key, windowSeconds?, burst? }` so callers can feed it to shared limiters.\n\n### OPA Adapter\n\n- `OPAPolicyAdapter` bridges engine decisions to Open Policy Agent (OPA). It forwards the evaluation context + policies to OPA and merges any override result (`effect`, `reason`, `fieldDecisions`, `requiredConsents`).\n- Use when migrating to OPA policies or running defense-in-depth: call `engine.decide()`, then pass the preliminary decision to `adapter.evaluate(...)`. The adapter marks merged decisions with `evaluatedBy: 'opa'`.\n- OPA inputs include meta, rules, relationships, rate limits, and consent catalogs to simplify policy authoring on the OPA side.\n\n## Contract Integration\n\n`ContractSpec.policy` now supports:\n\n```ts\npolicy: {\n auth: 'anonymous' | 'user' | 'admin';\n ...\n policies?: PolicyRef[]; // policies evaluated before execution\n fieldPolicies?: { // field hints (read/write) per policy\n field: string;\n actions: ('read' | 'write')[];\n policy?: PolicyRef;\n }[];\n}\n```\n\nAdapters can resolve refs through a shared `PolicyEngine` and populate `ctx.decide` so `SpecRegistry.execute` benefits from centralized enforcement.\n\n## Authoring Guidelines\n\n1. Prefer **allow-by-default** policies but explicitly deny sensitive flows (defense-in-depth).\n2. Keep rule scopes narrow (per feature/operation) and compose multiple `PolicyRef`s when necessary.\n3. Store PII field lists here to avoid duplication across logs/telemetry.\n4. Use explicit rule reasons for auditability and better developer feedback.\n5. Treat versioning seriously; bump `meta.version` whenever behavior changes.\n\n## Future Enhancements\n\n- Richer expression language (composable predicates, time-based conditions).\n- Multi-tenant relationship graph services (store/resolve relationships at scale).\n- Tooling that auto-generates docs/tests for policies referenced in specs.\n\n"}];e(t);export{t as tech_contracts_policy_DocBlocks};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{registerDocBlocks as e}from"../../docs/registry.js";import"../../registry.js";const t=[{id:`docs.tech.contracts.presentations-conventions`,title:`Presentations Conventions (A11y & i18n)`,summary:"- Always provide `meta.description` (≥ 3 chars) — used by a11y/docs/agents.",kind:`reference`,visibility:`public`,route:`/docs/tech/contracts/presentations-conventions`,tags:[`tech`,`contracts`,`presentations-conventions`],body:`## Presentations Conventions (A11y & i18n)
|
|
2
|
+
|
|
3
|
+
- Always provide \`meta.description\` (≥ 3 chars) — used by a11y/docs/agents.
|
|
4
|
+
- Prefer source = BlockNote for rich guides; use component key for interactive flows.
|
|
5
|
+
- i18n strings belong in host apps; descriptors carry keys/defaults only.
|
|
6
|
+
- Target selection: include only what you intend to support to avoid drift.
|
|
7
|
+
- PII: declare JSON-like paths under \`policy.pii\`; engine redacts in outputs.
|
|
8
|
+
`}];e(t);export{t as tech_contracts_presentations_conventions_DocBlocks};
|
package/dist/presentations.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"zod";function t(e){return`${e.meta.name}.v${e.meta.version}`}var n=class{items=new Map;register(e){let n=t(e);if(this.items.has(n))throw Error(`Duplicate presentation ${n}`);return this.items.set(n,e),this}list(){return[...this.items.values()]}get(e,t){if(t!=null)return this.items.get(`${e}.v${t}`);let n,r=-1/0;for(let[t,i]of this.items.entries())t.startsWith(`${e}.v`)&&i.meta.version>r&&(r=i.meta.version,n=i);return n}};function r(t){let n={meta:{name:t.meta.name,version:t.meta.version,stability:t.meta.stability??`stable`,tags:t.meta.tags??[],description:t.meta.description??``},kind:t.content.kind};return t.content.kind===`web_component`?{...n,framework:t.content.framework,componentKey:t.content.componentKey,props:e.toJSONSchema(t.content.props.getZod())}:t.content.kind===`markdown`?{...n,content:t.content.content,resourceUri:t.content.resourceUri}:{...n,mimeType:t.content.mimeType,model:e.toJSONSchema(t.content.model.getZod())}}export{n as PresentationRegistry,r as jsonSchemaForPresentation};
|
|
1
|
+
import e from"zod";function t(e){return`${e.meta.name}.v${e.meta.version}`}var n=class{items=new Map;constructor(e){e&&e.forEach(e=>this.register(e))}register(e){let n=t(e);if(this.items.has(n))throw Error(`Duplicate presentation ${n}`);return this.items.set(n,e),this}list(){return[...this.items.values()]}get(e,t){if(t!=null)return this.items.get(`${e}.v${t}`);let n,r=-1/0;for(let[t,i]of this.items.entries())t.startsWith(`${e}.v`)&&i.meta.version>r&&(r=i.meta.version,n=i);return n}};function r(t){let n={meta:{name:t.meta.name,version:t.meta.version,stability:t.meta.stability??`stable`,tags:t.meta.tags??[],description:t.meta.description??``},kind:t.content.kind};return t.content.kind===`web_component`?{...n,framework:t.content.framework,componentKey:t.content.componentKey,props:e.toJSONSchema(t.content.props.getZod())}:t.content.kind===`markdown`?{...n,content:t.content.content,resourceUri:t.content.resourceUri}:{...n,mimeType:t.content.mimeType,model:e.toJSONSchema(t.content.model.getZod())}}export{n as PresentationRegistry,r as jsonSchemaForPresentation};
|
package/dist/presentations.v2.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import{schemaToMarkdown as e}from"./schema-to-markdown.js";import t from"react";import n from"turndown";const r=new n;function i(e){let t=e.text??``;return!e.marks||e.marks.length===0?t:e.marks.reduce((e,t)=>{switch(t.type){case`bold`:return`**${e}**`;case`italic`:return`*${e}*`;case`underline`:return`__${e}__`;case`strike`:return`~~${e}~~`;case`code`:return`\`${e}\``;case`link`:{let n=t.attrs?.href??``;return n?`[${e}](${n})`:e}default:return e}},t)}function a(e){return e?.length?e.map(e=>s(e)).join(``):``}function o(e,t=!1){if(!e?.length)return``;let n=1;return e.map(e=>{let r=a(e.content??[]);return r?`${t?`${n++}. `:`- `}${r}`:``}).filter(Boolean).join(`
|
|
2
|
+
`)}function s(e){switch(e.type){case`doc`:return a(e.content);case`paragraph`:{let t=a(e.content);return t.trim().length?t:``}case`heading`:{let t=Math.min(Math.max(e.attrs?.level??1,1),6);return`${`#`.repeat(t)} ${a(e.content)}`.trim()}case`bullet_list`:return o(e.content,!1);case`ordered_list`:return o(e.content,!0);case`list_item`:return a(e.content);case`blockquote`:return a(e.content).split(`
|
|
3
|
+
`).map(e=>`> ${e}`).join(`
|
|
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(`
|
|
6
|
+
|
|
7
|
+
`).trim();try{return JSON.stringify(e,null,2)}catch{return String(e)}}var l=class{renderers=new Map;validators=[];register(e){let t=this.renderers.get(e.target)??[];return t.push(e),this.renderers.set(e.target,t),this}prependRegister(e){let t=this.renderers.get(e.target)??[];return t.unshift(e),this.renderers.set(e.target,t),this}addValidator(e){return this.validators.push(e),this}async render(e,t,n){if(!t.targets.includes(e))throw Error(`Target ${e} not declared for ${t.meta.name}.v${t.meta.version}`);for(let r of this.validators)await r.validate(t,e,n);let r=this.renderers.get(e)??[];for(let e of r)try{return await e.render(t,n)}catch{}throw Error(`No renderer available for ${e}`)}};function u(){let t=new l,n=(e,t)=>{let n=JSON.parse(JSON.stringify(t)),r=e.policy?.pii??[],i=(e,t)=>{let n=t.replace(/^\//,``).replace(/\[(\d+)\]/g,`.$1`).split(`.`).filter(Boolean),r=e;for(let e=0;e<n.length-1;e++){let t=n[e];if(r&&typeof r==`object`&&t in r)r=r[t];else return}let i=n[n.length-1];r&&typeof r==`object`&&i&&i in r&&(r[i]=`[REDACTED]`)};for(let e of r)i(n,e);return n};return t.register({target:`markdown`,async render(t,r){let i=r?.data;if(!i&&r?.fetchData&&(i=await r.fetchData()),t.source.type===`component`&&t.source.props&&i!==void 0){let n=Array.isArray(i),r=!n&&typeof i==`object`&&!!i&&!Object.values(i).some(e=>Array.isArray(e)||typeof e==`object`&&!!e);if(n||r)return{mimeType:`text/markdown`,body:e(t.source.props,i,{title:t.meta.description??t.meta.name,description:`${t.meta.name} v${t.meta.version}`})};throw Error(`Complex data structure for ${t.meta.name} - expecting custom renderer`)}if(t.source.type===`blocknotejs`){let e=n(t,{text:c(t.source.docJson)});return{mimeType:`text/markdown`,body:String(e.text)}}if(t.source.type===`component`&&i!==void 0)throw Error(`No schema (source.props) available for ${t.meta.name} - expecting custom renderer`);if(t.source.type===`component`)return{mimeType:`text/markdown`,body:`${`# ${t.meta.name} v${t.meta.version}`}${t.meta.description?`\n\n${t.meta.description}`:``}${t.meta.tags&&t.meta.tags.length?`\n\nTags: ${t.meta.tags.join(`, `)}`:``}${t.meta.owners&&t.meta.owners.length?`\n\nOwners: ${t.meta.owners.join(`, `)}`:``}${`\n\nComponent: \`${t.source.componentKey}\``}${t.policy?.pii?.length?`\n\nRedacted paths: ${t.policy.pii.map(e=>`\`${e}\``).join(`, `)}`:``}`};throw Error(`unsupported`)}}),t.register({target:`application/json`,async render(e){let t=n(e,{meta:e.meta,source:e.source});return{mimeType:`application/json`,body:JSON.stringify(t,null,2)}}}),t.register({target:`application/xml`,async render(e){let t=n(e,{meta:e.meta,source:e.source});return{mimeType:`application/xml`,body:`<presentation name="${e.meta.name}" version="${e.meta.version}"><json>${encodeURIComponent(JSON.stringify(t))}</json></presentation>`}}}),t}function d(e){return e.register({target:`react`,async render(e){if(e.source.type===`component`){let t=e.source.props&&e.source.props.getZod().safeParse({}).success?{}:void 0;return{kind:`react_component`,componentKey:e.source.componentKey,props:t}}return{kind:`blocknotejs`,docJson:e.source.docJson,blockConfig:e.source.blockConfig}}}),e}function f(e){return e.addValidator({validate(e){if(!e.meta.description||e.meta.description.length<3)throw Error(`Presentation ${e.meta.name}.v${e.meta.version} missing meta.description`)}}),e}function p(e,r){let i=new n({headingStyle:`atx`,codeBlockStyle:`fenced`,bulletListMarker:`-`});return i.addRule(`link`,{filter:`a`,replacement:(e,t)=>{let n=t.href;return n&&e?`[${e}](${n})`:e||``}}),e.prependRegister({target:`markdown`,async render(e,n){if(e.source.type!==`component`)throw Error(`React-to-markdown renderer only handles component presentations`);let{renderToStaticMarkup:a}=await import(`react-dom/server`),o=r[e.source.componentKey];if(!o)throw Error(`Component ${e.source.componentKey} not found in componentMap`);let s;try{s=a(t.createElement(o,e.source.props?{}:void 0))}catch(t){throw Error(`Failed to render component ${e.source.componentKey}: ${t instanceof Error?t.message:`Unknown error`}`)}let c;try{c=i.turndown(s)}catch(e){throw Error(`Failed to convert HTML to markdown: ${e instanceof Error?e.message:`Unknown error`}`)}return e.policy?.pii&&e.policy.pii.length>0?{mimeType:`text/markdown`,body:c.replace(/\[REDACTED\]/g,`[REDACTED]`)}:{mimeType:`text/markdown`,body:c}}}),e}export{l as TransformEngine,u as createDefaultTransformEngine,f as registerBasicValidation,d as registerDefaultReactRenderer,p as registerReactToMarkdownRenderer};
|
package/dist/prompt.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import"zod";function e(e){return e}export{e as definePrompt};
|
package/dist/promptRegistry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import"zod";var e=class{prompts=new Map;register(e){let t=`${e.meta.name}.v${e.meta.version}`;if(this.prompts.has(t))throw Error(`Duplicate prompt ${t}`);return this.prompts.set(t,e),this}list(){return[...this.prompts.values()]}get(e,t){if(t!=null)return this.prompts.get(`${e}.v${t}`);let n,r=-1/0;for(let[t,i]of this.prompts.entries())t.startsWith(`${e}.v`)&&i.meta.version>r&&(r=i.meta.version,n=i);return n}};export{e as PromptRegistry};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import{registerDocBlocks as e}from"../../docs/registry.js";import"../../registry.js";const t=[{id:`docs.tech.contracts.regenerator`,title:`Regenerator Service`,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.`,kind:`reference`,visibility:`public`,route:`/docs/tech/contracts/regenerator`,tags:[`tech`,`contracts`,`regenerator`],body:`## Regenerator Service
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
- Runtime entrypoint: \`packages/libs/contracts/src/regenerator/service.ts\`
|
|
6
|
+
- Types/interfaces: \`packages/libs/contracts/src/regenerator/types.ts\`
|
|
7
|
+
- Signal adapters: \`packages/libs/contracts/src/regenerator/adapters.ts\`
|
|
8
|
+
|
|
9
|
+
### Architecture
|
|
10
|
+
|
|
11
|
+
\`\`\`text
|
|
12
|
+
Signal Adapters ──► RegeneratorService ──► Rules ──► ProposalSink
|
|
13
|
+
▲ │
|
|
14
|
+
│ ▼
|
|
15
|
+
Telemetry / Errors / Behavior Spec change proposals
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
1. **Signal adapters** pull batches of telemetry, error logs, or behavior metrics for each \`RegenerationContext\`.
|
|
19
|
+
2. \`RegeneratorService\` schedules polling (\`resolveAppConfig\` + \`composeAppConfig\` provide context).
|
|
20
|
+
3. **Rules** implement domain heuristics and emit \`SpecChangeProposal\` objects.
|
|
21
|
+
4. **Proposal sinks** persist or forward proposals for human review.
|
|
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};
|
package/dist/registry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{eventKey as e}from"./events.js";import{isEmitDeclRef as t}from"./spec.js";function
|
|
1
|
+
import{eventKey as e}from"./events.js";import{isEmitDeclRef as t}from"./spec.js";import{defaultDocRegistry as n,docId as r,registerDocBlocks as i}from"./docs/registry.js";function a(e,t){return`${e}.v${t}`}var o=class{specs=new Map;handlers=new Map;register(e){let t=a(e.meta.name,e.meta.version);if(this.specs.has(t))throw Error(`Duplicate spec ${t}`);return this.specs.set(t,e),this}bind(e,t){let n=a(e.meta.name,e.meta.version);if(!this.specs.has(n))throw Error(`Cannot bind; spec not found: ${n}`);if(this.handlers.has(n))throw Error(`Handler already bound for ${n}`);return this.handlers.set(n,t),this}getSpec(e,t){if(t!=null)return this.specs.get(a(e,t));let n,r=-1/0;for(let[t,i]of this.specs.entries())t.startsWith(`${e}.v`)&&i.meta.version>r&&(r=i.meta.version,n=i);return n}getHandler(e,t){let n=this.getSpec(e,t);if(n)return this.handlers.get(a(n.meta.name,n.meta.version))}listSpecs(){return[...this.specs.values()]}listBound(){let e=[];for(let[t,n]of this.specs.entries()){let r=this.handlers.get(t);r&&e.push({spec:n,handler:r})}return e}async execute(n,r,i,o){let s=this.getSpec(n,r);if(!s)throw Error(`Spec not found for ${n}${r?`.v${r}`:``}`);let c=await o.specVariantResolver?.resolve({name:s.meta.name,version:s.meta.version,kind:s.meta.kind},o)??s,l=a(c.meta.name,c.meta.version),u=this.handlers.get(l);if(!u){let e=a(s.meta.name,s.meta.version);u=this.handlers.get(e),l=e}if(!u)throw Error(`No handler bound for ${l}`);let d=c.io.input?.getZod().parse(i);if(o.decide){let[e,t]=c.meta.name.split(`.`),n=await o.decide({service:e,command:t,version:c.meta.version,actor:o.actor??`anonymous`,channel:o.channel,roles:o.roles,organizationId:o.organizationId,userId:o.userId,flags:[]});if(n.effect===`deny`)throw Error(`PolicyDenied: ${c.meta.name}.v${c.meta.version}`);if(n.rateLimit&&o.rateLimit){let e=n.rateLimit.key??`default`,t=n.rateLimit.rpm??60;await o.rateLimit(e,1,t)}}let f=new Map;if(c.sideEffects?.emits)for(let e of c.sideEffects.emits)t(e)?f.set(`${e.ref.name}.v${e.ref.version}`,e.ref.payload):f.set(`${e.name}.v${e.version}`,e.payload);let p=async(t,n,r)=>{let i=e(t,n),s=f.get(i);if(!s)throw Error(`UndeclaredEvent: ${i} not allowed by ${a(c.meta.name,c.meta.version)}`);let l=s.getZod().parse(r);await o.eventPublisher?.({name:t,version:n,payload:l,traceId:o.traceId})};o.appConfig&&(o.branding||=o.appConfig.branding,o.translation?o.translation.config||(o.translation={...o.translation,config:o.appConfig.translation}):o.translation={config:o.appConfig.translation});let m=o.telemetry,h=async(e,t)=>{if(!(!m||!e?.event))try{let n=e.properties?.(t)??{};await m.track(e.event.name,e.event.version??1,n,{tenantId:o.organizationId??void 0,organizationId:o.organizationId,userId:o.userId,actor:o.actor,channel:o.channel,metadata:o.traceId?{traceId:o.traceId}:void 0})}catch{}},g;try{g=await u(d,{...o,__emitGuard__:p})}catch(e){throw c.telemetry?.failure&&await h(c.telemetry.failure,{input:d??i,error:e}),e}c.telemetry?.success&&await h(c.telemetry.success,{input:d??i,output:g});let _=c.io.output;return _?.getZod?_.getZod().parse(g):g}};export{o as SpecRegistry,n as defaultDocRegistry,r as docId,a as opKey,i as registerDocBlocks};
|
package/dist/resources.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import"zod";function e(e){return e}var t=class{templates=[];register(e){return this.templates.push(e),this}listTemplates(){return[...this.templates]}match(e){for(let t of this.templates){let n=RegExp(`^`+t.meta.uriTemplate.replace(/\{[^}]+\}/g,`([^/]+)`)+`$`),r=e.match(n);if(!r)continue;let i=[...t.meta.uriTemplate.matchAll(/\{([^}]+)\}/g)].map(e=>e[1]),a={};return i.forEach((e,t)=>a[e]=decodeURIComponent(r[t+1])),{tmpl:t,params:a}}}};function n(e,t){return{kind:`resource_ref`,uriTemplate:e,varName:t.varName??`id`,graphQLType:t.graphQLType,many:t.many}}function r(e){let t=e;return!!t&&t.kind===`resource_ref`&&typeof t.uriTemplate==`string`}export{t as ResourceRegistry,e as defineResourceTemplate,r as isResourceRef,n as resourceRef};
|