@tiinex/app 0.1.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.
Files changed (580) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +31 -0
  3. package/README.md +26 -0
  4. package/docs/CONSUMER-CONTRACT.md +65 -0
  5. package/package.json +94 -0
  6. package/src/acceptance/knownScenarios.case.mjs +48 -0
  7. package/src/acceptance/knownScenarios.js +89 -0
  8. package/src/acceptance/postV423CanonicalTransitionProductVerticalSlice.case.mjs +774 -0
  9. package/src/acceptance/postV437M0ETimePortalProductParityClosure.case.mjs +51 -0
  10. package/src/acceptance/postV447M0FGithubSocialPublicationProductIntegration.case.mjs +33 -0
  11. package/src/acceptance/postV450M0ProductAcceptanceHardening.case.mjs +82 -0
  12. package/src/acceptance/postV470SchemaReadingContractMaterializationIdentitySourceCoalescingAuthorityCorrection.case.mjs +236 -0
  13. package/src/acceptance/recoveryAcceptance.case.mjs +196 -0
  14. package/src/adapters/adapter.definition.schema.json +33 -0
  15. package/src/adapters/archive/archive.adapter.case.mjs +212 -0
  16. package/src/adapters/export/export.adapter.js +79 -0
  17. package/src/adapters/git-native/git-native.adapter.js +43 -0
  18. package/src/adapters/github/github.adapter.case.mjs +843 -0
  19. package/src/adapters/github/github.adapter.js +395 -0
  20. package/src/adapters/github/github.issueEmbedded.js +262 -0
  21. package/src/adapters/github/github.issueMirror.js +309 -0
  22. package/src/adapters/github/github.issueSnapshot.js +475 -0
  23. package/src/adapters/github/github.issueSurface.js +188 -0
  24. package/src/adapters/github/github.issueTransport.js +237 -0
  25. package/src/adapters/github/github.publicationRead.js +24 -0
  26. package/src/adapters/github/github.readTransport.js +18 -0
  27. package/src/adapters/github/github.repoDiscovery.js +222 -0
  28. package/src/adapters/github/github.repoMirror.js +255 -0
  29. package/src/adapters/github/github.repoProxy.js +276 -0
  30. package/src/adapters/github/github.repoSurface.js +60 -0
  31. package/src/adapters/github/github.transportDiagnostics.js +68 -0
  32. package/src/adapters/local/local.adapter.case.mjs +72 -0
  33. package/src/adapters/local/local.adapter.js +188 -0
  34. package/src/adapters/registry.js +35 -0
  35. package/src/adapters/static/static.adapter.js +84 -0
  36. package/src/app/App.js +1 -0
  37. package/src/app/TiinexApp.jsx +822 -0
  38. package/src/app/appShell.views.jsx +58 -0
  39. package/src/app/artifactAuthoringCapability.js +49 -0
  40. package/src/app/boot/bootApp.js +19 -0
  41. package/src/app/boot/environment.js +1 -0
  42. package/src/app/canonicalAuthoringValues.js +4 -0
  43. package/src/app/canonicalCreationProductController.js +57 -0
  44. package/src/app/canonicalCreationProductSettlement.case.mjs +10 -0
  45. package/src/app/canonicalCreationProductSettlement.js +11 -0
  46. package/src/app/canonicalReferenceLocalCreateCommand.js +210 -0
  47. package/src/app/canonicalReferenceTargets.js +73 -0
  48. package/src/app/canonicalTransitionLocalCreateCommand.js +217 -0
  49. package/src/app/defaultWorkspaceStart.case.mjs +39 -0
  50. package/src/app/defaultWorkspaceStart.js +65 -0
  51. package/src/app/defaultWorkspaceStartCommand.js +55 -0
  52. package/src/app/durableLocalMutationPolicy.js +21 -0
  53. package/src/app/githubMaterializationSummary.js +69 -0
  54. package/src/app/githubProgress.js +25 -0
  55. package/src/app/githubSourceInput.js +47 -0
  56. package/src/app/githubSourceMaterializationCommand.js +97 -0
  57. package/src/app/githubSourceOperation.js +226 -0
  58. package/src/app/governanceDialogData.js +27 -0
  59. package/src/app/handoffPackageImportCommand.js +182 -0
  60. package/src/app/historyAuthority.js +53 -0
  61. package/src/app/initialWorkspaceBootstrapOperation.js +105 -0
  62. package/src/app/lineageCommand.js +118 -0
  63. package/src/app/lineageSourceRecovery.js +339 -0
  64. package/src/app/localDraftMutationCommand.js +174 -0
  65. package/src/app/localMaterialCommand.js +124 -0
  66. package/src/app/nodeGraphVerse.case.mjs +111 -0
  67. package/src/app/persistenceOwnership.js +92 -0
  68. package/src/app/productStateBoundary.js +7 -0
  69. package/src/app/providers/AppProviders.js +1 -0
  70. package/src/app/providers/LocaleProvider.js +1 -0
  71. package/src/app/providers/SchemaRegistryProvider.js +1 -0
  72. package/src/app/providers/WorkspaceProvider.js +1 -0
  73. package/src/app/publicTarget.js +251 -0
  74. package/src/app/publicTargetRestoreCommand.js +149 -0
  75. package/src/app/recordUi.cache.js +35 -0
  76. package/src/app/recordUi.js +11 -0
  77. package/src/app/routes/RouteSurface.js +1 -0
  78. package/src/app/routes/routes.js +1 -0
  79. package/src/app/runtimeState.js +54 -0
  80. package/src/app/schemaCurrentDeclaration.js +69 -0
  81. package/src/app/schemaFactoryLocalCreateCommand.js +101 -0
  82. package/src/app/schemaFactoryViewerProof.case.mjs +134 -0
  83. package/src/app/schemaFactoryViewerProof.js +20 -0
  84. package/src/app/schemaNavigationCommand.js +285 -0
  85. package/src/app/schemaNavigationMaterialization.js +171 -0
  86. package/src/app/schemaNavigationRuntimeCatalog.js +25 -0
  87. package/src/app/schemaNavigationState.js +66 -0
  88. package/src/app/schemaReadingContractQualification.js +91 -0
  89. package/src/app/schemaSourceRecovery.js +373 -0
  90. package/src/app/scrollPersistence.js +30 -0
  91. package/src/app/semanticOperationHistory.js +18 -0
  92. package/src/app/shareActionCommand.js +55 -0
  93. package/src/app/shareProjection.js +190 -0
  94. package/src/app/shell/AppShell.js +1 -0
  95. package/src/app/shell/Header.js +1 -0
  96. package/src/app/shell/Navigation.js +1 -0
  97. package/src/app/shell/SurfaceSwitcher.js +1 -0
  98. package/src/app/sourceTransportRefresh.js +176 -0
  99. package/src/app/startupOwnership.js +40 -0
  100. package/src/app/startupPresentation.case.mjs +34 -0
  101. package/src/app/startupPresentation.js +33 -0
  102. package/src/app/startupPresentation.views.jsx +21 -0
  103. package/src/app/startupRenderPhase.js +9 -0
  104. package/src/app/startupWorkspaceCommand.js +62 -0
  105. package/src/app/startupWorkspaceConfigApplication.js +49 -0
  106. package/src/app/statePersistenceScheduler.js +106 -0
  107. package/src/app/tiinexAppConfigPlan.js +108 -0
  108. package/src/app/tiinexAppConfigSource.js +349 -0
  109. package/src/app/tiinexAppStartupSource.js +79 -0
  110. package/src/app/tiinexHostedWorkspaceConventions.js +572 -0
  111. package/src/app/timePortalHistoricalRead.js +114 -0
  112. package/src/app/timePortalSnapshotResolution.js +53 -0
  113. package/src/app/urlMaterialCommand.js +24 -0
  114. package/src/app/useCanonicalPlacementSelectionOptions.js +9 -0
  115. package/src/app/useCanonicalReferenceSelectionOptions.js +8 -0
  116. package/src/app/useLocalMaterialIntake.js +68 -0
  117. package/src/app/useTimePortalProductController.jsx +111 -0
  118. package/src/app/useWorkspaceEntrypointIntake.js +77 -0
  119. package/src/app/useWorkspaceSelectionProductController.jsx +21 -0
  120. package/src/app/viewState.js +35 -0
  121. package/src/app/viewport.js +21 -0
  122. package/src/app/visualDormancy.js +286 -0
  123. package/src/app/workspaceContinuityNotices.js +32 -0
  124. package/src/app/workspaceDisplayCounts.js +9 -0
  125. package/src/app/workspaceEntrypointIntakeCommand.js +87 -0
  126. package/src/app/workspaceEntrypointProductRouting.case.mjs +20 -0
  127. package/src/app/workspaceExportCommand.js +21 -0
  128. package/src/app/workspaceExportDownload.js +23 -0
  129. package/src/app/workspaceExportExecutionCommand.js +10 -0
  130. package/src/app/workspaceGithubPublication.js +237 -0
  131. package/src/app/workspaceHandoffExport.js +56 -0
  132. package/src/app/workspaceHomeTarget.js +9 -0
  133. package/src/app/workspaceMulticolumn.js +113 -0
  134. package/src/app/workspaceNavigationParity.case.mjs +110 -0
  135. package/src/app/workspaceOpenProgress.js +26 -0
  136. package/src/app/workspacePlacementOptions.js +46 -0
  137. package/src/app/workspaceRecordActions.js +158 -0
  138. package/src/app/workspaceScopedInteraction.js +68 -0
  139. package/src/app/workspaceSelectionOriginContext.js +29 -0
  140. package/src/app/workspaceSelectionSession.js +54 -0
  141. package/src/app/workspaceSourceCloseCommand.js +25 -0
  142. package/src/app/workspaceSpineProductRouting.case.mjs +22 -0
  143. package/src/app/workspaceStartupTransition.js +32 -0
  144. package/src/app/workspaceWindow.js +85 -0
  145. package/src/artifacts/artifact.fixture.js +1 -0
  146. package/src/artifacts/artifact.identity.js +6 -0
  147. package/src/artifacts/artifact.identityAggregation.js +218 -0
  148. package/src/artifacts/artifact.model.js +2 -0
  149. package/src/artifacts/artifact.parse.case.mjs +196 -0
  150. package/src/artifacts/artifact.participantIndex.js +189 -0
  151. package/src/artifacts/fixtures/evidence.trace.md +50 -0
  152. package/src/artifacts/fixtures/topic.trace.md +33 -0
  153. package/src/artifacts/fixtures/unknown-schema.trace.md +25 -0
  154. package/src/audit/audit.findings.js +1 -0
  155. package/src/audit/audit.model.js +2 -0
  156. package/src/audit/audit.plan.js +13 -0
  157. package/src/audit/audit.report.js +12 -0
  158. package/src/audit/audit.severity.js +1 -0
  159. package/src/audit/audit.traverse.js +119 -0
  160. package/src/audit/integrity/auditIntegrity.checks.js +1 -0
  161. package/src/audit/integrity/auditIntegrity.compare.js +1 -0
  162. package/src/audit/lineage/auditLineage.load.js +1 -0
  163. package/src/audit/lineage/auditLineage.plan.js +1 -0
  164. package/src/audit/lineage/auditLineage.resolve.js +12 -0
  165. package/src/audit/sources/auditSources.boundaries.js +1 -0
  166. package/src/audit/sources/auditSources.checks.js +1 -0
  167. package/src/audit/validation/auditValidation.recheck.js +1 -0
  168. package/src/audit/validation/auditValidation.run.js +1 -0
  169. package/src/build.identity.js +15 -0
  170. package/src/commands/command.vocabulary.js +14 -0
  171. package/src/conformance/conformance.fixtures.js +151 -0
  172. package/src/conformance/conformance.run.js +238 -0
  173. package/src/data/applicationDataStore.js +23 -0
  174. package/src/data/companionAccess.js +35 -0
  175. package/src/diagnostics/events.js +1 -0
  176. package/src/diagnostics/invariant.js +1 -0
  177. package/src/diagnostics/schemaBindingChecks.js +1 -0
  178. package/src/diagnostics/schemaModuleChecks.js +1 -0
  179. package/src/diagnostics/sourceBoundaryChecks.js +5 -0
  180. package/src/diagnostics/sourceTransport.report.js +190 -0
  181. package/src/discovery/discovery.controls.js +7 -0
  182. package/src/export/export.plan.js +182 -0
  183. package/src/export/handoff.plan.js +50 -0
  184. package/src/export/package.builder.case.mjs +97 -0
  185. package/src/export/package.controlTopology.case.mjs +130 -0
  186. package/src/export/package.zip.case.mjs +33 -0
  187. package/src/graph/artifactGraph.model.js +344 -0
  188. package/src/graph/artifactGraph.project.js +139 -0
  189. package/src/graph/artifactGraph.worker.js +10 -0
  190. package/src/i18n/i18n.keys.js +1 -0
  191. package/src/i18n/i18n.provider.js +1 -0
  192. package/src/i18n/i18n.resolve.js +5 -0
  193. package/src/i18n/locales/en/common.json +4 -0
  194. package/src/i18n/locales/en/schemas/evidence.json +3 -0
  195. package/src/i18n/locales/en/schemas/presentation-surface.json +3 -0
  196. package/src/i18n/locales/en/schemas/preservation.json +3 -0
  197. package/src/i18n/locales/en/schemas/root.json +3 -0
  198. package/src/i18n/locales/en/schemas/schema-module.json +3 -0
  199. package/src/i18n/locales/en/schemas/topic.json +3 -0
  200. package/src/i18n/locales/en/surfaces/audit.json +3 -0
  201. package/src/i18n/locales/en/surfaces/create.json +3 -0
  202. package/src/i18n/locales/en/surfaces/detail.json +3 -0
  203. package/src/i18n/locales/en/surfaces/display-options.json +3 -0
  204. package/src/i18n/locales/en/surfaces/edit.json +3 -0
  205. package/src/i18n/locales/en/surfaces/feed.json +3 -0
  206. package/src/i18n/locales/en/surfaces/lineage.json +3 -0
  207. package/src/i18n/locales/en/surfaces/preview.json +3 -0
  208. package/src/i18n/locales/en/surfaces/share.json +3 -0
  209. package/src/i18n/locales/en/surfaces/source-settings.json +3 -0
  210. package/src/i18n/locales/en/surfaces/tree.json +3 -0
  211. package/src/i18n/locales/sv/common.json +4 -0
  212. package/src/i18n/locales/sv/schemas/evidence.json +3 -0
  213. package/src/i18n/locales/sv/schemas/presentation-surface.json +3 -0
  214. package/src/i18n/locales/sv/schemas/preservation.json +3 -0
  215. package/src/i18n/locales/sv/schemas/root.json +3 -0
  216. package/src/i18n/locales/sv/schemas/schema-module.json +3 -0
  217. package/src/i18n/locales/sv/schemas/topic.json +3 -0
  218. package/src/i18n/locales/sv/surfaces/audit.json +3 -0
  219. package/src/i18n/locales/sv/surfaces/create.json +3 -0
  220. package/src/i18n/locales/sv/surfaces/detail.json +3 -0
  221. package/src/i18n/locales/sv/surfaces/display-options.json +3 -0
  222. package/src/i18n/locales/sv/surfaces/edit.json +3 -0
  223. package/src/i18n/locales/sv/surfaces/feed.json +3 -0
  224. package/src/i18n/locales/sv/surfaces/lineage.json +3 -0
  225. package/src/i18n/locales/sv/surfaces/preview.json +3 -0
  226. package/src/i18n/locales/sv/surfaces/share.json +3 -0
  227. package/src/i18n/locales/sv/surfaces/source-settings.json +3 -0
  228. package/src/i18n/locales/sv/surfaces/tree.json +3 -0
  229. package/src/index.js +10 -0
  230. package/src/integrity/integrity.testFixture.js +9 -0
  231. package/src/interaction/interaction.spine.js +12 -0
  232. package/src/lineage/lineage.audit.js +1 -0
  233. package/src/lineage/lineage.edges.js +1 -0
  234. package/src/main.js +319 -0
  235. package/src/main.jsx +34 -0
  236. package/src/multiverse/multiverse.model.js +10 -0
  237. package/src/parity/poc.m1ParityScenarios.js +42 -0
  238. package/src/parity/poc.parityLedger.js +261 -0
  239. package/src/publication/publication.githubSocialContract.case.mjs +247 -0
  240. package/src/publication/publication.preflight.case.mjs +64 -0
  241. package/src/react/TiinexApplication.jsx +39 -0
  242. package/src/react/VerseHost.jsx +29 -0
  243. package/src/react/applicationDataContext.jsx +30 -0
  244. package/src/react.js +2 -0
  245. package/src/readers/modes/audit.reader.js +1 -0
  246. package/src/readers/modes/detail.reader.js +1 -0
  247. package/src/readers/modes/handover.reader.js +1 -0
  248. package/src/readers/modes/mobile.reader.js +1 -0
  249. package/src/readers/modes/print.reader.js +1 -0
  250. package/src/readers/modes/scan.reader.js +1 -0
  251. package/src/readers/reader.model.js +1 -0
  252. package/src/readers/reader.resolve.js +2 -0
  253. package/src/reingest/reingest.plan.case.mjs +65 -0
  254. package/src/runtime.js +54 -0
  255. package/src/schemas/README.md +99 -0
  256. package/src/schemas/coordination/handoff/tiinex.handoff.v1.schema.md +614 -0
  257. package/src/schemas/coordination/project/tiinex.project.v1.schema.md +311 -0
  258. package/src/schemas/core/decision/tiinex.decision.v1.schema.md +227 -0
  259. package/src/schemas/core/evidence/tiinex.evidence.v1.schema.md +318 -0
  260. package/src/schemas/core/feedback/tiinex.feedback.v1.schema.md +243 -0
  261. package/src/schemas/core/interpretation/.transitions/evidence-to-interpretation-transition-definition.trace.md +102 -0
  262. package/src/schemas/core/interpretation/tiinex.interpretation.v1.schema.md +308 -0
  263. package/src/schemas/core/preservation/tiinex.preservation.v1.schema.md +312 -0
  264. package/src/schemas/core/relation/.generation/reference-relation-generation-authority.trace.md +185 -0
  265. package/src/schemas/core/relation/.transitions/topic-references-task-transition-definition.trace.md +119 -0
  266. package/src/schemas/core/relation/tiinex.relation.v1.schema.md +240 -0
  267. package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.schema.md +550 -0
  268. package/src/schemas/core/signal/tiinex.signal.v1.schema.md +239 -0
  269. package/src/schemas/core/task/.transitions/create-task-transition-definition.trace.md +93 -0
  270. package/src/schemas/core/task/.transitions/topic-to-task-transition-definition.trace.md +102 -0
  271. package/src/schemas/core/task/task-semantic-package.trace.md +53 -0
  272. package/src/schemas/core/task/tiinex.task.v1-transitions.trace.md +33 -0
  273. package/src/schemas/core/task/tiinex.task.v1.authoring.js +65 -0
  274. package/src/schemas/core/task/tiinex.task.v1.schema.md +229 -0
  275. package/src/schemas/core/topic/.transitions/create-topic-transition-definition.trace.md +93 -0
  276. package/src/schemas/core/topic/tiinex.topic.v1-transitions.trace.md +33 -0
  277. package/src/schemas/core/topic/tiinex.topic.v1.schema.md +197 -0
  278. package/src/schemas/core/topic/topic-semantic-package.trace.md +53 -0
  279. package/src/schemas/discovery/finding/tiinex.discovery.finding.v1.schema.md +240 -0
  280. package/src/schemas/discovery/tiinex.discovery.v1.schema.md +294 -0
  281. package/src/schemas/manifest.json +367 -0
  282. package/src/schemas/origins.js +46 -0
  283. package/src/schemas/party/organization/tiinex.party.organization.v1.schema.md +290 -0
  284. package/src/schemas/party/role/tiinex.party.role.v1.schema.md +298 -0
  285. package/src/schemas/party/tiinex.party.v1.schema.js +14 -0
  286. package/src/schemas/party/tiinex.party.v1.schema.json +23 -0
  287. package/src/schemas/party/tiinex.party.v1.schema.md +311 -0
  288. package/src/schemas/party/tiinex.party.v1.schema.runtime.json +2033 -0
  289. package/src/schemas/party/tiinex.party.v1.schema.source.js +9 -0
  290. package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.schema.md +476 -0
  291. package/src/schemas/reduction/tiinex.reduction.v1.schema.md +248 -0
  292. package/src/schemas/schema/module/tiinex.schema.module.v1.schema.md +465 -0
  293. package/src/schemas/schema.companionContract.case.mjs +259 -0
  294. package/src/schemas/schema.factory.case.mjs +256 -0
  295. package/src/schemas/schema.factory.viewerProjection.js +183 -0
  296. package/src/schemas/schemaMarkdownCatalog.js +19 -0
  297. package/src/schemas/tiinex.root.v1.schema.md +865 -0
  298. package/src/schemas/validation/finding/tiinex.validation.finding.v1.schema.md +309 -0
  299. package/src/schemas/validation/method/tiinex.validation.method.v1.schema.md +280 -0
  300. package/src/schemas/validation/report/tiinex.validation.report.v1.schema.md +300 -0
  301. package/src/schemas/workspace/tiinex.workspace.v1.schema.md +486 -0
  302. package/src/schemas/workspace/workspace.add.views.jsx +327 -0
  303. package/src/schemas/workspace/workspace.audit.views.jsx +160 -0
  304. package/src/schemas/workspace/workspace.auditBadge.views.jsx +98 -0
  305. package/src/schemas/workspace/workspace.canonicalReferenceDialog.views.jsx +63 -0
  306. package/src/schemas/workspace/workspace.canonicalTaskDialog.views.jsx +169 -0
  307. package/src/schemas/workspace/workspace.cardActions.js +9 -0
  308. package/src/schemas/workspace/workspace.cards.views.jsx +146 -0
  309. package/src/schemas/workspace/workspace.chrome.views.jsx +299 -0
  310. package/src/schemas/workspace/workspace.continuationDialog.views.jsx +80 -0
  311. package/src/schemas/workspace/workspace.discovery.views.jsx +63 -0
  312. package/src/schemas/workspace/workspace.discoveryRenderWindow.js +56 -0
  313. package/src/schemas/workspace/workspace.displayOptions.views.jsx +114 -0
  314. package/src/schemas/workspace/workspace.entrypointChoice.views.jsx +30 -0
  315. package/src/schemas/workspace/workspace.exportDialog.controller.jsx +40 -0
  316. package/src/schemas/workspace/workspace.exportDialog.views.jsx +142 -0
  317. package/src/schemas/workspace/workspace.governance.views.jsx +45 -0
  318. package/src/schemas/workspace/workspace.graph.views.jsx +134 -0
  319. package/src/schemas/workspace/workspace.lineage.views.jsx +307 -0
  320. package/src/schemas/workspace/workspace.read.views.jsx +105 -0
  321. package/src/schemas/workspace/workspace.recordActionButton.views.jsx +35 -0
  322. package/src/schemas/workspace/workspace.recordDialogs.views.jsx +257 -0
  323. package/src/schemas/workspace/workspace.selection.views.jsx +14 -0
  324. package/src/schemas/workspace/workspace.sourceReceipt.views.jsx +40 -0
  325. package/src/schemas/workspace/workspace.timePortal.views.jsx +56 -0
  326. package/src/schemas/workspace/workspace.tree.views.jsx +107 -0
  327. package/src/schemas/workspace/workspace.viewFormatting.js +172 -0
  328. package/src/schemas/workspace/workspace.views.jsx +210 -0
  329. package/src/source-settings/sourceSettings.model.js +7 -0
  330. package/src/sources/draft/draft.source.js +1 -0
  331. package/src/sources/github/github.loader.js +204 -0
  332. package/src/sources/github/github.permalink.js +1 -0
  333. package/src/sources/github/github.source.js +1 -0
  334. package/src/sources/github/github.transport.case.mjs +237 -0
  335. package/src/sources/github/github.transport.js +472 -0
  336. package/src/sources/local/local.source.js +1 -0
  337. package/src/sources/source.assetReferences.js +109 -0
  338. package/src/sources/source.boundaries.js +24 -0
  339. package/src/sources/source.identity.js +56 -0
  340. package/src/sources/source.model.case.mjs +26 -0
  341. package/src/sources/source.model.js +56 -0
  342. package/src/sources/source.presenter.js +66 -0
  343. package/src/sources/source.resolve.js +11 -0
  344. package/src/sources/static/static.source.js +1 -0
  345. package/src/sources/transport.policy.case.mjs +39 -0
  346. package/src/sources/transport.policy.js +81 -0
  347. package/src/storage/storage.policy.js +79 -0
  348. package/src/styles/app.css +8699 -0
  349. package/src/styles/responsive.css +10 -0
  350. package/src/styles/theme.css +4 -0
  351. package/src/styles/tokens.css +30 -0
  352. package/src/surfaces/audit/AuditSurface.js +1 -0
  353. package/src/surfaces/audit/audit.model.js +1 -0
  354. package/src/surfaces/audit/audit.render.js +1 -0
  355. package/src/surfaces/contracts.js +45 -0
  356. package/src/surfaces/create/CreateSurface.js +1 -0
  357. package/src/surfaces/create/create.model.js +1 -0
  358. package/src/surfaces/create/create.render.js +1 -0
  359. package/src/surfaces/detail/DetailSurface.js +1 -0
  360. package/src/surfaces/detail/detail.model.js +1 -0
  361. package/src/surfaces/detail/detail.render.js +1 -0
  362. package/src/surfaces/display-options/DisplayOptionsSurface.js +1 -0
  363. package/src/surfaces/display-options/displayOptions.model.js +1 -0
  364. package/src/surfaces/display-options/displayOptions.render.js +1 -0
  365. package/src/surfaces/edit/EditSurface.js +1 -0
  366. package/src/surfaces/edit/edit.model.js +1 -0
  367. package/src/surfaces/edit/edit.render.js +1 -0
  368. package/src/surfaces/feed/FeedSurface.js +1 -0
  369. package/src/surfaces/feed/feed.model.js +1 -0
  370. package/src/surfaces/feed/feed.render.js +1 -0
  371. package/src/surfaces/lineage/LineageSurface.js +1 -0
  372. package/src/surfaces/lineage/lineage.model.js +1 -0
  373. package/src/surfaces/lineage/lineage.render.js +1 -0
  374. package/src/surfaces/preview/PreviewSurface.js +1 -0
  375. package/src/surfaces/preview/preview.model.js +1 -0
  376. package/src/surfaces/preview/preview.render.js +1 -0
  377. package/src/surfaces/registry.js +58 -0
  378. package/src/surfaces/share/ShareSurface.js +1 -0
  379. package/src/surfaces/share/share.model.js +1 -0
  380. package/src/surfaces/share/share.render.js +1 -0
  381. package/src/surfaces/source-settings/SourceSettingsSurface.js +1 -0
  382. package/src/surfaces/source-settings/sourceSettings.model.js +1 -0
  383. package/src/surfaces/source-settings/sourceSettings.render.js +1 -0
  384. package/src/surfaces/surfaceContext.js +1 -0
  385. package/src/surfaces/tree/TreeSurface.js +1 -0
  386. package/src/surfaces/tree/tree.model.js +1 -0
  387. package/src/surfaces/tree/tree.render.js +1 -0
  388. package/src/tooling/portable/adapters/cli/cli.common-output.case.mjs +153 -0
  389. package/src/tooling/portable/adapters/cli/cli.handoff-sibling-allocation.case.mjs +52 -0
  390. package/src/tooling/portable/adapters/cli/cli.run.case.mjs +372 -0
  391. package/src/tooling/portable/adapters/cli/cli.summaryProjection.case.mjs +46 -0
  392. package/src/tooling/portable/audit/audit.capability.case.mjs +45 -0
  393. package/src/tooling/portable/fixtures/legacy-artifacts/collaboration/dogfood/001-tiinex-development-dogfood-collaboration-model.trace.fixture.txt +37 -0
  394. package/src/tooling/portable/fixtures/legacy-artifacts/handoff/tooling/001-v480-tooling-workflow-schema-enablement-handoff.trace.fixture.txt +108 -0
  395. package/src/tooling/portable/fixtures/legacy-artifacts/handoff/tooling/002-v481-tooling-recipient-relative-handoff-material-closure-planner-foundation-handoff.trace.fixture.txt +130 -0
  396. package/src/tooling/portable/fixtures/legacy-artifacts/loom/role/001-loom-role.trace.fixture.txt +61 -0
  397. package/src/tooling/portable/fixtures/legacy-artifacts/sigma/role/001-1-sigma-role.trace.fixture.txt +61 -0
  398. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-1-1-1-1-1-site-tooling-v474-loaded-parent-identity-evidence-closure-result.trace.fixture.txt +48 -0
  399. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-1-1-1-1-site-tooling-v474-loaded-parent-identity-evidence-closure.trace.fixture.txt +48 -0
  400. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-1-1-1-site-tooling-v473-portable-parent-authority-coherence-metadata-fidelity-closure-result.trace.fixture.txt +48 -0
  401. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-1-1-site-tooling-v473-portable-parent-authority-coherence-metadata-fidelity-closure.trace.fixture.txt +48 -0
  402. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-1-site-tooling-v472-portable-exact-authoring-fidelity-closure-result.trace.fixture.txt +48 -0
  403. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-1-site-tooling-v472-portable-exact-authoring-fidelity-closure.trace.fixture.txt +48 -0
  404. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-1-site-tooling-v471-portable-lineage-authoring-closure-result.trace.fixture.txt +48 -0
  405. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/001-site-tooling-v471-portable-lineage-authoring-closure.trace.fixture.txt +39 -0
  406. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/002-1-v475-canonical-artifact-envelope-reference-integrity-validation.trace.fixture.txt +43 -0
  407. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/003-1-v476-canonical-authority-binding-integrity-method-lineage-alloca.trace.fixture.txt +42 -0
  408. package/src/tooling/portable/fixtures/legacy-artifacts/tooling/dogfood/027-handoff-package-workspace-archive-and-control-plane-minimality-audit.trace.fixture.txt +56 -0
  409. package/src/tooling/portable/fixtures/legacyArtifactFixtures.mjs +34 -0
  410. package/src/tooling/portable/grounding/grounding.capsule.case.mjs +65 -0
  411. package/src/tooling/portable/grounding/grounding.readiness.case.mjs +543 -0
  412. package/src/tooling/portable/grounding/grounding.semanticIntegration.case.mjs +131 -0
  413. package/src/tooling/portable/handoff/boundedWorkspaceRepresentation.case.mjs +103 -0
  414. package/src/tooling/portable/handoff/carrierLineage.fixedWidth.case.mjs +97 -0
  415. package/src/tooling/portable/handoff/coldStartQualification.case.mjs +293 -0
  416. package/src/tooling/portable/handoff/fixtures/027-invalid-audit-result.fixture.txt +192 -0
  417. package/src/tooling/portable/handoff/fixtures/027-invalid-return-handoff.fixture.txt +92 -0
  418. package/src/tooling/portable/handoff/fixtures/cold-start-qualification.v1.examples.json +60 -0
  419. package/src/tooling/portable/handoff/handoff.manufacture.case.mjs +293 -0
  420. package/src/tooling/portable/handoff/materialClosure.case.mjs +727 -0
  421. package/src/tooling/portable/handoff/multiRootManufacture.case.mjs +615 -0
  422. package/src/tooling/portable/handoff/operatorBridgeCore.case.mjs +205 -0
  423. package/src/tooling/portable/handoff/workspaceLandingPlan.case.mjs +143 -0
  424. package/src/tooling/portable/input/node.input.case.mjs +293 -0
  425. package/src/tooling/portable/lifecycle/lifecycle.readiness.case.mjs +179 -0
  426. package/src/tooling/portable/lineage/fixtures/lineage.integrity.repair-projection.v1.examples.json +605 -0
  427. package/src/tooling/portable/lineage/lineage.integrity.shared-capability.case.mjs +37 -0
  428. package/src/tooling/portable/lineage/publicationProviderReceipt.fixture.mjs +50 -0
  429. package/src/tooling/portable/package/fixtures/reference-relation-generation-authority.trace.md +84 -0
  430. package/src/tooling/portable/package/fixtures/tiinex.root.v1.package-authority.contract-fixture.md +64 -0
  431. package/src/tooling/portable/package/fixtures/tiinex.schema.generation.v1.generation-binding.contract-fixture.md +140 -0
  432. package/src/tooling/portable/package/fixtures/tiinex.schema.transition.companion.v1.contract-fixture.md +73 -0
  433. package/src/tooling/portable/package/fixtures/tiinex.semantic.package.v1.contract-fixture.md +147 -0
  434. package/src/tooling/portable/package/fixtures/tiinex.transition.definition.v1.package-contract-fixture.md +77 -0
  435. package/src/tooling/portable/providers/schema.providers.genericity.case.mjs +31 -0
  436. package/src/tooling/portable/reduction/reduction.preflight.case.mjs +298 -0
  437. package/src/tooling/portable/schema/fixtures/evidence-preservation-body.inheritance-record-fixture.md +65 -0
  438. package/src/tooling/portable/schema/fixtures/tiinex.portal.time.v1.contract-fixture.md +294 -0
  439. package/src/tooling/portable/schema/fixtures/tiinex.root.v1.contract-fixture.md +584 -0
  440. package/src/tooling/portable/schema/fixtures/tiinex.root.v1.machine-shape.contract-fixture.md +44 -0
  441. package/src/tooling/portable/schema/fixtures/tiinex.root.v1.ordinary-target.contract-fixture.md +630 -0
  442. package/src/tooling/portable/schema/fixtures/tiinex.schema.contract.v1.repeated-record.contract-fixture.md +69 -0
  443. package/src/tooling/portable/schema/fixtures/tiinex.schema.generation.v1.repeated-record.contract-fixture.md +98 -0
  444. package/src/tooling/portable/schema/fixtures/tiinex.schema.inheritance.v1.repeated-record.contract-fixture.md +58 -0
  445. package/src/tooling/portable/schema/fixtures/tiinex.task.v1.contract-fixture.md +165 -0
  446. package/src/tooling/portable/schema/fixtures/tiinex.transition.definition.v1.contract-fixture.md +744 -0
  447. package/src/tooling/portable/schema/fixtures/tiinex.transition.definition.v1.field-domain.contract-fixture.md +319 -0
  448. package/src/transitions/canonical-schema-cache/053d46ce082d4ec261b82abc44ecca403d61e240/tiinex.relation.v1.schema.md +240 -0
  449. package/src/transitions/canonical-schema-cache/053d46ce082d4ec261b82abc44ecca403d61e240/tiinex.schema.contract.v1.schema.md +391 -0
  450. package/src/transitions/canonical-schema-cache/053d46ce082d4ec261b82abc44ecca403d61e240/tiinex.schema.generation.v1.schema.md +379 -0
  451. package/src/transitions/canonical-schema-cache/053d46ce082d4ec261b82abc44ecca403d61e240/tiinex.schema.transition.companion.v1.schema.md +265 -0
  452. package/src/transitions/canonical-schema-cache/053d46ce082d4ec261b82abc44ecca403d61e240/tiinex.semantic.package.v1.schema.md +402 -0
  453. package/src/transitions/canonical-schema-cache/52ecdea0a75893882ce282214d155f70e1309c2a/tiinex.topic.v1.schema.md +197 -0
  454. package/src/transitions/canonical-schema-cache/d69b8ff55a56b8cb9282b8684db6a938a4435b94/tiinex.root.v1.schema.md +797 -0
  455. package/src/transitions/canonical-schema-cache/d69b8ff55a56b8cb9282b8684db6a938a4435b94/tiinex.transition.definition.v1.schema.md +1062 -0
  456. package/src/transitions/canonicalTransition.packageContracts.js +22 -0
  457. package/src/transitions/canonicalTransition.productDefaults.js +105 -0
  458. package/src/transitions/canonicalTransition.schemaCache.case.mjs +45 -0
  459. package/src/transitions/canonicalTransition.schemaCache.js +81 -0
  460. package/src/transitions/canonicalTransition.semanticPackage.js +146 -0
  461. package/src/transitions/record.transitions.case.mjs +88 -0
  462. package/src/transitions/transition.authorityRepresentation.js +55 -0
  463. package/src/transitions/transition.availabilityPlanner.js +376 -0
  464. package/src/transitions/transition.availabilitySemantics.js +150 -0
  465. package/src/transitions/transition.definitionReadProjection.js +107 -0
  466. package/src/transitions/transition.definitionRegistry.js +355 -0
  467. package/src/transitions/transition.definitionRegistryAggregation.js +21 -0
  468. package/src/transitions/transition.definitions.js +46 -0
  469. package/src/transitions/transition.explicitGenerationPlanner.js +58 -0
  470. package/src/transitions/transition.generationInputPlanner.js +19 -0
  471. package/src/transitions/transition.interpretationMaterializer.js +2 -0
  472. package/src/transitions/transition.invocationBindingPacket.js +52 -0
  473. package/src/transitions/transition.invocationBindingPlanner.js +467 -0
  474. package/src/transitions/transition.legacyShorthand.js +133 -0
  475. package/src/transitions/transition.localArtifactMaterializers.js +16 -0
  476. package/src/transitions/transition.localCreateCapability.js +111 -0
  477. package/src/transitions/transition.outputMaterializationPlanner.js +336 -0
  478. package/src/transitions/transition.parentReference.js +90 -0
  479. package/src/transitions/transition.presentation.js +43 -0
  480. package/src/transitions/transition.productPreparation.js +377 -0
  481. package/src/transitions/transition.productPresentation.browser.js +28 -0
  482. package/src/transitions/transition.productPresentation.js +55 -0
  483. package/src/transitions/transition.referenceCreateCapability.js +119 -0
  484. package/src/transitions/transition.referenceTarget.js +50 -0
  485. package/src/transitions/transition.relationMaterializer.js +2 -0
  486. package/src/transitions/transition.resultSemantics.js +453 -0
  487. package/src/transitions/transition.taskMaterializer.js +2 -0
  488. package/src/transitions/transition.topicMaterializer.js +2 -0
  489. package/src/transitions/transition.validate.case.mjs +58 -0
  490. package/src/ui/cards/ArtifactCard.js +1 -0
  491. package/src/ui/cards/SchemaCard.js +1 -0
  492. package/src/ui/cards/SourceCard.js +1 -0
  493. package/src/ui/dialog.presenter.js +24 -0
  494. package/src/ui/feedback/DegradedNotice.js +1 -0
  495. package/src/ui/feedback/EmptyState.js +1 -0
  496. package/src/ui/feedback/ValidationNotice.js +1 -0
  497. package/src/ui/forms/FormRenderer.js +1 -0
  498. package/src/ui/forms/fields/MarkdownField.js +1 -0
  499. package/src/ui/forms/fields/SelectField.js +1 -0
  500. package/src/ui/forms/fields/SourcePickerField.js +1 -0
  501. package/src/ui/forms/fields/TextField.js +1 -0
  502. package/src/ui/icon.paths.js +37 -0
  503. package/src/ui/layout/Panel.js +1 -0
  504. package/src/ui/layout/ResponsiveFrame.js +1 -0
  505. package/src/ui/layout/SplitView.js +1 -0
  506. package/src/ui/layout/Stack.js +1 -0
  507. package/src/ui/panels/DetailPanel.js +1 -0
  508. package/src/ui/panels/LineagePanel.js +1 -0
  509. package/src/ui/panels/SourcePanel.js +1 -0
  510. package/src/ui/primitives/Badge.js +1 -0
  511. package/src/ui/primitives/Badge.jsx +5 -0
  512. package/src/ui/primitives/Button.js +1 -0
  513. package/src/ui/primitives/Button.jsx +12 -0
  514. package/src/ui/primitives/Card.js +1 -0
  515. package/src/ui/primitives/Field.js +1 -0
  516. package/src/ui/primitives/Field.jsx +21 -0
  517. package/src/ui/primitives/Icon.jsx +90 -0
  518. package/src/ui/primitives/Modal.jsx +27 -0
  519. package/src/validation/i18n.js +37 -0
  520. package/src/validation/validateArtifact.case.mjs +41 -0
  521. package/src/verses/column/ColumnVerse.js +1 -0
  522. package/src/verses/column/column.model.js +6 -0
  523. package/src/verses/column/column.project.js +7 -0
  524. package/src/verses/context.js +26 -0
  525. package/src/verses/contracts.js +1 -0
  526. package/src/verses/hostRegistry.js +47 -0
  527. package/src/verses/registry.js +22 -0
  528. package/src/verses/universe.model.js +8 -0
  529. package/src/verses/universe.presenter.js +8 -0
  530. package/src/verses/universe.project.js +12 -0
  531. package/src/viewer.js +34 -0
  532. package/src/workspace.model.js +5 -0
  533. package/src/workspaces/workspace.actions.js +1 -0
  534. package/src/workspaces/workspace.artifactActions.js +56 -0
  535. package/src/workspaces/workspace.auditView.js +153 -0
  536. package/src/workspaces/workspace.candidates.js +149 -0
  537. package/src/workspaces/workspace.config.js +153 -0
  538. package/src/workspaces/workspace.configuredSource.js +68 -0
  539. package/src/workspaces/workspace.discoveryProgress.js +34 -0
  540. package/src/workspaces/workspace.discoveryView.js +386 -0
  541. package/src/workspaces/workspace.displayFilters.js +63 -0
  542. package/src/workspaces/workspace.displayOptions.js +58 -0
  543. package/src/workspaces/workspace.emptyStateCopy.js +24 -0
  544. package/src/workspaces/workspace.entrypointLifecycle.js +131 -0
  545. package/src/workspaces/workspace.entrypointViewIntent.js +83 -0
  546. package/src/workspaces/workspace.entrypoints.js +157 -0
  547. package/src/workspaces/workspace.feedSort.js +152 -0
  548. package/src/workspaces/workspace.import.js +212 -0
  549. package/src/workspaces/workspace.importConflicts.js +200 -0
  550. package/src/workspaces/workspace.importLifecycle.case.mjs +103 -0
  551. package/src/workspaces/workspace.lifecycle.case.mjs +353 -0
  552. package/src/workspaces/workspace.lifecycle.js +357 -0
  553. package/src/workspaces/workspace.lineageView.js +244 -0
  554. package/src/workspaces/workspace.localSourceLifecycle.js +91 -0
  555. package/src/workspaces/workspace.materialLedger.js +110 -0
  556. package/src/workspaces/workspace.materialReconciliation.case.mjs +164 -0
  557. package/src/workspaces/workspace.materialReconciliation.js +390 -0
  558. package/src/workspaces/workspace.memberIdentity.js +140 -0
  559. package/src/workspaces/workspace.model.js +2 -0
  560. package/src/workspaces/workspace.navigation.js +20 -0
  561. package/src/workspaces/workspace.openSemantics.js +33 -0
  562. package/src/workspaces/workspace.pathTree.js +132 -0
  563. package/src/workspaces/workspace.persistence.case.mjs +271 -0
  564. package/src/workspaces/workspace.persistence.js +469 -0
  565. package/src/workspaces/workspace.persistenceCache.js +41 -0
  566. package/src/workspaces/workspace.persistenceClear.js +45 -0
  567. package/src/workspaces/workspace.persistencePresentation.js +93 -0
  568. package/src/workspaces/workspace.persistenceRecovery.js +147 -0
  569. package/src/workspaces/workspace.persistenceRouteCache.js +82 -0
  570. package/src/workspaces/workspace.publicationReceipts.case.mjs +36 -0
  571. package/src/workspaces/workspace.publicationReceipts.js +56 -0
  572. package/src/workspaces/workspace.recoverabilityView.js +264 -0
  573. package/src/workspaces/workspace.route.js +432 -0
  574. package/src/workspaces/workspace.runtimeCanonical.js +18 -0
  575. package/src/workspaces/workspace.sourceMaterial.js +71 -0
  576. package/src/workspaces/workspace.sourceRecordPath.js +5 -0
  577. package/src/workspaces/workspace.sourceRecords.js +75 -0
  578. package/src/workspaces/workspace.store.js +3 -0
  579. package/src/workspaces/workspace.summary.js +116 -0
  580. package/src/workspaces/workspace.timePortal.js +137 -0
