@happyvertical/smrt-planner 0.0.1 → 0.0.2
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/app/404.html +12 -12
- package/app/_app/immutable/chunks/2jFBkS1C.js +1 -0
- package/app/_app/immutable/chunks/6P9zxrzU.js +1 -0
- package/app/_app/immutable/chunks/{DyGfbRG-.js → BnRri03M.js} +1 -1
- package/app/_app/immutable/chunks/Ci0DUht6.js +34 -0
- package/app/_app/immutable/chunks/{CV-2zt0K.js → CsprTb3f.js} +2 -2
- package/app/_app/immutable/chunks/{D333l2GL.js → DkR8_Ws6.js} +1 -1
- package/app/_app/immutable/chunks/{DJtH-lRi.js → Xp1g1t4n.js} +1 -1
- package/app/_app/immutable/entry/{app.D5JJain6.js → app.IZIJXhgq.js} +2 -2
- package/app/_app/immutable/entry/start.BuaYHD1N.js +1 -0
- package/app/_app/immutable/nodes/{0.CL1MxOva.js → 0.m_U8WC7E.js} +3 -3
- package/app/_app/immutable/nodes/{1.BO731RRg.js → 1.Crw8ULhB.js} +1 -1
- package/app/_app/immutable/nodes/{12.BmZyLHbM.js → 12.BIocA1aI.js} +1 -1
- package/app/_app/immutable/nodes/{2.BEw046av.js → 2.CR5BwGnt.js} +2 -2
- package/app/_app/immutable/nodes/{3.DvwpTAQA.js → 3.1B56hgAG.js} +1 -1
- package/app/_app/immutable/nodes/{4.qrT4bnmS.js → 4.SSIC7sUh.js} +1 -1
- package/app/_app/immutable/nodes/{5.DDLa2uhV.js → 5.DgdwleDQ.js} +1 -1
- package/app/_app/immutable/nodes/{6.DN0QTY6z.js → 6.DmD9rqLU.js} +1 -1
- package/app/_app/immutable/nodes/{7.C_8N82Wq.js → 7.DdngsBmo.js} +1 -1
- package/app/_app/version.json +1 -1
- package/app/ai/index.html +14 -14
- package/app/blueprint/index.html +13 -13
- package/app/cookbook/index.html +13 -13
- package/app/index.html +13 -13
- package/app/m/ads/AdDeliveryTier/index.html +14 -14
- package/app/m/ads/AdEvent/index.html +14 -14
- package/app/m/ads/AdFormat/index.html +14 -14
- package/app/m/ads/AdGroup/index.html +14 -14
- package/app/m/ads/AdVariation/index.html +14 -14
- package/app/m/analytics/AnalyticsDataStream/index.html +14 -14
- package/app/m/analytics/AnalyticsEvent/index.html +14 -14
- package/app/m/analytics/AnalyticsProperty/index.html +14 -14
- package/app/m/analytics/AnalyticsReport/index.html +14 -14
- package/app/m/approvals/ApprovalEvent/index.html +14 -14
- package/app/m/approvals/ApprovalPolicy/index.html +14 -14
- package/app/m/approvals/ApprovalRequest/index.html +14 -14
- package/app/m/assets/Asset/index.html +14 -14
- package/app/m/assets/AssetAssociation/index.html +14 -14
- package/app/m/assets/AssetMetafield/index.html +14 -14
- package/app/m/assets/AssetStatus/index.html +14 -14
- package/app/m/assets/AssetType/index.html +14 -14
- package/app/m/assets/Folder/index.html +14 -14
- package/app/m/chat/AgentSession/index.html +14 -14
- package/app/m/chat/ChatMessage/index.html +14 -14
- package/app/m/chat/ChatParticipant/index.html +14 -14
- package/app/m/chat/ChatReaction/index.html +14 -14
- package/app/m/chat/ChatRoom/index.html +14 -14
- package/app/m/chat/ChatThread/index.html +14 -14
- package/app/m/chat/VoiceGatewayTurn/index.html +14 -14
- package/app/m/chat/VoiceSession/index.html +14 -14
- package/app/m/commerce/Agreement/index.html +14 -14
- package/app/m/commerce/Cart/index.html +14 -14
- package/app/m/commerce/Contract/index.html +14 -14
- package/app/m/commerce/ContractLineItem/index.html +14 -14
- package/app/m/commerce/Customer/index.html +14 -14
- package/app/m/commerce/Estimate/index.html +14 -14
- package/app/m/commerce/Fulfillment/index.html +14 -14
- package/app/m/commerce/FulfillmentLineItem/index.html +14 -14
- package/app/m/commerce/Invoice/index.html +14 -14
- package/app/m/commerce/InvoiceLineItem/index.html +14 -14
- package/app/m/commerce/Lease/index.html +14 -14
- package/app/m/commerce/LicenseSale/index.html +14 -14
- package/app/m/commerce/Order/index.html +14 -14
- package/app/m/commerce/Payment/index.html +14 -14
- package/app/m/commerce/PaymentAllocation/index.html +14 -14
- package/app/m/commerce/PaymentInstrument/index.html +14 -14
- package/app/m/commerce/PaymentIntent/index.html +14 -14
- package/app/m/commerce/Payout/index.html +14 -14
- package/app/m/commerce/ProductionOrder/index.html +14 -14
- package/app/m/commerce/PurchaseOrder/index.html +14 -14
- package/app/m/commerce/Vendor/index.html +14 -14
- package/app/m/commerce/WholesaleOrder/index.html +14 -14
- package/app/m/content/Content/index.html +14 -14
- package/app/m/content/ContentContribution/index.html +14 -14
- package/app/m/content/ContentContributionAttachment/index.html +14 -14
- package/app/m/content/ContentContributionRevision/index.html +14 -14
- package/app/m/content/ContentContributionType/index.html +14 -14
- package/app/m/content/ContentContributor/index.html +14 -14
- package/app/m/content/ContentCorrection/index.html +14 -14
- package/app/m/content/ContentFeedSource/index.html +14 -14
- package/app/m/content/ContentGovernanceAssignment/index.html +14 -14
- package/app/m/content/ContentGovernancePolicy/index.html +14 -14
- package/app/m/content/ContentGovernanceProfile/index.html +14 -14
- package/app/m/content/ContentReference/index.html +14 -14
- package/app/m/content/ContentReview/index.html +14 -14
- package/app/m/content/ContentVersion/index.html +14 -14
- package/app/m/content/Contents/index.html +14 -14
- package/app/m/events/Event/index.html +14 -14
- package/app/m/events/EventParticipant/index.html +14 -14
- package/app/m/events/EventSeries/index.html +14 -14
- package/app/m/events/EventType/index.html +14 -14
- package/app/m/facts/Fact/index.html +14 -14
- package/app/m/facts/FactContent/index.html +14 -14
- package/app/m/facts/FactEvidence/index.html +14 -14
- package/app/m/facts/FactSource/index.html +14 -14
- package/app/m/facts/FactSubject/index.html +14 -14
- package/app/m/facts/FactTag/index.html +14 -14
- package/app/m/fields/FieldPolicy/index.html +14 -14
- package/app/m/fields/FieldPolicySuggestion/index.html +14 -14
- package/app/m/fields/FieldUsageCounter/index.html +14 -14
- package/app/m/images/Image/index.html +14 -14
- package/app/m/inventory/InventoryLocation/index.html +14 -14
- package/app/m/inventory/StockLevel/index.html +14 -14
- package/app/m/inventory/StockMovement/index.html +14 -14
- package/app/m/ledgers/Account/index.html +14 -14
- package/app/m/ledgers/Journal/index.html +14 -14
- package/app/m/ledgers/JournalEntry/index.html +14 -14
- package/app/m/manufacturing/Assembly/index.html +14 -14
- package/app/m/manufacturing/BillOfMaterials/index.html +14 -14
- package/app/m/manufacturing/BomLine/index.html +14 -14
- package/app/m/manufacturing/Operation/index.html +14 -14
- package/app/m/manufacturing/ProductionRun/index.html +14 -14
- package/app/m/manufacturing/ProductionRunCompletion/index.html +14 -14
- package/app/m/manufacturing/RoutingStep/index.html +14 -14
- package/app/m/marketing/Campaign/index.html +14 -14
- package/app/m/marketing/CampaignChannel/index.html +14 -14
- package/app/m/marketing/CampaignMetricSnapshot/index.html +14 -14
- package/app/m/messages/Account/index.html +14 -14
- package/app/m/messages/Attachment/index.html +14 -14
- package/app/m/messages/Blacklist/index.html +14 -14
- package/app/m/messages/Email/failed-sends/index.html +14 -14
- package/app/m/messages/Email/index.html +14 -14
- package/app/m/messages/Email/mailbox/index.html +14 -14
- package/app/m/messages/EmailAccount/index.html +14 -14
- package/app/m/messages/EmailFolder/index.html +14 -14
- package/app/m/messages/Message/index.html +14 -14
- package/app/m/messages/MessagingEndpoint/index.html +14 -14
- package/app/m/messages/PersonaMessageRoute/index.html +14 -14
- package/app/m/messages/SlackAccount/index.html +14 -14
- package/app/m/messages/SlackMessage/index.html +14 -14
- package/app/m/messages/TelegramAccount/index.html +14 -14
- package/app/m/messages/Tweet/index.html +14 -14
- package/app/m/messages/TwitterAccount/index.html +14 -14
- package/app/m/messages/Whitelist/index.html +14 -14
- package/app/m/messages/ZulipAccount/index.html +14 -14
- package/app/m/places/Place/index.html +14 -14
- package/app/m/places/PlaceType/index.html +14 -14
- package/app/m/preferences/UiPreferenceRecord/index.html +14 -14
- package/app/m/products/Category/index.html +14 -14
- package/app/m/products/Material/index.html +14 -14
- package/app/m/products/Product/index.html +14 -14
- package/app/m/products/Product/ingredients/index.html +14 -14
- package/app/m/products/ProductVariant/index.html +14 -14
- package/app/m/products/Sku/index.html +14 -14
- package/app/m/profiles/ApiKey/index.html +14 -14
- package/app/m/profiles/Bot/index.html +14 -14
- package/app/m/profiles/MagicLinkToken/index.html +14 -14
- package/app/m/profiles/NostrIdentity/index.html +14 -14
- package/app/m/profiles/OidcIdentity/index.html +14 -14
- package/app/m/profiles/Organization/index.html +14 -14
- package/app/m/profiles/Person/index.html +14 -14
- package/app/m/profiles/Profile/index.html +14 -14
- package/app/m/profiles/ProfileMetadata/index.html +14 -14
- package/app/m/profiles/ProfileMetafield/index.html +14 -14
- package/app/m/profiles/ProfileRelationship/index.html +14 -14
- package/app/m/profiles/ProfileRelationshipTerm/index.html +14 -14
- package/app/m/profiles/ProfileRelationshipType/index.html +14 -14
- package/app/m/profiles/ProfileType/index.html +14 -14
- package/app/m/projects/Comment/index.html +14 -14
- package/app/m/projects/Issue/index.html +14 -14
- package/app/m/projects/Label/index.html +14 -14
- package/app/m/projects/Project/index.html +14 -14
- package/app/m/projects/ProjectIntegration/index.html +14 -14
- package/app/m/projects/PullRequest/index.html +14 -14
- package/app/m/projects/Repository/index.html +14 -14
- package/app/m/properties/Property/index.html +14 -14
- package/app/m/properties/Zone/index.html +14 -14
- package/app/m/reports/RuntimeReport/index.html +14 -14
- package/app/m/reports/SmrtPrincipalReportRefreshTask/index.html +14 -14
- package/app/m/reports/SmrtReportLock/index.html +14 -14
- package/app/m/reports/SmrtReportRefreshTask/index.html +14 -14
- package/app/m/reports/SmrtReportRun/index.html +14 -14
- package/app/m/reports/SmrtReportSchedule/index.html +14 -14
- package/app/m/reports/SmrtReportWatermark/index.html +14 -14
- package/app/m/sales/AttributionException/index.html +14 -14
- package/app/m/sales/AttributionPolicy/index.html +14 -14
- package/app/m/sales/Commission/index.html +14 -14
- package/app/m/sales/CommissionAdjustment/index.html +14 -14
- package/app/m/sales/CommissionPayout/index.html +14 -14
- package/app/m/sales/CommissionPlan/index.html +14 -14
- package/app/m/sales/Earner/index.html +14 -14
- package/app/m/sales/EarnerSourceAttribution/index.html +14 -14
- package/app/m/sales/EarningEvent/index.html +14 -14
- package/app/m/sales/ExecutedAgreement/index.html +14 -14
- package/app/m/sales/Lead/index.html +14 -14
- package/app/m/sales/Opportunity/index.html +14 -14
- package/app/m/sales/OpportunityConversion/index.html +14 -14
- package/app/m/sales/PipelineDefinition/index.html +14 -14
- package/app/m/sales/PipelineStage/index.html +14 -14
- package/app/m/sales/Referral/index.html +14 -14
- package/app/m/sales/ReferralAgreement/index.html +14 -14
- package/app/m/sales/ReferralLink/index.html +14 -14
- package/app/m/sales/ReferralProgram/index.html +14 -14
- package/app/m/sales/ReferralTermSnapshot/index.html +14 -14
- package/app/m/sales/ReferralTouch/index.html +14 -14
- package/app/m/sales/Referrer/index.html +14 -14
- package/app/m/sales/SalesActivity/index.html +14 -14
- package/app/m/sales/SalesRepresentative/index.html +14 -14
- package/app/m/sites/Site/index.html +14 -14
- package/app/m/sites/SiteAgentBinding/index.html +14 -14
- package/app/m/social/OAuthState/index.html +14 -14
- package/app/m/social/SocialAccount/index.html +14 -14
- package/app/m/social/SocialPost/index.html +14 -14
- package/app/m/social/SocialPostAnalyticsSnapshot/index.html +14 -14
- package/app/m/subscriptions/BillingAdjustment/index.html +14 -14
- package/app/m/subscriptions/ClientCharge/index.html +14 -14
- package/app/m/subscriptions/CreditGrant/index.html +14 -14
- package/app/m/subscriptions/PricingRule/index.html +14 -14
- package/app/m/subscriptions/RetailCharge/index.html +14 -14
- package/app/m/subscriptions/SpendingPolicy/index.html +14 -14
- package/app/m/subscriptions/SubscriptionPlan/index.html +14 -14
- package/app/m/subscriptions/TenantSubscription/index.html +14 -14
- package/app/m/subscriptions/TenantUsageMetric/index.html +14 -14
- package/app/m/support/ServiceTimeEntry/index.html +14 -14
- package/app/m/support/SupportAiRun/index.html +14 -14
- package/app/m/support/SupportAvailability/index.html +14 -14
- package/app/m/support/SupportCase/index.html +14 -14
- package/app/m/support/SupportCaseEvent/index.html +14 -14
- package/app/m/support/SupportChannelBinding/index.html +14 -14
- package/app/m/support/SupportCharge/index.html +14 -14
- package/app/m/support/SupportCompensation/index.html +14 -14
- package/app/m/support/SupportCompensationPlan/index.html +14 -14
- package/app/m/support/SupportEscalation/index.html +14 -14
- package/app/m/support/SupportInteraction/index.html +14 -14
- package/app/m/support/SupportPlan/index.html +14 -14
- package/app/m/support/SupportPolicy/index.html +14 -14
- package/app/m/support/SupportQualification/index.html +14 -14
- package/app/m/support/SupportServiceTarget/index.html +14 -14
- package/app/m/support/SupportSpecialist/index.html +14 -14
- package/app/m/support/SupportWorkLink/index.html +14 -14
- package/app/m/tags/Tag/index.html +14 -14
- package/app/m/tags/TagAlias/index.html +14 -14
- package/app/m/timesheets/AttendanceBreak/index.html +14 -14
- package/app/m/timesheets/AttendancePunch/index.html +14 -14
- package/app/m/timesheets/ServiceChargeSnapshot/index.html +14 -14
- package/app/m/timesheets/ServiceCompensationSnapshot/index.html +14 -14
- package/app/m/timesheets/ServiceTimeEntry/index.html +14 -14
- package/app/m/users/AccessRequest/index.html +14 -14
- package/app/m/users/Group/index.html +14 -14
- package/app/m/users/GroupMember/index.html +14 -14
- package/app/m/users/GroupRole/index.html +14 -14
- package/app/m/users/Membership/index.html +14 -14
- package/app/m/users/MembershipOverride/index.html +14 -14
- package/app/m/users/Permission/index.html +14 -14
- package/app/m/users/ResourceGrant/index.html +14 -14
- package/app/m/users/Role/index.html +14 -14
- package/app/m/users/RolePermission/index.html +14 -14
- package/app/m/users/Session/index.html +14 -14
- package/app/m/users/Tenant/index.html +14 -14
- package/app/m/users/TenantIntegration/index.html +14 -14
- package/app/m/users/TenantPermissionOverride/index.html +14 -14
- package/app/m/users/User/index.html +14 -14
- package/app/m/users/UsersCliAuthRequest/index.html +14 -14
- package/app/m/users/UsersMagicLinkToken/index.html +14 -14
- package/app/m/video/Character/index.html +14 -14
- package/app/m/video/CharacterAsset/index.html +14 -14
- package/app/m/video/CompositeJob/index.html +14 -14
- package/app/m/video/Performer/index.html +14 -14
- package/app/m/video/PerformerAsset/index.html +14 -14
- package/app/m/video/Scene/index.html +14 -14
- package/app/m/video/SceneAsset/index.html +14 -14
- package/app/m/video/VideoComposition/index.html +14 -14
- package/app/m/video/VideoCompositionAsset/index.html +14 -14
- package/app/m/video/VideoSequence/index.html +14 -14
- package/app/m/video/VideoSequenceAsset/index.html +14 -14
- package/app/m/video/VideoShot/index.html +14 -14
- package/app/m/video/VideoShotAsset/index.html +14 -14
- package/app/m/video/VideoShotCharacter/index.html +14 -14
- package/app/m/video/VideoWorkflow/index.html +14 -14
- package/app/m/voice/VoiceOutput/index.html +14 -14
- package/app/m/voice/VoiceProfile/index.html +14 -14
- package/app/m/voice/VoiceSample/index.html +14 -14
- package/app/packages/ads/index.html +12 -12
- package/app/packages/analytics/index.html +12 -12
- package/app/packages/approvals/index.html +12 -12
- package/app/packages/assets/index.html +12 -12
- package/app/packages/chat/index.html +12 -12
- package/app/packages/comments/index.html +12 -12
- package/app/packages/commerce/index.html +12 -12
- package/app/packages/content/index.html +12 -12
- package/app/packages/events/index.html +12 -12
- package/app/packages/expenses/index.html +12 -12
- package/app/packages/facts/index.html +12 -12
- package/app/packages/fields/index.html +12 -12
- package/app/packages/human-resources/index.html +12 -12
- package/app/packages/images/index.html +12 -12
- package/app/packages/index.html +12 -12
- package/app/packages/inventory/index.html +12 -12
- package/app/packages/ledgers/index.html +12 -12
- package/app/packages/manufacturing/index.html +12 -12
- package/app/packages/marketing/index.html +12 -12
- package/app/packages/messages/index.html +12 -12
- package/app/packages/places/index.html +12 -12
- package/app/packages/preferences/index.html +12 -12
- package/app/packages/products/index.html +12 -12
- package/app/packages/profiles/index.html +12 -12
- package/app/packages/projects/index.html +12 -12
- package/app/packages/properties/index.html +12 -12
- package/app/packages/reports/index.html +12 -12
- package/app/packages/sales/index.html +12 -12
- package/app/packages/sites/index.html +12 -12
- package/app/packages/social/index.html +12 -12
- package/app/packages/subscriptions/index.html +12 -12
- package/app/packages/support/index.html +12 -12
- package/app/packages/tags/index.html +12 -12
- package/app/packages/timesheets/index.html +12 -12
- package/app/packages/users/index.html +12 -12
- package/app/packages/video/index.html +12 -12
- package/app/packages/voice/index.html +12 -12
- package/app/recipes/account-access/help/index.html +12 -12
- package/app/recipes/account-access/index.html +12 -12
- package/app/recipes/activity/help/index.html +12 -12
- package/app/recipes/activity/index.html +12 -12
- package/app/recipes/agreements/help/index.html +12 -12
- package/app/recipes/agreements/index.html +12 -12
- package/app/recipes/analytics.reports/help/index.html +12 -12
- package/app/recipes/analytics.reports/index.html +12 -12
- package/app/recipes/assets/help/index.html +12 -12
- package/app/recipes/assets/index.html +12 -12
- package/app/recipes/billing/help/index.html +12 -12
- package/app/recipes/billing/index.html +12 -12
- package/app/recipes/chat.assistant/help/index.html +12 -12
- package/app/recipes/chat.assistant/index.html +12 -12
- package/app/recipes/comments/help/index.html +12 -12
- package/app/recipes/comments/index.html +12 -12
- package/app/recipes/commerce.customers/help/index.html +12 -12
- package/app/recipes/commerce.customers/index.html +12 -12
- package/app/recipes/commerce.estimates/help/index.html +12 -12
- package/app/recipes/commerce.estimates/index.html +12 -12
- package/app/recipes/commerce.purchases/help/index.html +12 -12
- package/app/recipes/commerce.purchases/index.html +12 -12
- package/app/recipes/commerce.sales/help/index.html +12 -12
- package/app/recipes/commerce.sales/index.html +12 -12
- package/app/recipes/commerce.vendors/help/index.html +12 -12
- package/app/recipes/commerce.vendors/index.html +12 -12
- package/app/recipes/commerce.wholesale/help/index.html +12 -12
- package/app/recipes/commerce.wholesale/index.html +12 -12
- package/app/recipes/events.calendar/help/index.html +12 -12
- package/app/recipes/events.calendar/index.html +12 -12
- package/app/recipes/fields.form-customization/help/index.html +12 -12
- package/app/recipes/fields.form-customization/index.html +12 -12
- package/app/recipes/inventory.stock/help/index.html +12 -12
- package/app/recipes/inventory.stock/index.html +12 -12
- package/app/recipes/ledgers.bookkeeping/help/index.html +12 -12
- package/app/recipes/ledgers.bookkeeping/index.html +12 -12
- package/app/recipes/messages/help/index.html +12 -12
- package/app/recipes/messages/index.html +12 -12
- package/app/recipes/products/help/index.html +12 -12
- package/app/recipes/products/index.html +12 -12
- package/app/recipes/projects.tracker/help/index.html +12 -12
- package/app/recipes/projects.tracker/index.html +12 -12
- package/app/recipes/reports.materialized/help/index.html +12 -12
- package/app/recipes/reports.materialized/index.html +12 -12
- package/app/recipes/sales.pipeline/help/index.html +12 -12
- package/app/recipes/sales.pipeline/index.html +12 -12
- package/app/recipes/tags.taxonomy/help/index.html +12 -12
- package/app/recipes/tags.taxonomy/index.html +12 -12
- package/app/recipes/team-collaboration/help/index.html +12 -12
- package/app/recipes/team-collaboration/index.html +12 -12
- package/app/s/custom-billing/index.html +13 -13
- package/app/s/custom-buying/index.html +13 -13
- package/app/s/custom-classes/index.html +13 -13
- package/app/s/custom-jobs/index.html +13 -13
- package/app/s/custom-kitchen/index.html +13 -13
- package/app/s/custom-material/index.html +13 -13
- package/app/s/custom-members/index.html +13 -13
- package/app/s/custom-parts/index.html +13 -13
- package/app/s/custom-schedule/index.html +13 -13
- package/app/s/custom-shop/index.html +13 -13
- package/app/s/custom-wholesale/index.html +13 -13
- package/app/s/section-access-control/index.html +13 -13
- package/app/s/section-account-security/index.html +13 -13
- package/app/s/section-accounting/index.html +13 -13
- package/app/s/section-activity/index.html +13 -13
- package/app/s/section-agreements/index.html +13 -13
- package/app/s/section-analytics/index.html +13 -13
- package/app/s/section-assets/index.html +13 -13
- package/app/s/section-billing/index.html +13 -13
- package/app/s/section-calendar/index.html +13 -13
- package/app/s/section-catalog/index.html +13 -13
- package/app/s/section-chat.assistant/index.html +13 -13
- package/app/s/section-comments/index.html +13 -13
- package/app/s/section-fields.form-customization/index.html +13 -13
- package/app/s/section-messages/index.html +13 -13
- package/app/s/section-more/index.html +13 -13
- package/app/s/section-operations/index.html +13 -13
- package/app/s/section-projects/index.html +13 -13
- package/app/s/section-purchasing/index.html +13 -13
- package/app/s/section-reports.materialized/index.html +13 -13
- package/app/s/section-sales/index.html +13 -13
- package/app/s/section-taxonomy/index.html +13 -13
- package/app/s/section-team/index.html +13 -13
- package/dist/ai/state.svelte.d.ts +9 -4
- package/dist/ai/state.svelte.js +46 -16
- package/dist/ai/status.js +8 -0
- package/dist/assistant/session.svelte.d.ts +1 -0
- package/dist/assistant/session.svelte.js +22 -4
- package/dist/components/AiSetup.svelte +31 -2
- package/dist/components/BrowserAssistant.svelte +12 -8
- package/dist/core/app.d.ts +33 -8
- package/dist/core/app.js +112 -8
- package/dist/index.d.ts +1 -1
- package/dist/inference/byo.svelte.d.ts +8 -4
- package/dist/inference/byo.svelte.js +36 -8
- package/dist/inference/config.d.ts +12 -5
- package/dist/inference/config.js +96 -40
- package/dist/inference/openai.js +5 -0
- package/dist/kitchen/client.js +10 -4
- package/dist/planner/assistant.js +1 -1
- package/package.json +2 -1
- package/app/_app/immutable/chunks/BYde9M_U.js +0 -1
- package/app/_app/immutable/chunks/OJ_lLTHH.js +0 -1
- package/app/_app/immutable/chunks/ufuM4XBq.js +0 -33
- package/app/_app/immutable/entry/start.CH9DJLgI.js +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AssistantSession, type SessionOptions } from '../assistant/session.svelte.ts';
|
|
2
2
|
import { type VoiceOptions, VoiceSession } from '../assistant/voice.svelte.ts';
|
|
3
3
|
import { ByoModel } from '../inference/byo.svelte.ts';
|
|
4
|
-
import { type ConfigResult, type InferenceConfig } from '../inference/config.ts';
|
|
4
|
+
import { type ConfigResult, type InferenceConfig, type InferenceMode } from '../inference/config.ts';
|
|
5
5
|
import { type CapabilitySummary } from './status.ts';
|
|
6
6
|
/** UI choices that are not part of the cookbook. */
|
|
7
7
|
export interface AiPrefs {
|
|
@@ -59,7 +59,9 @@ export declare class AiState {
|
|
|
59
59
|
speaking: boolean;
|
|
60
60
|
/** Where the model runs, from `planner.config.json` or the `inference` prop. */
|
|
61
61
|
inference: InferenceConfig;
|
|
62
|
-
/**
|
|
62
|
+
/** Modes this policy exposes. Manual is always available for a multi-mode policy. */
|
|
63
|
+
availableModes: InferenceMode[];
|
|
64
|
+
/** Set when the config was unusable and inference fails closed to manual. */
|
|
63
65
|
notice: string;
|
|
64
66
|
/** The visitor's own endpoint (byo mode only). */
|
|
65
67
|
byo: ByoModel | null;
|
|
@@ -84,10 +86,13 @@ export declare class AiState {
|
|
|
84
86
|
/**
|
|
85
87
|
* Apply the inference config. `host` is ready at once (nothing to download);
|
|
86
88
|
* `byo` is ready once the visitor has connected an endpoint on the AI page;
|
|
87
|
-
* `browser` is today's WebLLM. An unusable config arrives as `
|
|
88
|
-
*
|
|
89
|
+
* `browser` is today's WebLLM. An unusable config arrives as `manual` with a
|
|
90
|
+
* `notice`.
|
|
89
91
|
*/
|
|
90
92
|
configure(result: ConfigResult): void;
|
|
93
|
+
/** Change providers only after a visitor selects one from the configured policy. */
|
|
94
|
+
selectInference(mode: InferenceMode): void;
|
|
95
|
+
private applyMode;
|
|
91
96
|
private syncByo;
|
|
92
97
|
private decideFirstRun;
|
|
93
98
|
/** Before hydration every capability reads as not set up, as on the server. */
|
package/dist/ai/state.svelte.js
CHANGED
|
@@ -63,7 +63,9 @@ export class AiState {
|
|
|
63
63
|
speaking = $state(false);
|
|
64
64
|
/** Where the model runs, from `planner.config.json` or the `inference` prop. */
|
|
65
65
|
inference = $state(DEFAULT_INFERENCE);
|
|
66
|
-
/**
|
|
66
|
+
/** Modes this policy exposes. Manual is always available for a multi-mode policy. */
|
|
67
|
+
availableModes = $state(['browser']);
|
|
68
|
+
/** Set when the config was unusable and inference fails closed to manual. */
|
|
67
69
|
notice = $state('');
|
|
68
70
|
/** The visitor's own endpoint (byo mode only). */
|
|
69
71
|
byo = $state(null);
|
|
@@ -119,36 +121,60 @@ export class AiState {
|
|
|
119
121
|
/**
|
|
120
122
|
* Apply the inference config. `host` is ready at once (nothing to download);
|
|
121
123
|
* `byo` is ready once the visitor has connected an endpoint on the AI page;
|
|
122
|
-
* `browser` is today's WebLLM. An unusable config arrives as `
|
|
123
|
-
*
|
|
124
|
+
* `browser` is today's WebLLM. An unusable config arrives as `manual` with a
|
|
125
|
+
* `notice`.
|
|
124
126
|
*/
|
|
125
127
|
configure(result) {
|
|
126
128
|
const { config, notice } = result;
|
|
127
129
|
this.pendingConfig = false;
|
|
128
130
|
this.inference = config;
|
|
129
131
|
this.notice = notice ?? '';
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
132
|
+
const configured = [config.mode, ...(config.alternatives ?? [])];
|
|
133
|
+
this.availableModes = [
|
|
134
|
+
...configured,
|
|
135
|
+
...(config.alternatives?.length && !configured.includes('manual')
|
|
136
|
+
? ['manual']
|
|
137
|
+
: []),
|
|
138
|
+
];
|
|
139
|
+
this.byo = configured.includes('byo')
|
|
140
|
+
? new ByoModel({
|
|
141
|
+
storage: this.options.storage,
|
|
142
|
+
credentialPersistence: config.credentialPersistence,
|
|
143
|
+
presets: config.byo?.presets,
|
|
144
|
+
fetch: this.options.fetch,
|
|
145
|
+
onChange: () => this.syncByo(),
|
|
146
|
+
})
|
|
147
|
+
: null;
|
|
148
|
+
this.applyMode(config.mode);
|
|
149
|
+
if (this.hydrated)
|
|
150
|
+
this.decideFirstRun();
|
|
151
|
+
}
|
|
152
|
+
/** Change providers only after a visitor selects one from the configured policy. */
|
|
153
|
+
selectInference(mode) {
|
|
154
|
+
if (!this.availableModes.includes(mode) || mode === this.inference.mode) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.inference = { ...this.inference, mode };
|
|
158
|
+
this.notice = '';
|
|
159
|
+
this.applyMode(mode);
|
|
160
|
+
}
|
|
161
|
+
applyMode(mode) {
|
|
162
|
+
this.session.setMode(mode);
|
|
163
|
+
if (mode === 'host' && this.inference.host) {
|
|
133
164
|
const { controller, store, settings, theme } = this.options.session;
|
|
134
165
|
const plan = controller ?? createSliceController({ store, settings, theme });
|
|
135
166
|
this.session.useRemote(createHostChat({
|
|
136
|
-
endpoint:
|
|
167
|
+
endpoint: this.inference.host.endpoint,
|
|
137
168
|
snapshot: () => plan.snapshot(),
|
|
138
169
|
fetch: this.options.fetch,
|
|
139
170
|
}), 'Server');
|
|
140
171
|
}
|
|
141
|
-
else if (
|
|
142
|
-
this.byo = new ByoModel({
|
|
143
|
-
storage: this.options.storage,
|
|
144
|
-
presets: config.byo?.presets,
|
|
145
|
-
fetch: this.options.fetch,
|
|
146
|
-
onChange: () => this.syncByo(),
|
|
147
|
-
});
|
|
172
|
+
else if (mode === 'byo') {
|
|
148
173
|
this.syncByo();
|
|
149
174
|
}
|
|
150
|
-
if (
|
|
151
|
-
this.
|
|
175
|
+
else if (mode === 'manual') {
|
|
176
|
+
this.session.useRemote(null, '');
|
|
177
|
+
}
|
|
152
178
|
}
|
|
153
179
|
syncByo() {
|
|
154
180
|
const byo = this.byo;
|
|
@@ -160,6 +186,7 @@ export class AiState {
|
|
|
160
186
|
// A host's server needs nothing set up, so the form has nothing to ask for.
|
|
161
187
|
this.firstRun =
|
|
162
188
|
this.inference.mode !== 'host' &&
|
|
189
|
+
this.inference.mode !== 'manual' &&
|
|
163
190
|
needsFirstRunSetup({
|
|
164
191
|
thinkDownloaded: this.session.prefs.consented.length > 0 ||
|
|
165
192
|
this.session.status === 'ready',
|
|
@@ -194,6 +221,9 @@ export class AiState {
|
|
|
194
221
|
}
|
|
195
222
|
/** One sentence on where what the visitor types goes, for the AI page. */
|
|
196
223
|
get privacyNote() {
|
|
224
|
+
if (this.inference.mode === 'manual') {
|
|
225
|
+
return 'Inference is off. Planning, validation and export still work without a model.';
|
|
226
|
+
}
|
|
197
227
|
if (this.inference.mode === 'host') {
|
|
198
228
|
return "Your messages and a short summary of your plan go to this site's server. Voice typing and reading aloud stay on this device.";
|
|
199
229
|
}
|
package/dist/ai/status.js
CHANGED
|
@@ -7,6 +7,14 @@ export function deriveCapabilities(input) {
|
|
|
7
7
|
}
|
|
8
8
|
function thinkSummary(t) {
|
|
9
9
|
const base = { id: 'think', name: 'Think' };
|
|
10
|
+
if (t.mode === 'manual') {
|
|
11
|
+
return {
|
|
12
|
+
...base,
|
|
13
|
+
state: 'off',
|
|
14
|
+
label: 'Think: inference off',
|
|
15
|
+
where: 'Off',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
10
18
|
if (t.mode === 'host') {
|
|
11
19
|
return {
|
|
12
20
|
...base,
|
|
@@ -40,6 +40,7 @@ export class AssistantSession {
|
|
|
40
40
|
loaded = null;
|
|
41
41
|
chat = null;
|
|
42
42
|
abort = null;
|
|
43
|
+
loadGeneration = 0;
|
|
43
44
|
options;
|
|
44
45
|
constructor(options) {
|
|
45
46
|
this.options = options;
|
|
@@ -65,7 +66,9 @@ export class AssistantSession {
|
|
|
65
66
|
? 'Connect your model on the AI page first, then I can help. The cards on the Planner page work without one.'
|
|
66
67
|
: this.mode === 'host'
|
|
67
68
|
? 'The assistant is not available right now. The cards on the Planner page work without it.'
|
|
68
|
-
:
|
|
69
|
+
: this.mode === 'manual'
|
|
70
|
+
? 'Inference is off. The cards on the Planner page work without it.'
|
|
71
|
+
: 'Download a model first, then I can help. The cards on the Planner page work without one.',
|
|
69
72
|
onReply: (text) => options.onReply?.(text),
|
|
70
73
|
});
|
|
71
74
|
}
|
|
@@ -74,14 +77,18 @@ export class AssistantSession {
|
|
|
74
77
|
* download; the chat is set with `useRemote`.
|
|
75
78
|
*/
|
|
76
79
|
setMode(mode) {
|
|
80
|
+
if (mode !== this.mode)
|
|
81
|
+
this.unload();
|
|
77
82
|
this.mode = mode;
|
|
78
83
|
if (mode !== 'browser') {
|
|
79
|
-
this.unload();
|
|
80
84
|
this.status = 'idle';
|
|
81
85
|
}
|
|
82
86
|
else if (!(this.options.webgpu ?? isWebGPUAvailable)()) {
|
|
83
87
|
this.status = 'unsupported';
|
|
84
88
|
}
|
|
89
|
+
else {
|
|
90
|
+
this.status = 'idle';
|
|
91
|
+
}
|
|
85
92
|
}
|
|
86
93
|
/** The remote chat model, or null when none is connected (byo, before setup). */
|
|
87
94
|
useRemote(chat, label) {
|
|
@@ -112,11 +119,16 @@ export class AssistantSession {
|
|
|
112
119
|
this.error = '';
|
|
113
120
|
this.progress = { progress: 0, text: 'Starting' };
|
|
114
121
|
const abort = new AbortController();
|
|
122
|
+
const generation = ++this.loadGeneration;
|
|
115
123
|
this.abort = abort;
|
|
116
124
|
try {
|
|
117
125
|
const loaded = await loadModel(modelId, (report) => {
|
|
118
126
|
this.progress = report;
|
|
119
127
|
}, abort.signal, this.options.host ?? browserHost);
|
|
128
|
+
if (generation !== this.loadGeneration || this.mode !== 'browser') {
|
|
129
|
+
loaded.dispose();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
120
132
|
this.loaded = loaded;
|
|
121
133
|
// Consent is recorded only once the download completed: a cancelled or
|
|
122
134
|
// failed attempt must show the size and memory warning again.
|
|
@@ -133,6 +145,8 @@ export class AssistantSession {
|
|
|
133
145
|
this.status = 'ready';
|
|
134
146
|
}
|
|
135
147
|
catch (error) {
|
|
148
|
+
if (generation !== this.loadGeneration)
|
|
149
|
+
return;
|
|
136
150
|
if (abort.signal.aborted) {
|
|
137
151
|
this.status = 'idle';
|
|
138
152
|
}
|
|
@@ -142,7 +156,8 @@ export class AssistantSession {
|
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
finally {
|
|
145
|
-
this.
|
|
159
|
+
if (generation === this.loadGeneration)
|
|
160
|
+
this.abort = null;
|
|
146
161
|
}
|
|
147
162
|
}
|
|
148
163
|
/** Stop a download in progress. */
|
|
@@ -152,7 +167,10 @@ export class AssistantSession {
|
|
|
152
167
|
/** Free the model, for example to choose another. */
|
|
153
168
|
unload() {
|
|
154
169
|
// A load in progress is aborted too, which terminates its worker.
|
|
155
|
-
this.
|
|
170
|
+
this.loadGeneration += 1;
|
|
171
|
+
const abort = this.abort;
|
|
172
|
+
this.abort = null;
|
|
173
|
+
abort?.abort();
|
|
156
174
|
this.transport.abort();
|
|
157
175
|
this.loaded?.dispose();
|
|
158
176
|
this.loaded = null;
|
|
@@ -42,6 +42,12 @@ const byo = $derived(aiState.byo);
|
|
|
42
42
|
const thinkWhere = $derived(
|
|
43
43
|
summaries.find((s) => s.id === 'think')?.where ?? '',
|
|
44
44
|
);
|
|
45
|
+
const modeLabel = {
|
|
46
|
+
manual: 'Manual planning',
|
|
47
|
+
byo: 'Your model',
|
|
48
|
+
browser: 'In-browser model (WebLLM)',
|
|
49
|
+
host: "This site's server",
|
|
50
|
+
} as const;
|
|
45
51
|
|
|
46
52
|
const model = $derived(getModel(session.prefs.modelId));
|
|
47
53
|
// A roomy graphics card can run the smarter model; it is only suggested, the
|
|
@@ -84,7 +90,28 @@ const handsFreeAvailable = $derived(voice.status === 'ready');
|
|
|
84
90
|
</p>
|
|
85
91
|
</div>
|
|
86
92
|
</header>
|
|
87
|
-
{#if
|
|
93
|
+
{#if aiState.availableModes.length > 1}
|
|
94
|
+
<label>
|
|
95
|
+
Assistant mode
|
|
96
|
+
<Select
|
|
97
|
+
value={mode}
|
|
98
|
+
onchange={(event) =>
|
|
99
|
+
aiState.selectInference(event.currentTarget.value as keyof typeof modeLabel)}
|
|
100
|
+
>
|
|
101
|
+
{#each aiState.availableModes as option (option)}
|
|
102
|
+
<option value={option}>{modeLabel[option]}</option>
|
|
103
|
+
{/each}
|
|
104
|
+
</Select>
|
|
105
|
+
</label>
|
|
106
|
+
<p class="meta">Changing modes happens only when you choose it here.</p>
|
|
107
|
+
{/if}
|
|
108
|
+
{#if mode === 'manual'}
|
|
109
|
+
<p class="status">Inference off</p>
|
|
110
|
+
<p class="meta">
|
|
111
|
+
Build, edit, validate and export your cookbook without a model. No
|
|
112
|
+
provider is contacted and no browser model is downloaded.
|
|
113
|
+
</p>
|
|
114
|
+
{:else if mode === 'host'}
|
|
88
115
|
<p class="status">Server</p>
|
|
89
116
|
<p class="meta">
|
|
90
117
|
This site's server answers the assistant. What you type, and a short
|
|
@@ -146,7 +173,9 @@ const handsFreeAvailable = $derived(voice.status === 'ready');
|
|
|
146
173
|
</p>
|
|
147
174
|
{/if}
|
|
148
175
|
<p class="meta">
|
|
149
|
-
|
|
176
|
+
{aiState.inference.credentialPersistence === 'memory'
|
|
177
|
+
? 'Kept only in this tab until reload'
|
|
178
|
+
: 'Stored only in this browser'}, and sent only to {byo.baseUrl || 'the address above'} (https, or this computer).
|
|
150
179
|
<button class="link" type="button" onclick={() => byo.forgetKey()}>
|
|
151
180
|
Forget the key
|
|
152
181
|
</button>
|
|
@@ -33,13 +33,15 @@ const voice = $derived(aiState.voice);
|
|
|
33
33
|
const model = $derived(getModel(session.prefs.modelId));
|
|
34
34
|
const dataSource = useDataSource();
|
|
35
35
|
const thinkName = $derived(
|
|
36
|
-
session.mode === '
|
|
37
|
-
?
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
: session.
|
|
36
|
+
session.mode === 'manual'
|
|
37
|
+
? 'Off'
|
|
38
|
+
: session.mode === 'browser'
|
|
39
|
+
? model
|
|
40
|
+
? shortLabel(model)
|
|
41
|
+
: ''
|
|
42
|
+
: session.mode === 'host'
|
|
43
|
+
? 'Server'
|
|
44
|
+
: session.remoteLabel,
|
|
43
45
|
);
|
|
44
46
|
|
|
45
47
|
// Applying a cookbook runs the Cookbooks tab's path, with the cookbook's own
|
|
@@ -192,7 +194,9 @@ $effect(() => {
|
|
|
192
194
|
<h2>Assistant</h2>
|
|
193
195
|
<p>
|
|
194
196
|
Describe your business and an assistant adds the matching recipes.
|
|
195
|
-
{aiState.inference.mode === '
|
|
197
|
+
{aiState.inference.mode === 'manual'
|
|
198
|
+
? 'Inference is off. The Planner page still works without a model.'
|
|
199
|
+
: aiState.inference.mode === 'browser'
|
|
196
200
|
? 'It runs on your own device, so nothing you type leaves this page.'
|
|
197
201
|
: aiState.privacyNote}
|
|
198
202
|
</p>
|
package/dist/core/app.d.ts
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
|
+
import type { InferenceConfig } from '../inference/config.ts';
|
|
2
|
+
import type { KitchenEndpoint } from '../kitchen/client.ts';
|
|
1
3
|
/**
|
|
2
|
-
* Absolute path of the prerendered
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Node built-ins.
|
|
6
|
-
*
|
|
7
|
-
* Serve the files from here, and write your own `planner.config.json` next to
|
|
8
|
-
* its `index.html` (copy the directory, or answer that one path yourself).
|
|
4
|
+
* Absolute path of the root-built prerendered planner app inside this package.
|
|
5
|
+
* Node only; kept out of `./core` so that entry stays free of Node built-ins.
|
|
6
|
+
* Serve it at `/`, or use `materializeApp` for a supported subpath artifact.
|
|
9
7
|
*/
|
|
10
8
|
export declare const appDir: string;
|
|
11
|
-
/** Absolute path of one
|
|
9
|
+
/** Absolute path of one packaged app file, e.g. `appFile('index.html')`. */
|
|
12
10
|
export declare function appFile(relativePath: string): string;
|
|
11
|
+
export interface PlannerAppConfig {
|
|
12
|
+
inference?: InferenceConfig;
|
|
13
|
+
kitchen?: KitchenEndpoint;
|
|
14
|
+
}
|
|
15
|
+
export interface MaterializeAppOptions {
|
|
16
|
+
/** New or empty directory that receives the app root. */
|
|
17
|
+
outDir: string;
|
|
18
|
+
/** Canonical mount prefix: leading slash, no trailing slash, e.g. `/plan`. */
|
|
19
|
+
basePath: string;
|
|
20
|
+
/** Written as `planner.config.json` after validation and normalization. */
|
|
21
|
+
config: PlannerAppConfig;
|
|
22
|
+
}
|
|
23
|
+
export interface MaterializedApp {
|
|
24
|
+
outDir: string;
|
|
25
|
+
configFile: string;
|
|
26
|
+
fallbackFile: string;
|
|
27
|
+
}
|
|
28
|
+
/** Validate and canonicalize a non-root app mount prefix. */
|
|
29
|
+
export declare function normalizeAppBasePath(basePath: string): string;
|
|
30
|
+
/** Validate config strictly enough for an immutable public artifact. */
|
|
31
|
+
export declare function normalizePlannerAppConfig(config: PlannerAppConfig): PlannerAppConfig;
|
|
32
|
+
/**
|
|
33
|
+
* Copy the published static app into a deterministic, prefix-safe deployment
|
|
34
|
+
* artifact. The copy is assembled beside `outDir` and renamed only after its
|
|
35
|
+
* fallback and config validate, so callers never receive a partial tree.
|
|
36
|
+
*/
|
|
37
|
+
export declare function materializeApp(options: MaterializeAppOptions): MaterializedApp;
|
package/dist/core/app.js
CHANGED
|
@@ -1,15 +1,119 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, renameSync, rmdirSync, rmSync, statSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { dirname, relative, resolve, sep } from 'node:path';
|
|
1
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { validateInferenceConfig } from "../inference/config.js";
|
|
5
|
+
import { parseKitchenConfig } from "../kitchen/client.js";
|
|
2
6
|
/**
|
|
3
|
-
* Absolute path of the prerendered
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Node built-ins.
|
|
7
|
-
*
|
|
8
|
-
* Serve the files from here, and write your own `planner.config.json` next to
|
|
9
|
-
* its `index.html` (copy the directory, or answer that one path yourself).
|
|
7
|
+
* Absolute path of the root-built prerendered planner app inside this package.
|
|
8
|
+
* Node only; kept out of `./core` so that entry stays free of Node built-ins.
|
|
9
|
+
* Serve it at `/`, or use `materializeApp` for a supported subpath artifact.
|
|
10
10
|
*/
|
|
11
11
|
export const appDir = fileURLToPath(new URL('../../app/', import.meta.url));
|
|
12
|
-
/** Absolute path of one
|
|
12
|
+
/** Absolute path of one packaged app file, e.g. `appFile('index.html')`. */
|
|
13
13
|
export function appFile(relativePath) {
|
|
14
14
|
return fileURLToPath(new URL(relativePath, new URL('../../app/', import.meta.url)));
|
|
15
15
|
}
|
|
16
|
+
const sensitiveName = /^(?:api[-_]?key|key|token|authorization|secret|password)$/i;
|
|
17
|
+
/** Validate and canonicalize a non-root app mount prefix. */
|
|
18
|
+
export function normalizeAppBasePath(basePath) {
|
|
19
|
+
if (typeof basePath !== 'string' ||
|
|
20
|
+
!/^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/.test(basePath) ||
|
|
21
|
+
basePath.split('/').some((segment) => segment === '.' || segment === '..')) {
|
|
22
|
+
throw new Error('basePath must start with /, contain URL-safe path segments, and have no trailing slash');
|
|
23
|
+
}
|
|
24
|
+
return basePath;
|
|
25
|
+
}
|
|
26
|
+
function assertCredentialFree(value, path = 'config') {
|
|
27
|
+
if (!value || typeof value !== 'object')
|
|
28
|
+
return;
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
value.forEach((entry, index) => {
|
|
31
|
+
assertCredentialFree(entry, `${path}[${index}]`);
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
36
|
+
if (sensitiveName.test(name)) {
|
|
37
|
+
throw new Error(`${path}.${name} is a credential field and cannot be built into the app`);
|
|
38
|
+
}
|
|
39
|
+
assertCredentialFree(entry, `${path}.${name}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Validate config strictly enough for an immutable public artifact. */
|
|
43
|
+
export function normalizePlannerAppConfig(config) {
|
|
44
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
45
|
+
throw new Error('config must be an object');
|
|
46
|
+
}
|
|
47
|
+
const unknown = Object.keys(config).filter((name) => name !== 'inference' && name !== 'kitchen');
|
|
48
|
+
if (unknown.length)
|
|
49
|
+
throw new Error(`unknown app config field: ${unknown[0]}`);
|
|
50
|
+
assertCredentialFree(config);
|
|
51
|
+
const inference = validateInferenceConfig({
|
|
52
|
+
inference: config.inference,
|
|
53
|
+
});
|
|
54
|
+
if (inference.notice)
|
|
55
|
+
throw new Error(inference.notice);
|
|
56
|
+
let kitchen;
|
|
57
|
+
if (config.kitchen !== undefined) {
|
|
58
|
+
kitchen = parseKitchenConfig(config.kitchen);
|
|
59
|
+
if (!kitchen) {
|
|
60
|
+
throw new Error('kitchen.endpoint must be a usable http(s) URL');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
inference: inference.config,
|
|
65
|
+
...(kitchen ? { kitchen } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function patchFallback(file, basePath) {
|
|
69
|
+
const source = readFileSync(file, 'utf8');
|
|
70
|
+
if (!source.includes('/_app/') || !/base:\s*""/.test(source)) {
|
|
71
|
+
throw new Error('packaged 404.html does not match the supported root fallback');
|
|
72
|
+
}
|
|
73
|
+
const patched = source
|
|
74
|
+
.replaceAll('/_app/', `${basePath}/_app/`)
|
|
75
|
+
.replace(/base:\s*""/, `base: ${JSON.stringify(basePath)}`);
|
|
76
|
+
if (patched.includes('"/_app/') || /base:\s*""/.test(patched)) {
|
|
77
|
+
throw new Error('could not make the fallback prefix-safe');
|
|
78
|
+
}
|
|
79
|
+
writeFileSync(file, patched);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Copy the published static app into a deterministic, prefix-safe deployment
|
|
83
|
+
* artifact. The copy is assembled beside `outDir` and renamed only after its
|
|
84
|
+
* fallback and config validate, so callers never receive a partial tree.
|
|
85
|
+
*/
|
|
86
|
+
export function materializeApp(options) {
|
|
87
|
+
const basePath = normalizeAppBasePath(options.basePath);
|
|
88
|
+
const config = normalizePlannerAppConfig(options.config);
|
|
89
|
+
const outDir = resolve(options.outDir);
|
|
90
|
+
const source = resolve(appDir);
|
|
91
|
+
const relation = relative(source, outDir);
|
|
92
|
+
if (!relation || (!relation.startsWith(`..${sep}`) && relation !== '..')) {
|
|
93
|
+
throw new Error('outDir must be outside the packaged app directory');
|
|
94
|
+
}
|
|
95
|
+
if (existsSync(outDir)) {
|
|
96
|
+
if (!statSync(outDir).isDirectory() || readdirSync(outDir).length > 0) {
|
|
97
|
+
throw new Error('outDir must be new or empty');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
mkdirSync(dirname(outDir), { recursive: true });
|
|
101
|
+
const temporary = mkdtempSync(resolve(dirname(outDir), '.smrt-planner-'));
|
|
102
|
+
try {
|
|
103
|
+
cpSync(source, temporary, { recursive: true });
|
|
104
|
+
patchFallback(resolve(temporary, '404.html'), basePath);
|
|
105
|
+
writeFileSync(resolve(temporary, 'planner.config.json'), `${JSON.stringify(config, null, 2)}\n`);
|
|
106
|
+
if (existsSync(outDir))
|
|
107
|
+
rmdirSync(outDir);
|
|
108
|
+
renameSync(temporary, outDir);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
rmSync(temporary, { recursive: true, force: true });
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
outDir,
|
|
116
|
+
configFile: resolve(outDir, 'planner.config.json'),
|
|
117
|
+
fallbackFile: resolve(outDir, '404.html'),
|
|
118
|
+
};
|
|
119
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
|
-
export { type ByoPresetDefinition, type ConfigResult, type InferenceConfig, type InferenceMode, loadInferenceConfig, parseInferenceConfig, } from './inference/config.ts';
|
|
8
|
+
export { type ByoPresetDefinition, type ConfigResult, type CredentialPersistence, type InferenceConfig, type InferenceMode, loadInferenceConfig, parseInferenceConfig, } from './inference/config.ts';
|
|
9
9
|
export { createHostChat, type HostChatOptions, type HostRequest, } from './inference/host.ts';
|
|
10
10
|
export { createOpenAIChat, testConnection } from './inference/openai.ts';
|
|
11
11
|
export { type KitchenConfig, type KitchenEndpoint, type KitchenOutcome, type KitchenResult, parseKitchenConfig, sendToKitchen, } from './kitchen/client.ts';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChatModel } from '../assistant/transport.ts';
|
|
2
|
-
import type { ByoPresetDefinition } from './config.ts';
|
|
2
|
+
import type { ByoPresetDefinition, CredentialPersistence } from './config.ts';
|
|
3
3
|
import { type ConnectionResult } from './openai.ts';
|
|
4
4
|
/** Choices (not the key): which endpoint, its address and model, and whether it is in use. */
|
|
5
5
|
export declare const BYO_PREFS_KEY = "smrt-planner:inference:v1";
|
|
@@ -24,6 +24,8 @@ export declare function loadByoKeys(storage: Storage | null): Record<string, Byo
|
|
|
24
24
|
export type ByoTestStatus = 'idle' | 'testing' | 'ok' | 'failed';
|
|
25
25
|
export interface ByoOptions {
|
|
26
26
|
storage: Storage | null;
|
|
27
|
+
/** Credentials default to local storage for compatibility; hosted apps use memory. */
|
|
28
|
+
credentialPersistence?: CredentialPersistence;
|
|
27
29
|
/** The config's `byo.presets`; default all built-ins. */
|
|
28
30
|
presets?: readonly (string | ByoPresetDefinition)[];
|
|
29
31
|
fetch?: typeof fetch;
|
|
@@ -33,8 +35,9 @@ export interface ByoOptions {
|
|
|
33
35
|
/**
|
|
34
36
|
* The visitor's own OpenAI-compatible endpoint: the preset they picked, its
|
|
35
37
|
* address, model and key, a connection test, and whether the assistant uses
|
|
36
|
-
* it. The key lives
|
|
37
|
-
*
|
|
38
|
+
* it. The key lives in the configured credential store (tab memory for hosted
|
|
39
|
+
* policies, localStorage for the compatible standalone default) and is only
|
|
40
|
+
* ever sent as the Authorization header to the chosen address.
|
|
38
41
|
*/
|
|
39
42
|
export declare class ByoModel {
|
|
40
43
|
readonly presets: ByoPresetDefinition[];
|
|
@@ -45,6 +48,7 @@ export declare class ByoModel {
|
|
|
45
48
|
testStatus: ByoTestStatus;
|
|
46
49
|
testMessage: string;
|
|
47
50
|
private readonly options;
|
|
51
|
+
private readonly credentialStorage;
|
|
48
52
|
constructor(options: ByoOptions);
|
|
49
53
|
get preset(): ByoPresetDefinition | undefined;
|
|
50
54
|
get baseUrl(): string;
|
|
@@ -82,5 +86,5 @@ export declare class ByoModel {
|
|
|
82
86
|
* (a mounted `Planner` in byo mode has no AI page of its own). Null when none
|
|
83
87
|
* is connected or what was saved is incomplete.
|
|
84
88
|
*/
|
|
85
|
-
export declare function savedByoChat(storage: Storage | null, presets?: readonly (string | ByoPresetDefinition)[], fetcher?: typeof fetch): ChatModel | null;
|
|
89
|
+
export declare function savedByoChat(storage: Storage | null, presets?: readonly (string | ByoPresetDefinition)[], fetcher?: typeof fetch, credentialPersistence?: CredentialPersistence): ChatModel | null;
|
|
86
90
|
export {};
|