@@ -0,0 +1,299 @@
1
+ import React from 'react';
2
+ import { Button } from '../../ui/primitives/Button.jsx';
3
+ import { Icon } from '../../ui/primitives/Icon.jsx';
4
+ import { workspaceEmptyStateCopy } from '../../workspaces/workspace.emptyStateCopy.js';
5
+ import { displayOptionsActiveConstraintCount } from '../../workspaces/workspace.displayOptions.js';
6
+ import { recordSourceClass } from '../../workspaces/workspace.displayFilters.js';
7
+ import { shouldShowWorkspaceSummary } from '../../workspaces/workspace.summary.js';
8
+ import { isLocalSessionMaterial } from '../../workspaces/workspace.localSourceLifecycle.js';
9
+ import { normalizeGithubTransportTier } from '../../sources/github/github.transport.js';
10
+ import { isOriginReferenceSource } from '@tiinex/core/sources/origin.references.js';
11
+ import { sourceTransportBadgesForSource } from '../../app/sourceTransportRefresh.js';
12
+ import { buildGovernanceBoundaryForSource, GOVERNANCE_BOUNDARY_SCHEMA_ID } from '@tiinex/core/governance/governance.boundary.js';
13
+ import { SourceReceiptDetails } from './workspace.sourceReceipt.views.jsx';
14
+
15
+ export function WorkspaceBoundaryKicker({ workspace = {} }) {
16
+ const records = Array.isArray(workspace.records) ? workspace.records : [];
17
+ const assets = Array.isArray(workspace.assets) ? workspace.assets : [];
18
+ const localCount = records.filter((record) => recordSourceClass(record) === 'local').length
19
+ + records.filter((record) => record?.materialReconciliation?.status === 'checksum-match' && record.materialReconciliation.localSnapshot).length
20
+ + assets.filter((asset) => isLocalSessionMaterial(asset)).length;
21
+ const sourceCount = records.filter((record) => recordSourceClass(record) === 'source-backed').length;
22
+ if (!localCount && !sourceCount) return null;
23
+ const label = sourceCount && localCount ? 'mixed' : sourceCount ? 'source-backed' : 'local';
24
+ const title = sourceCount && localCount
25
+ ? 'Workspace contains both browser-local and explicit source-backed material.'
26
+ : sourceCount
27
+ ? 'Workspace is currently showing explicit source-backed material.'
28
+ : 'Browser-local session material; source provenance is not inferred.';
29
+ return <span className={`tx-window-kicker tx-boundary-workspace-kicker tx-${label}`} title={title}><Icon name={sourceCount ? 'source' : 'workspace'} /><span>{label}</span></span>;
30
+ }
31
+
32
+ export function SourceStrip({ workspace, boundary, onCloseSource, onOpenAddDialog, onSourceTransportRefresh, onOpenGovernance, readOnly = false }) {
33
+ const sources = (Array.isArray(workspace.sources) ? workspace.sources : []);
34
+ if (!sources.length) return null;
35
+ return (
36
+ <div className="tx-source-strip workspace-source-strip tx-compact-source-strip" aria-label="Workspace sources">
37
+ <div className="tx-source-list">
38
+ {sources.map((source) => {
39
+ const closeable = Boolean(source.closeable);
40
+ const kind = String(source.adapterId || source.sourceKind || source.kind || '').toLowerCase();
41
+ const isLocal = kind.includes('local') || source.id === 'local';
42
+ const isOriginRecovery = isOriginReferenceSource(source) || source.recoveryOnly === true;
43
+ const isTargetedFileRecovery = source.sourceKind === 'github.file' && source.loadable === false;
44
+ const transport = isOriginRecovery ? originRecoveryTransportSummary(source) : sourceTransportSummary(source);
45
+ const sourceLabel = source.label || source.id || 'Source';
46
+ const addTitle = isLocal ? 'Add local files, archive imports, or workspace artifacts' : 'Open source controls for this source: choose repo files, explicit files, or issue snapshots';
47
+ const addLabel = isLocal ? 'Add' : 'Discover';
48
+ const canLoadFromSource = closeable && !isOriginRecovery && source.loadable !== false;
49
+ const closeTitle = isLocal ? (source.closeLabel || 'Clear local/session material') : isOriginRecovery ? `Dismiss recovery origin ${sourceLabel}` : `Close ${sourceLabel}`;
50
+ const closeAria = isLocal ? 'Clear Local source material from this browser session' : isOriginRecovery ? `Dismiss recovery-only origin ${sourceLabel}` : `Close ${sourceLabel}`;
51
+ return (
52
+ <span
53
+ key={source.id || source.label}
54
+ className={`tx-source-pill ${closeable ? 'tx-source-pill-closeable' : ''} ${isOriginRecovery ? 'tx-source-origin-recovery' : kind.includes('github') ? 'source-github' : 'source-local'}`}
55
+ title={source.boundary || boundary || ''}
56
+ data-discovery-state={source.discoveryState || undefined}
57
+ data-source-kind={kind || undefined}
58
+ data-source-role={isOriginRecovery ? 'origin-recovery' : isLocal ? 'local-session' : isTargetedFileRecovery ? 'targeted-provenance' : 'configured-source'}
59
+ >
60
+ <Icon name={kind.includes('github') ? 'source' : 'workspace'} />
61
+ <strong>{sourceLabel}</strong>
62
+ <small title={isOriginRecovery ? 'Explicit origin references recovered from imported/local artifacts, not loaded source records.' : undefined}>{sourceCountText(source, isOriginRecovery)}</small>
63
+ {isOriginRecovery ? <span className="tx-source-role-badge" title="Recovery-only origin: imported records remain local/session authority.">recovery only</span> : null}
64
+ {transport.badges?.length ? <span className={`tx-source-transport-group ${transport.mixed ? 'is-mixed' : ''}`} aria-label={transport.mixed ? 'Surface transports' : 'Source transport'}>
65
+ {transport.badges.map((badge) => badge.refreshable ? (
66
+ <button key={badge.key} type="button" className={`tx-source-transport tx-source-transport-button ${badge.className}`} title={badge.title} aria-label={badge.title} onClick={() => onSourceTransportRefresh?.(source.id, badge.refreshTier || badge.tier, badge.surfaceKeys || [])}>{badge.label}</button>
67
+ ) : (
68
+ <span key={badge.key} className={`tx-source-transport ${badge.className}`} title={badge.title}>{badge.label}</span>
69
+ ))}
70
+ </span> : null}
71
+ <SourceGovernanceBadge source={source} onOpenGovernance={onOpenGovernance} />
72
+ {canLoadFromSource && !readOnly ? <button type="button" className="tx-source-load" aria-label={`${addLabel} material for ${sourceLabel}`} title={addTitle} onClick={() => onOpenAddDialog?.(isLocal ? '' : source.id)}><Icon name="add" /><span>{addLabel}</span></button> : null}
73
+ {closeable && !readOnly ? <button type="button" className="tx-source-close" aria-label={closeAria} title={closeTitle} onClick={() => onCloseSource?.(source.id)}><Icon name="close" /></button> : null}
74
+ </span>
75
+ );
76
+ })}
77
+ </div>
78
+ </div>
79
+ );
80
+ }
81
+
82
+
83
+ function sourceCountText(source = {}, originRecovery = false) {
84
+ if (!originRecovery) return Number(source.count || 0);
85
+ const refs = Number(source.originReferenceCount || 0);
86
+ return refs ? `${refs} ref${refs === 1 ? '' : 's'}` : '0 loaded';
87
+ }
88
+
89
+ function originRecoveryTransportSummary(source = {}) {
90
+ return {
91
+ badges: [{
92
+ key: 'origin-recovery',
93
+ label: 'recovery',
94
+ tier: 'direct',
95
+ refreshTier: '',
96
+ refreshable: false,
97
+ title: source.boundary || 'Explicit origin metadata is available for user-invoked lineage recovery; this is not a configured source and does not make imported material source-backed.',
98
+ className: 'tx-transport-tier-direct tx-transport-origin-recovery'
99
+ }],
100
+ mixed: false
101
+ };
102
+ }
103
+
104
+ function SourceGovernanceBadge({ source = {}, onOpenGovernance }) {
105
+ if (isOriginReferenceSource(source) || source.recoveryOnly === true) return null;
106
+ const sourceKind = String(source.adapterId || source.sourceKind || source.kind || '').toLowerCase();
107
+ const repo = String(source.repo || source.repository || source.config?.repo || '').trim();
108
+ const explicitBoundary = source.governanceBoundary && typeof source.governanceBoundary === 'object' && source.governanceBoundary.schema === GOVERNANCE_BOUNDARY_SCHEMA_ID
109
+ ? source.governanceBoundary
110
+ : null;
111
+ const boundary = explicitBoundary || (sourceKind.includes('github') && repo
112
+ ? buildGovernanceBoundaryForSource(source, { rootChecked: false, discoveredFrom: 'source-strip-unchecked' })
113
+ : null);
114
+ if (!boundary || typeof boundary !== 'object') return null;
115
+ const status = String(boundary.status || '').trim();
116
+ if (!status || status === 'local') return null;
117
+ const policyKind = boundary.policy?.kind || '';
118
+ const label = status === 'found'
119
+ ? 'lineage policy'
120
+ : status === 'origin-fallback'
121
+ ? (policyKind || 'license')
122
+ : status === 'missing'
123
+ ? 'no policy'
124
+ : 'policy ?';
125
+ const title = `${boundary.note || boundary.boundary || 'Source governance boundary'} · Click to read governance context.`;
126
+ const className = `tx-source-governance tx-governance-${status}`;
127
+ if (typeof onOpenGovernance === 'function') {
128
+ return <button type="button" className={className} title={title} aria-label={`Open governance boundary: ${label}`} onClick={() => onOpenGovernance(source.id)}><Icon name={status === 'missing' ? 'warning' : 'audit'} /><span>{label}</span></button>;
129
+ }
130
+ return <span className={className} title={title} aria-label={`Governance boundary: ${label}`}><Icon name={status === 'missing' ? 'warning' : 'audit'} /><span>{label}</span></span>;
131
+ }
132
+
133
+ function sourceTransportSummary(source = {}) {
134
+ const plan = String(source.transportLabel || source.transport || 'cache → mirror → proxy → direct').replace(/\s*→\s*/g, ' → ');
135
+ const pendingTier = normalizeGithubTransportTier(source.transportOutcome?.pendingTier || '');
136
+ const badges = sourceTransportBadgesForSource(source).map((badge) => {
137
+ const pending = Boolean(badge.pendingTier || (pendingTier && (!Array.isArray(source.transportOutcome?.pendingSurfaces) || source.transportOutcome.pendingSurfaces.includes(badge.key))));
138
+ const tier = normalizeGithubTransportTier(badge.pendingTier || badge.tier || pendingTier || '') || 'cache';
139
+ const refreshTier = tier;
140
+ const status = String(badge.status || '').toLowerCase();
141
+ const titleParts = [
142
+ badge.mixed ? `${badge.label}: ${tier}` : `Source transport: ${tier}`,
143
+ badge.surfaceKeys?.length && badge.key !== 'all' ? `Surface: ${badge.surfaceKeys.join(', ')}` : '',
144
+ pending ? `Trying ${tier} now` : '',
145
+ Number(badge.loaded || 0) ? `${Number(badge.loaded || 0)} loaded` : '',
146
+ badge.unavailable ? 'Unavailable/skipped' : '',
147
+ badge.failed ? 'Failed' : '',
148
+ `Configured plan: ${plan}`,
149
+ badge.refreshable ? `Click: try ${badge.nextTier}` : 'Direct is the last fallback tier.'
150
+ ].filter(Boolean);
151
+ const text = badge.mixed && badge.shortLabel ? `${badge.shortLabel} ${tier}${pending ? '…' : ''}` : `${tier}${pending ? '…' : ''}`;
152
+ return Object.assign({}, badge, {
153
+ label: text,
154
+ tier,
155
+ refreshTier,
156
+ refreshable: Boolean(badge.refreshable && !pending),
157
+ title: titleParts.join(' · '),
158
+ className: [
159
+ `tx-transport-tier-${tier}`,
160
+ badge.mixed ? 'is-transport-surface' : '',
161
+ pending ? 'is-transport-pending' : '',
162
+ status === 'failed' || status === 'unavailable' || badge.unavailable || badge.failed ? 'is-transport-failed' : '',
163
+ status === 'ok' || Number(badge.loaded || 0) ? 'is-transport-ok' : ''
164
+ ].filter(Boolean).join(' ')
165
+ });
166
+ });
167
+ return { badges, mixed: badges.length > 1 };
168
+ }
169
+
170
+ export function WorkspaceMaterialSummary({ summary }) {
171
+ if (!shouldShowWorkspaceSummary(summary)) return null;
172
+ const counts = summary.counts || {};
173
+ const latest = summary.latestImport;
174
+ const latestDiagnostics = latest?.diagnostics || {};
175
+ const latestLedger = latestDiagnostics.materialLedgerReceipt || latestDiagnostics.materialLedger || null;
176
+ const ledgerExplainsVisibility = Boolean(latestLedger && (Number(latestLedger.hiddenRecords || 0) || Number(latestLedger.groupedRecords || 0) || Number(latestLedger.sourceWorkspaceArtifacts || latestLedger.legacySourceWorkspaceArtifacts || latestLedger.sourceWorkspaceArtifacts || 0)));
177
+ const noisyLatest = latest && (latest.ok === false || counts.errors || counts.warnings || counts.previewOmitted || ledgerExplainsVisibility);
178
+ return (
179
+ <section className="tx-workspace-material-summary" aria-label="Workspace material summary">
180
+ <div className="tx-material-summary-counts">
181
+ <span title="Loaded records before Display options"><Icon name="manualFiles" /><strong>{counts.records || 0}</strong><small>loaded records</small></span>
182
+ <span><Icon name="asset" /><strong>{counts.assets || 0}</strong><small>assets</small></span>
183
+ <span><Icon name="workspace" /><strong>{counts.workspaceArtifacts || 0}</strong><small>workspaces</small></span>
184
+ {counts.sourceBackedRecords ? <span><Icon name="source" /><strong>{counts.sourceBackedRecords}</strong><small>source-backed</small></span> : null}
185
+ {counts.hiddenRecords ? <span title="Loaded records not visible in the current feed/tree view. Grouped records are source+local material shown as one canonical card; display-hidden records are filtered/supporting/parent material still available for lineage."><Icon name="filters" /><strong>{counts.visibleRecords || 0}/{counts.records || 0}</strong><small>visible</small></span> : null}
186
+ {counts.groupedRecords ? <span title="Records grouped under a canonical source/local artifact cluster, not lost."><Icon name="check" /><strong>{counts.groupedRecords}</strong><small>grouped</small></span> : null}
187
+ {counts.hiddenByDisplayRecords ? <span title="Records hidden by Display options/search/leaf membership; still available for lineage and recovery."><Icon name="filters" /><strong>{counts.hiddenByDisplayRecords}</strong><small>display-hidden</small></span> : null}
188
+ {counts.lineageUsableRecords && counts.lineageUsableRecords !== counts.visibleRecords ? <span title="Records available to lineage/read-models, including material hidden by current display filters."><Icon name="lineage" /><strong>{counts.lineageUsableRecords}</strong><small>lineage usable</small></span> : null}
189
+ {counts.materialChecksumMatches ? <span title="Verified local/source equivalents were reconciled to one canonical source-backed artifact; redundant local duplicates are pruned instead of hidden for later resurrection."><Icon name="check" /><strong>{counts.materialChecksumMatches}</strong><small>deduped matches</small></span> : null}
190
+ {counts.localAssets ? <span title="Browser-local assets are locally available only; they are not source or public truth."><Icon name="asset" /><strong>{counts.localAssets}</strong><small>local assets</small></span> : null}
191
+ {counts.materialChecksumMismatches ? <span title="Imported/local material and source material share identity but checksum differs."><Icon name="warning" /><strong>{counts.materialChecksumMismatches}</strong><small>mismatch</small></span> : null}
192
+ {counts.recoveryOriginSources ? <span title="Explicit origins preserved from imported/local artifacts; recovery-only, not source-backed authority."><Icon name="source" /><strong>{counts.recoveryOriginSources}</strong><small>recovery origins</small></span> : null}
193
+ </div>
194
+ {noisyLatest ? (
195
+ <div className={`tx-material-summary-import ${latest.ok ? 'tx-import-ok' : 'tx-import-degraded'}`} title={latest.message}>
196
+ <Icon name={latest.ok ? 'check' : 'warning'} />
197
+ <span>{latest.message}</span>
198
+ {(counts.warnings || counts.errors || counts.previewOmitted) ? (
199
+ <small>{counts.errors || 0} errors · {counts.warnings || 0} warnings · {counts.previewOmitted || 0} previews omitted</small>
200
+ ) : null}
201
+ <SourceReceiptDetails latest={latest} />
202
+ </div>
203
+ ) : null}
204
+ </section>
205
+ );
206
+ }
207
+
208
+ export function ProgressStrip({ workspace }) {
209
+ const progress = workspace.discoveryProgress;
210
+ if (!progress?.active) return null;
211
+ return (
212
+ <div className="tx-progress-strip tx-portal-resolution-progress" role="status" aria-live="polite" data-phase={progress.phase || 'resolving'}>
213
+ <span>{progress.label || 'Preparing source snapshot'}</span>
214
+ {progress.quantified !== false && progress.percent != null ? <div className="tx-progress-bar" aria-label="Source progress"><i style={{ width: `${Math.max(0, Math.min(100, Number(progress.percent || 0)))}%` }} /></div> : <small className="tx-progress-phase">{progress.phase || 'working'}</small>}
215
+ </div>
216
+ );
217
+ }
218
+
219
+ export function WorkspaceDropHint({ workspace, hasMaterial }) {
220
+ if (hasMaterial || workspace.discoveryProgress) return null;
221
+ return (
222
+ <div className="tx-workspace-drop-hint" role="note">
223
+ <p><strong>Drop local material here</strong><span>.md, folders, or .zip · local/session only</span></p>
224
+ </div>
225
+ );
226
+ }
227
+
228
+ export function ModeToolbar({ state, query, displayOptions, selectedRecord, lineageLoadReport = null, lineageReady = false, onVerse, onQuery, onOpenDisplayOptions, onRunLineageAudit, onLoadFullLineage, readOnly = false }) {
229
+ const requestedVerse = state.view?.workspaceVerse || 'feed';
230
+ const verse = readOnly && !['feed', 'tree', 'graph'].includes(requestedVerse) ? 'feed' : requestedVerse;
231
+ const discoveryVerse = verse === 'feed' || verse === 'tree';
232
+ const graphVerse = verse === 'graph';
233
+ const lineageVerse = verse === 'lineage';
234
+ const auditVerse = verse === 'audit';
235
+ const selectedRecordId = String(state.view?.selectedRecordId || '');
236
+ const selectedLineageReport = lineageLoadReport && String(lineageLoadReport.selectedRecordId || '') === selectedRecordId ? lineageLoadReport : null;
237
+ const lineageAttempted = Boolean(lineageVerse && selectedRecord && (lineageReady || selectedLineageReport));
238
+ const lineageComplete = Boolean(lineageAttempted && (lineageReady || (selectedLineageReport && selectedLineageReport.state === 'complete' && !selectedLineageReport.hasMissing)));
239
+ const needsLineageLoad = Boolean(lineageVerse && selectedRecord && (!selectedLineageReport || selectedLineageReport.state !== 'complete' || selectedLineageReport.hasMissing));
240
+ const modeLabel = graphVerse ? 'GRAPH ORIENTATION' : lineageVerse ? 'LINEAGE MODE' : auditVerse ? 'AUDIT DETAILS' : 'DISCOVERY MODE';
241
+ const activeDisplayConstraintCount = displayOptionsActiveConstraintCount(displayOptions, lineageVerse ? 'lineage' : 'discovery');
242
+ const lineageReturnVerse = state.view?.lineageReturnVerse === 'tree' ? 'tree' : 'feed';
243
+ const returnVerse = auditVerse && selectedRecord ? 'lineage' : lineageVerse ? lineageReturnVerse : 'feed';
244
+ const canDisplayOptions = discoveryVerse || lineageAttempted;
245
+ const canSearch = graphVerse || !lineageVerse || lineageAttempted;
246
+ return (
247
+ <div className="tx-mode-strip tx-column-toolbar" aria-label="Mode controls">
248
+ <strong className="tx-mode-name">{modeLabel}</strong>
249
+ {discoveryVerse ? (
250
+ <>
251
+ <div className="tx-segment" aria-label="Discovery view">
252
+ <button type="button" className={verse === 'feed' ? 'tx-active' : ''} onClick={() => onVerse('feed')}>Feed</button>
253
+ <button type="button" className={verse === 'tree' ? 'tx-active' : ''} onClick={() => onVerse('tree')}>Tree</button>
254
+ </div>
255
+ <button type="button" className="tx-mode-action-button tx-mode-graph-button" onClick={() => onVerse('graph')} aria-label="Open Node Graph Verse">Graph</button>
256
+ </>
257
+ ) : (
258
+ <>
259
+ <button type="button" className="tx-mode-return" onClick={() => onVerse(returnVerse)}>← Back</button>
260
+ {lineageVerse && selectedRecord ? <button type="button" className="tx-mode-action-button tx-mode-graph-button" onClick={() => onVerse('graph')} aria-label="Open selected artifact in Node Graph Verse">Graph</button> : null}
261
+ </>
262
+ )}
263
+ {!readOnly && needsLineageLoad ? (
264
+ <button type="button" className="tx-mode-load-lineage-button" onClick={onLoadFullLineage} title="Load or retry the full lineage index from available source/direct transport before Audit" aria-label="Load full lineage">
265
+ <Icon name="lineage" /><span>Load full lineage</span>
266
+ </button>
267
+ ) : null}
268
+ {!readOnly && lineageComplete ? (
269
+ <button type="button" className="tx-mode-action-button tx-mode-audit-button tx-mode-audit-run-button" onClick={onRunLineageAudit} title="Audit lineage" aria-label="Audit lineage">
270
+ <Icon name="audit" /><span>Audit</span>
271
+ </button>
272
+ ) : null}
273
+ {canDisplayOptions ? (
274
+ <button type="button" className="tx-mode-action-button tx-display-options-icon-trigger" onClick={onOpenDisplayOptions} title={`Display options${activeDisplayConstraintCount ? ` · ${activeDisplayConstraintCount} active` : ''}`} aria-label={`Display options${activeDisplayConstraintCount ? `, ${activeDisplayConstraintCount} active` : ''}`}>
275
+ <Icon name="filters" />
276
+ {activeDisplayConstraintCount ? <span className="tx-mode-action-count">{activeDisplayConstraintCount}</span> : null}
277
+ </button>
278
+ ) : null}
279
+ {canSearch ? (
280
+ <label className="tx-search-field tx-search-field-icon">
281
+ <Icon name="search" />
282
+ <input value={query} onChange={(event) => onQuery(event.target.value)} type="search" placeholder={graphVerse ? 'Search graph title/schema/path…' : lineageVerse ? 'Search loaded lineage…' : 'Search title/body/schema/path…'} />
283
+ </label>
284
+ ) : null}
285
+ </div>
286
+ );
287
+ }
288
+
289
+ export function EmptyWorkspaceState({ filtered, hasMaterial, query, summary = null, progress = null }) {
290
+ const copy = workspaceEmptyStateCopy({ filtered, hasMaterial, query, summary, progress });
291
+ return (
292
+ <div className="tx-empty-node-state tx-compact-empty-node-state" role="status" aria-live="polite">
293
+ <p>{copy.message}</p>
294
+ {copy.hint ? <small>{copy.hint}</small> : null}
295
+ {copy.firstWarning?.message ? <small className="tx-empty-receipt-detail">Warning: {String(copy.firstWarning.message).slice(0, 220)}</small> : null}
296
+ {copy.firstError?.error ? <small className="tx-empty-receipt-detail">Error: {String(copy.firstError.error).slice(0, 220)}</small> : null}
297
+ </div>
298
+ );
299
+ }
@@ -0,0 +1,80 @@
1
+ import React, { useState } from 'react';
2
+ import { Badge } from '../../ui/primitives/Badge.jsx';
3
+ import { Button } from '../../ui/primitives/Button.jsx';
4
+ import { Modal } from '../../ui/primitives/Modal.jsx';
5
+ import { createContinuationDraft, listContinuationTargets } from '@tiinex/core/transitions/record.transitions.js';
6
+
7
+ export function ContinuationDialog({ record, schemaRegistry, transitionDefinition = null, workspaceRecords = [], onDismiss, onCreateTransition }) {
8
+ const transitionTarget = transitionDefinition ? targetFromTransitionDefinition(transitionDefinition) : null;
9
+ const targets = transitionTarget ? [transitionTarget] : listContinuationTargets(schemaRegistry);
10
+ const [selected, setSelected] = useState(targets[0]?.id || 'tiinex.task.v1');
11
+ const [title, setTitle] = useState(`Continue · ${record?.title || 'artifact'}`.slice(0, 96));
12
+ const [summary, setSummary] = useState(`Continuation leaf drafted from ${record?.title || 'this artifact'}.`.slice(0, 280));
13
+ const target = targets.find((item) => item.id === selected) || targets[0] || { id: 'tiinex.task.v1', label: 'Task', summary: 'Task continuation.' };
14
+ const draft = createContinuationDraft(record, target, { title, summary, transitionDefinitionId: transitionDefinition?.id || '', intent: transitionDefinition?.intent || 'continue' }, { existingRecords: workspaceRecords });
15
+ const lockedTarget = Boolean(transitionDefinition);
16
+ const dialogTitle = transitionDefinition?.label || 'Create continuation leaf';
17
+ return (
18
+ <Modal title={dialogTitle} onDismiss={onDismiss} initialFocus="continuationTitle">
19
+ <div className="tx-continuation-dialog tx-continuation-dialog-compact">
20
+ {!lockedTarget && targets.length > 1 ? <ContinuationTargetPicker targets={targets} selected={selected} onSelect={setSelected} /> : null}
21
+ <label className="tx-field"><span>Title</span><input id="continuationTitle" value={title} onChange={(event) => setTitle(event.target.value)} maxLength={96} /></label>
22
+ <label className="tx-field"><span>Summary</span><textarea value={summary} onChange={(event) => setSummary(event.target.value)} rows={3} maxLength={280} /></label>
23
+ <TransitionValidationNotice validation={draft.validation} />
24
+ <details className="tx-continuation-meta">
25
+ <summary>Generated details</summary>
26
+ <div className="tx-card-badges">
27
+ <Badge>{draft.schema}</Badge><Badge>{transitionDefinition?.presentation?.group || 'Continue'}</Badge><Badge>{target.id}</Badge><Badge>{draft.transition.parentBoundary}</Badge>
28
+ </div>
29
+ <p className="tx-muted">Creates a browser-local {target.label} draft from the selected record. Source-backed parent material stays read-only and no source provenance is inferred.</p>
30
+ <details className="tx-continuation-preview"><summary>Preview generated Markdown</summary><pre className="tx-record-markdown-preview">{draft.markdown}</pre></details>
31
+ </details>
32
+ <div className="tx-dialog-actions">
33
+ <Button variant="ghost" onClick={onDismiss}>Cancel</Button>
34
+ <Button variant="primary" icon={transitionDefinition?.presentation?.icon || 'continue'} onClick={() => onCreateTransition?.(record, draft)}>Create local {target.label.toLowerCase()}</Button>
35
+ </div>
36
+ </div>
37
+ </Modal>
38
+ );
39
+ }
40
+
41
+ function ContinuationTargetPicker({ targets = [], selected = '', onSelect }) {
42
+ return (
43
+ <div className="tx-continuation-target-grid" role="listbox" aria-label="Continuation target schema">
44
+ {targets.map((item) => <button key={item.id} type="button" className={`tx-continuation-target ${selected === item.id ? 'tx-active' : ''}`} aria-selected={selected === item.id} onClick={() => onSelect?.(item.id)}><strong>{item.label}</strong><small>{item.summary}</small></button>)}
45
+ </div>
46
+ );
47
+ }
48
+
49
+ export function TransitionValidationNotice({ validation }) {
50
+ if (!validation) return null;
51
+ const severe = (validation.findings || []).filter((finding) => finding.severity === 'error' || finding.severity === 'warning').slice(0, 3);
52
+ if (validation.ok && severe.length === 0) return null;
53
+ return (
54
+ <div className={`tx-transition-validation tx-transition-validation-${validation.status || (validation.ok ? 'valid' : 'invalid')}`}>
55
+ <strong>{validation.ok ? 'Transition conformance passed' : 'Transition conformance needs attention'}</strong>
56
+ <span>{validation.counts?.error || 0} errors · {validation.counts?.warning || 0} warnings · local draft boundary</span>
57
+ {severe.length ? <ul>{severe.map((finding) => <li key={finding.code}>{finding.message}</li>)}</ul> : null}
58
+ </div>
59
+ );
60
+ }
61
+
62
+ function targetFromTransitionDefinition(definition = {}) {
63
+ const resultSchema = definition.resultSchema || 'tiinex.task.v1';
64
+ return {
65
+ id: resultSchema,
66
+ label: definition.shortLabel || labelFromSchemaId(resultSchema),
67
+ summary: definition.label || 'Schema-backed continuation.',
68
+ contract: definition.id || '',
69
+ transitionDefinitionId: definition.id || '',
70
+ intent: definition.intent || 'continue',
71
+ creationContract: `creation:continue-from-record:${resultSchema}`,
72
+ creationStatus: 'implemented',
73
+ boundary: 'Transition definition creates a browser-local draft and does not mutate source material.'
74
+ };
75
+ }
76
+
77
+ function labelFromSchemaId(id = '') {
78
+ const tail = String(id || '').split('.').filter(Boolean).slice(-2, -1)[0] || String(id || 'leaf');
79
+ return tail.charAt(0).toUpperCase() + tail.slice(1);
80
+ }
@@ -0,0 +1,63 @@
1
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
2
+ import { AssetCard, MemoRecordCard as RecordCard } from './workspace.cards.views.jsx';
3
+ import { discoveryInitialRecordWindowLimitForScroll, discoveryRecordWindowKey, discoveryRenderWindowProfile, discoveryWindowState, DISCOVERY_INITIAL_RECORD_WINDOW } from './workspace.discoveryRenderWindow.js';
4
+
5
+ export function DiscoveryRecordList({ records = [], assets = [], auditById = new Map(), stageScrollTop = 0, actionStateKey = '', workspaceRecords = [], workspaceId = '', transitionProductContext = null, onOpenRecord, onFocusRecordLineage, onShareRecord, onRecordAction, onOpenSchema, onOpenAsset, readOnly = false, selectionActive = false, selectionCandidates = [], onSelectCandidate }) {
6
+ const selectionByRecordId = useMemo(() => new Map((Array.isArray(selectionCandidates) ? selectionCandidates : []).filter((item) => String(item?.workspaceId || '') === String(workspaceId) && item?.id).map((item) => [String(item.id), item])), [selectionCandidates, workspaceId]);
7
+ const resetKey = useMemo(() => discoveryRecordWindowKey(records, assets), [records, assets]);
8
+ const [viewport, setViewport] = useState(() => discoveryViewportSnapshot());
9
+ const profile = useMemo(() => discoveryRenderWindowProfile(viewport), [viewport]);
10
+ const restoreWindowLimit = useMemo(() => discoveryInitialRecordWindowLimitForScroll(stageScrollTop, viewport, profile), [stageScrollTop, viewport, profile]);
11
+ const [visibleRecordLimit, setVisibleRecordLimit] = useState(() => restoreWindowLimit || profile.initial || DISCOVERY_INITIAL_RECORD_WINDOW);
12
+ const sentinelRef = useRef(null);
13
+ const windowState = useMemo(() => discoveryWindowState(records, visibleRecordLimit, profile), [records, visibleRecordLimit, profile]);
14
+ const totalRecords = windowState.total;
15
+ const visibleRecords = windowState.visibleRecords;
16
+ const remainingRecords = windowState.remaining;
17
+
18
+ useEffect(() => {
19
+ setVisibleRecordLimit(Math.max(profile.initial || DISCOVERY_INITIAL_RECORD_WINDOW, restoreWindowLimit || 0));
20
+ }, [resetKey, profile.initial, restoreWindowLimit]);
21
+
22
+ useEffect(() => {
23
+ if (typeof window === 'undefined') return undefined;
24
+ const update = () => setViewport(discoveryViewportSnapshot());
25
+ window.addEventListener('resize', update, { passive: true });
26
+ window.visualViewport?.addEventListener?.('resize', update, { passive: true });
27
+ return () => {
28
+ window.removeEventListener('resize', update);
29
+ window.visualViewport?.removeEventListener?.('resize', update);
30
+ };
31
+ }, []);
32
+
33
+ useEffect(() => {
34
+ if (!remainingRecords || !sentinelRef.current || typeof IntersectionObserver === 'undefined') return undefined;
35
+ const node = sentinelRef.current;
36
+ const observer = new IntersectionObserver((entries) => {
37
+ if (!entries.some((entry) => entry.isIntersecting)) return;
38
+ setVisibleRecordLimit((limit) => Math.min(totalRecords, limit + windowState.step));
39
+ }, { rootMargin: '540px 0px' });
40
+ observer.observe(node);
41
+ return () => observer.disconnect();
42
+ }, [remainingRecords, totalRecords, windowState.step]);
43
+
44
+ return (
45
+ <div className="tx-discovery-record-list tx-unified-record-list" aria-label="Discovery artifacts" data-record-window={visibleRecords.length < totalRecords ? 'partial' : 'complete'}>
46
+ {visibleRecords.map((record) => <RecordCard key={record.id} record={record} auditItem={auditById.get(record.id)} actionStateKey={actionStateKey} workspaceRecords={workspaceRecords} workspaceId={workspaceId} transitionProductContext={transitionProductContext} readOnly={readOnly} selectionActive={selectionActive} selectionCandidate={selectionByRecordId.get(String(record.id)) || null} onSelectCandidate={onSelectCandidate} onOpenRecord={onOpenRecord} onFocusRecordLineage={onFocusRecordLineage} onShareRecord={onShareRecord} onRecordAction={onRecordAction} onOpenSchema={onOpenSchema} />)}
47
+ {remainingRecords ? (
48
+ <div className="tx-discovery-window-sentinel" ref={sentinelRef} aria-live="polite">
49
+ <span className="tx-discovery-window-summary">Showing {visibleRecords.length} of {totalRecords} matching artifacts. Search and filters already cover all loaded content.</span>
50
+ <button type="button" onClick={() => setVisibleRecordLimit((limit) => Math.min(totalRecords, limit + windowState.step))}>Load more</button>
51
+ </div>
52
+ ) : null}
53
+ {assets.map((asset) => <AssetCard key={asset.id || asset.path} asset={asset} actionStateKey={actionStateKey} onOpenAsset={onOpenAsset} />)}
54
+ </div>
55
+ );
56
+ }
57
+
58
+ function discoveryViewportSnapshot() {
59
+ if (typeof window === 'undefined') return { width: 0, coarse: false };
60
+ let coarse = false;
61
+ try { coarse = Boolean(window.matchMedia?.('(pointer: coarse)')?.matches); } catch (_) {}
62
+ return { width: Math.floor(window.visualViewport?.width || window.innerWidth || 0), height: Math.floor(window.visualViewport?.height || window.innerHeight || 0), coarse };
63
+ }
@@ -0,0 +1,56 @@
1
+ export const DISCOVERY_INITIAL_RECORD_WINDOW = 60;
2
+ export const DISCOVERY_RECORD_WINDOW_STEP = 40;
3
+ export const DISCOVERY_MOBILE_INITIAL_RECORD_WINDOW = 30;
4
+ export const DISCOVERY_MOBILE_RECORD_WINDOW_STEP = 24;
5
+ export const DISCOVERY_DESKTOP_ESTIMATED_CARD_HEIGHT = 126;
6
+ export const DISCOVERY_MOBILE_ESTIMATED_CARD_HEIGHT = 154;
7
+ export const DISCOVERY_SCROLL_RESTORE_OVERSCAN_PX = 900;
8
+
9
+ export function discoveryRenderWindowProfile(viewport = {}) {
10
+ const width = Number(viewport.width || 0);
11
+ const coarse = viewport.coarse === true;
12
+ const mobile = coarse || (width > 0 && width <= 540);
13
+ return Object.freeze({
14
+ mobile,
15
+ initial: mobile ? DISCOVERY_MOBILE_INITIAL_RECORD_WINDOW : DISCOVERY_INITIAL_RECORD_WINDOW,
16
+ step: mobile ? DISCOVERY_MOBILE_RECORD_WINDOW_STEP : DISCOVERY_RECORD_WINDOW_STEP,
17
+ estimatedCardHeight: mobile ? DISCOVERY_MOBILE_ESTIMATED_CARD_HEIGHT : DISCOVERY_DESKTOP_ESTIMATED_CARD_HEIGHT,
18
+ restoreOverscanPx: DISCOVERY_SCROLL_RESTORE_OVERSCAN_PX
19
+ });
20
+ }
21
+
22
+ export function discoveryInitialRecordWindowLimitForScroll(scrollTop = 0, viewport = {}, profile = discoveryRenderWindowProfile(viewport)) {
23
+ const initial = Math.max(1, Number(profile.initial || DISCOVERY_INITIAL_RECORD_WINDOW));
24
+ const top = Math.max(0, Number(scrollTop || 0));
25
+ if (!Number.isFinite(top) || top <= 0) return initial;
26
+ const viewportHeight = Math.max(0, Number(viewport.height || 0));
27
+ const estimate = Math.max(72, Number(profile.estimatedCardHeight || DISCOVERY_DESKTOP_ESTIMATED_CARD_HEIGHT));
28
+ const overscan = Math.max(0, Number(profile.restoreOverscanPx || DISCOVERY_SCROLL_RESTORE_OVERSCAN_PX));
29
+ const needed = Math.ceil((top + viewportHeight + overscan) / estimate);
30
+ return Math.max(initial, needed);
31
+ }
32
+
33
+ export function discoveryRecordWindowKey(records = [], assets = []) {
34
+ const first = records[0]?.id || records[0]?.path || '';
35
+ const last = records[records.length - 1]?.id || records[records.length - 1]?.path || '';
36
+ const firstAsset = assets[0]?.id || assets[0]?.path || '';
37
+ return `${records.length}:${first}:${last}:${assets.length}:${firstAsset}`;
38
+ }
39
+
40
+ export function discoveryWindowState(records = [], requestedLimit = 0, profile = discoveryRenderWindowProfile()) {
41
+ const source = Array.isArray(records) ? records : [];
42
+ const total = source.length;
43
+ const initial = Math.max(1, Number(profile.initial || DISCOVERY_INITIAL_RECORD_WINDOW));
44
+ const requested = Math.max(initial, Number(requestedLimit || initial));
45
+ const limit = total > initial ? Math.min(total, requested) : total;
46
+ const visibleRecords = limit < total ? source.slice(0, limit) : source;
47
+ return Object.freeze({
48
+ total,
49
+ visibleRecords,
50
+ visibleCount: visibleRecords.length,
51
+ remaining: Math.max(0, total - visibleRecords.length),
52
+ partial: visibleRecords.length < total,
53
+ initial,
54
+ step: Math.max(1, Number(profile.step || DISCOVERY_RECORD_WINDOW_STEP))
55
+ });
56
+ }
@@ -0,0 +1,114 @@
1
+ import React, { useState } from 'react';
2
+ import { Button } from '../../ui/primitives/Button.jsx';
3
+ import { Modal } from '../../ui/primitives/Modal.jsx';
4
+ import { materialRoleLabel } from '@tiinex/core/workspaces/workspace.materialRole.js';
5
+ import { normalizeWorkspaceDisplayOptions } from '../../workspaces/workspace.displayOptions.js';
6
+ import { normalizeTimePortalView } from '../../workspaces/workspace.timePortal.js';
7
+
8
+ export function DisplayOptionsDialog({ options, counts = {}, scope = 'discovery', timePortal = null, onResolveTimePortal, onReturnLatest, onSubmit, onDismiss }) {
9
+ const [draft, setDraft] = useState(normalizeWorkspaceDisplayOptions(options));
10
+ const normalizedTimePortal = normalizeTimePortalView(timePortal);
11
+ const [timeDraft, setTimeDraft] = useState({ begin: normalizedTimePortal?.begin || '', end: normalizedTimePortal?.end || '' });
12
+ const schemaChoices = Array.isArray(counts.schemaChoices) ? counts.schemaChoices : [];
13
+ const artifactChoices = Array.isArray(counts.artifactChoices) ? counts.artifactChoices : [];
14
+ const sourceChoices = Array.isArray(counts.sourceChoices) ? counts.sourceChoices : [];
15
+ const lineageScope = String(scope || 'discovery') === 'lineage';
16
+ function setFlag(key, value) {
17
+ setDraft((current) => Object.assign({}, current, { [key]: Boolean(value) }));
18
+ }
19
+ function setValue(key, value) {
20
+ setDraft((current) => Object.assign({}, current, { [key]: String(value || 'all') || 'all' }));
21
+ }
22
+ function submit(event) {
23
+ event.preventDefault();
24
+ onSubmit?.(normalizeWorkspaceDisplayOptions(draft));
25
+ }
26
+ return (
27
+ <Modal title="Display options" onDismiss={onDismiss} initialFocus={lineageScope ? 'displaySchemaFilter' : 'displayLeavesOnly'} className="tx-dialog-display-options">
28
+ <form className="tx-form tx-display-options-form tx-display-options-parity-form" onSubmit={submit} data-form="display-options-form">
29
+ <p className="tx-muted">{lineageScope ? 'Lineage filters apply to the loaded lineage only. Leaves-only and material membership controls are Discovery-only.' : 'Presentation only. Source, audit, lineage, and export truth stay intact even when material is filtered from Feed/Tree.'}</p>
30
+ <div className="tx-display-filter-grid" aria-label="Artifact filters">
31
+ <label className="tx-select-field">
32
+ <span>Schema</span>
33
+ <select id="displaySchemaFilter" value={draft.schemaFilter} onChange={(event) => setValue('schemaFilter', event.target.value)}>
34
+ <option value="all">All schemas</option>
35
+ {schemaChoices.map(([value, count]) => <option key={value} value={value}>{compactSchemaOption(value)} · {count}</option>)}
36
+ </select>
37
+ </label>
38
+ <label className="tx-select-field">
39
+ <span>Artifact role</span>
40
+ <select value={draft.artifactFilter} onChange={(event) => setValue('artifactFilter', event.target.value)}>
41
+ <option value="all">All roles</option>
42
+ {artifactChoices.map(([value, count]) => <option key={value} value={value}>{artifactFilterLabel(value)} · {count}</option>)}
43
+ </select>
44
+ </label>
45
+ <label className="tx-select-field">
46
+ <span>Source boundary</span>
47
+ <select value={draft.sourceFilter} onChange={(event) => setValue('sourceFilter', event.target.value)}>
48
+ <option value="all">All boundaries</option>
49
+ {sourceChoices.map(([value, count]) => <option key={value} value={value}>{sourceFilterLabel(value)} · {count}</option>)}
50
+ </select>
51
+ </label>
52
+ </div>
53
+ {!lineageScope ? (
54
+ <label className="tx-display-option-row tx-display-option-primary">
55
+ <span><strong>Leaves only</strong><small>{Number(counts.leaves || 0)} terminal work {Number(counts.leaves || 0) === 1 ? 'leaf' : 'leaves'} · hides loaded parents, schema/type definitions, support files, and body-missing source shells</small></span>
56
+ <input id="displayLeavesOnly" type="checkbox" checked={draft.leavesOnly} onChange={(event) => setFlag('leavesOnly', event.target.checked)} />
57
+ </label>
58
+ ) : null}
59
+ <label className="tx-display-option-row">
60
+ <span><strong>Mismatches only</strong><small>{Number(counts.mismatches || 0)} record{Number(counts.mismatches || 0) === 1 ? '' : 's'} currently carry mismatch-level audit status</small></span>
61
+ <input id="displayMismatchesOnly" type="checkbox" checked={draft.mismatchesOnly} onChange={(event) => setFlag('mismatchesOnly', event.target.checked)} />
62
+ </label>
63
+ {!lineageScope ? (
64
+ <section className="tx-display-time-portal" aria-label="Time Portal">
65
+ <h3>Time Portal</h3>
66
+ <p className="tx-muted">Source-grounded historical review. Begin/End expresses intent only; no date is converted into a commit.</p>
67
+ <div className="tx-display-filter-grid">
68
+ <label className="tx-field"><span>Begin</span><input type="datetime-local" value={timeDraft.begin} onChange={(event) => setTimeDraft((current) => Object.assign({}, current, { begin: event.target.value }))} /></label>
69
+ <label className="tx-field"><span>End / as-of intent</span><input type="datetime-local" value={timeDraft.end} onChange={(event) => setTimeDraft((current) => Object.assign({}, current, { end: event.target.value }))} /></label>
70
+ </div>
71
+ <div className="tx-dialog-actions tx-time-portal-inline-actions">
72
+ {normalizedTimePortal ? <Button type="button" variant="ghost" onClick={onReturnLatest}>Return to latest</Button> : null}
73
+ <Button type="button" variant="ghost" onClick={() => onResolveTimePortal?.(timeDraft)}>Resolve source snapshot</Button>
74
+ </div>
75
+ </section>
76
+ ) : null}
77
+ {!lineageScope ? (
78
+ <>
79
+ <label className="tx-display-option-row">
80
+ <span><strong>Supporting docs</strong><small>{Number(counts.supportingMarkdown || 0)} supporting doc{Number(counts.supportingMarkdown || 0) === 1 ? '' : 's'} · preserved but hidden by default</small></span>
81
+ <input id="displaySupportingMarkdown" type="checkbox" checked={draft.showSupportingMarkdown} onChange={(event) => setFlag('showSupportingMarkdown', event.target.checked)} />
82
+ </label>
83
+ <label className="tx-display-option-row">
84
+ <span><strong>Workspace artifacts</strong><small>{Number(counts.workspaceArtifacts || 0)} artifact{Number(counts.workspaceArtifacts || 0) === 1 ? '' : 's'} · Open/Merge remain artifact capabilities</small></span>
85
+ <input type="checkbox" checked={draft.showWorkspaceArtifacts} onChange={(event) => setFlag('showWorkspaceArtifacts', event.target.checked)} />
86
+ </label>
87
+ <label className="tx-display-option-row">
88
+ <span><strong>Assets</strong><small>{Number(counts.assets || 0)} asset{Number(counts.assets || 0) === 1 ? '' : 's'} · hidden by default, never fake leaves</small></span>
89
+ <input type="checkbox" checked={draft.showAssets} onChange={(event) => setFlag('showAssets', event.target.checked)} />
90
+ </label>
91
+ </>
92
+ ) : null}
93
+ <div className="tx-dialog-actions">
94
+ <Button type="button" variant="ghost" onClick={onDismiss}>Cancel</Button>
95
+ <Button type="submit" variant="primary" icon="check">Apply</Button>
96
+ </div>
97
+ </form>
98
+ </Modal>
99
+ );
100
+ }
101
+
102
+ function compactSchemaOption(value = '') {
103
+ return String(value || 'artifact').replace(/^tiinex\./, '').replace(/\.v\d+$/, '');
104
+ }
105
+
106
+ function artifactFilterLabel(value = '') {
107
+ return materialRoleLabel(value);
108
+ }
109
+
110
+ function sourceFilterLabel(value = '') {
111
+ if (value === 'source-backed') return 'Source-backed';
112
+ if (value === 'local') return 'Local/session';
113
+ return value || 'Source boundary';
114
+ }