smartpipe-cli 1.4.0rc2__tar.gz → 1.4.0rc4__tar.gz

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 (260) hide show
  1. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/CHANGELOG.md +142 -13
  2. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/CITATION.cff +1 -1
  3. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/CONTRIBUTING.md +6 -5
  4. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/PKG-INFO +35 -14
  5. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/README.md +33 -13
  6. smartpipe_cli-1.4.0rc4/demo/video/README.md +23 -0
  7. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/Main.tsx +26 -7
  8. smartpipe_cli-1.4.0rc4/demo/video/src/Narration.tsx +94 -0
  9. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/Root.tsx +17 -2
  10. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/Background.tsx +3 -10
  11. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/Terminal.tsx +69 -4
  12. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/config.ts +10 -6
  13. smartpipe_cli-1.4.0rc4/demo/video/src/narration/durations.json +13 -0
  14. smartpipe_cli-1.4.0rc4/demo/video/src/narration/lines.json +13 -0
  15. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/scenes/Close.tsx +1 -2
  16. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/scenes/CostHonesty.tsx +27 -42
  17. smartpipe_cli-1.4.0rc4/demo/video/src/scenes/Graph.tsx +236 -0
  18. smartpipe_cli-1.4.0rc4/demo/video/src/scenes/Hook.tsx +47 -0
  19. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/scenes/Multimodal.tsx +150 -31
  20. smartpipe_cli-1.4.0rc4/demo/video/src/scenes/ScaleA.tsx +43 -0
  21. smartpipe_cli-1.4.0rc4/demo/video/src/scenes/ScaleB.tsx +42 -0
  22. smartpipe_cli-1.4.0rc4/docs/assets/demo-thumb.jpg +0 -0
  23. smartpipe_cli-1.4.0rc4/docs/assets/graph-hero.png +0 -0
  24. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/comparison.md +2 -2
  25. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/feeding-smartpipe.md +10 -2
  26. smartpipe_cli-1.4.0rc4/docs/concepts/granularity.md +109 -0
  27. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/models-and-providers.md +59 -47
  28. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/output-formats.md +7 -1
  29. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/structured-output.md +57 -0
  30. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/the-item.md +15 -2
  31. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/README.md +3 -2
  32. smartpipe_cli-1.4.0rc4/docs/cookbook/knowledge-graph.md +131 -0
  33. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/live-monitoring.md +2 -2
  34. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/visualizing-results.md +2 -2
  35. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/demo/index.html +1 -1
  36. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/index.md +12 -10
  37. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/inputs/files.md +2 -2
  38. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/install.md +3 -3
  39. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/1-first-pipeline.md +29 -14
  40. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/3-files-and-media.md +6 -1
  41. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/6-pipelines-that-last.md +7 -4
  42. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/privacy.md +27 -13
  43. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/reference/cli.md +89 -22
  44. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/reference/sem-files.md +39 -1
  45. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/troubleshooting.md +13 -9
  46. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/cluster.md +2 -2
  47. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/diff.md +1 -1
  48. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/embed.md +5 -4
  49. smartpipe_cli-1.4.0rc4/docs/verbs/graph.md +217 -0
  50. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/join.md +7 -2
  51. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/outliers.md +3 -3
  52. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/reduce.md +3 -3
  53. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/sort.md +4 -1
  54. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/summarize.md +5 -0
  55. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/top-k.md +6 -6
  56. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/where.md +5 -1
  57. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/mkdocs.yml +9 -1
  58. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/pyproject.toml +4 -1
  59. smartpipe_cli-1.4.0rc4/src/smartpipe/cli/auth_cmd.py +268 -0
  60. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/cluster_cmd.py +4 -1
  61. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/completions.py +23 -1
  62. smartpipe_cli-1.4.0rc4/src/smartpipe/cli/config_cmd.py +1248 -0
  63. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/distinct_cmd.py +4 -1
  64. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/doctor_cmd.py +3 -4
  65. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/embed_cmd.py +4 -1
  66. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/extend_cmd.py +4 -1
  67. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/filter_cmd.py +4 -1
  68. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/join_cmd.py +4 -1
  69. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/map_cmd.py +4 -1
  70. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/outliers_cmd.py +5 -2
  71. smartpipe_cli-1.4.0rc4/src/smartpipe/cli/read_cmd.py +124 -0
  72. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/readable_cmd.py +1 -1
  73. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/reduce_cmd.py +4 -1
  74. smartpipe_cli-1.4.0rc4/src/smartpipe/cli/rescue.py +94 -0
  75. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/root.py +37 -20
  76. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/run_cmd.py +28 -4
  77. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/schema_cmd.py +45 -11
  78. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/screens.py +13 -10
  79. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/sem_file.py +55 -10
  80. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/sort_cmd.py +1 -1
  81. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/split_cmd.py +4 -1
  82. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/top_k_cmd.py +5 -2
  83. smartpipe_cli-1.4.0rc4/src/smartpipe/config/authflow.py +202 -0
  84. smartpipe_cli-1.4.0rc4/src/smartpipe/config/bundles.py +186 -0
  85. smartpipe_cli-1.4.0rc4/src/smartpipe/config/credentials.py +241 -0
  86. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/display.py +31 -19
  87. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/doctor.py +21 -19
  88. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/picker.py +264 -14
  89. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/state_cache.py +50 -3
  90. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/store.py +92 -118
  91. smartpipe_cli-1.4.0rc4/src/smartpipe/config/verify.py +288 -0
  92. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/container.py +14 -8
  93. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/aggregate.py +11 -3
  94. smartpipe_cli-1.4.0rc4/src/smartpipe/engine/fieldpath.py +167 -0
  95. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/predicate.py +26 -3
  96. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/prompts.py +53 -10
  97. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/schema.py +28 -0
  98. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/schema_repl.py +7 -2
  99. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/items.py +13 -1
  100. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/readers.py +53 -21
  101. smartpipe_cli-1.4.0rc4/src/smartpipe/io/richui.py +112 -0
  102. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/update_check.py +1 -1
  103. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/writers.py +3 -1
  104. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/budget.py +29 -1
  105. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/catalogs.py +62 -7
  106. smartpipe_cli-1.4.0rc4/src/smartpipe/models/keycheck.py +108 -0
  107. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/resolve.py +1 -2
  108. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/chart.py +14 -5
  109. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/cluster.py +17 -1
  110. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/common.py +4 -3
  111. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/convert.py +1 -1
  112. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/diff.py +6 -0
  113. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/filter.py +1 -1
  114. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/join.py +13 -2
  115. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/outliers.py +1 -1
  116. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/reduce.py +49 -9
  117. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/sortverb.py +4 -1
  118. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/summarize.py +3 -1
  119. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/top_k.py +27 -17
  120. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/where.py +5 -2
  121. smartpipe_cli-1.4.0rc2/demo/video/README.md +0 -17
  122. smartpipe_cli-1.4.0rc2/demo/video/src/scenes/Hook.tsx +0 -40
  123. smartpipe_cli-1.4.0rc2/demo/video/src/scenes/Scale.tsx +0 -47
  124. smartpipe_cli-1.4.0rc2/docs/assets/demo-thumb.jpg +0 -0
  125. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/auth_cmd.py +0 -78
  126. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/config_cmd.py +0 -564
  127. smartpipe_cli-1.4.0rc2/src/smartpipe/cli/read_cmd.py +0 -68
  128. smartpipe_cli-1.4.0rc2/src/smartpipe/config/credentials.py +0 -118
  129. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/.gitignore +0 -0
  130. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/LICENSE +0 -0
  131. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/NOTICE +0 -0
  132. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/Caption.tsx +0 -0
  133. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/FileGlyph.tsx +0 -0
  134. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/SceneFrame.tsx +0 -0
  135. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/components/Wordmark.tsx +0 -0
  136. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/font.ts +0 -0
  137. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/index.ts +0 -0
  138. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/demo/video/src/scenes/ColdOpen.tsx +0 -0
  139. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/concepts/pipes-and-items.md +0 -0
  140. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/contract-extraction.md +0 -0
  141. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/customer-feedback.md +0 -0
  142. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/invoice-reconciliation.md +0 -0
  143. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/log-triage.md +0 -0
  144. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/meeting-digest.md +0 -0
  145. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/ranking-documents.md +0 -0
  146. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/stream-enrichment.md +0 -0
  147. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/training-data-prep.md +0 -0
  148. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/cookbook/video-qa.md +0 -0
  149. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/2-structured-data.md +0 -0
  150. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/4-free-verbs.md +0 -0
  151. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/learn/5-scale-and-cost.md +0 -0
  152. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/quickstart.md +0 -0
  153. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/reference/agents.md +0 -0
  154. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/reference/custom-verbs.md +0 -0
  155. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/distinct.md +0 -0
  156. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/extend.md +0 -0
  157. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/filter.md +0 -0
  158. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/getschema.md +0 -0
  159. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/map.md +0 -0
  160. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/readable.md +0 -0
  161. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/sample.md +0 -0
  162. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/docs/verbs/split.md +0 -0
  163. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/qa/README.md +0 -0
  164. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/qa/fixtures/README.md +0 -0
  165. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/__init__.py +0 -0
  166. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/__main__.py +0 -0
  167. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/assets/probe.png +0 -0
  168. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/assets/probe.txt +0 -0
  169. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/assets/probe.wav +0 -0
  170. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/__init__.py +0 -0
  171. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/cache_cmd.py +0 -0
  172. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/chart_cmd.py +0 -0
  173. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/cite_cmd.py +0 -0
  174. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/diff_cmd.py +0 -0
  175. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/echo_cmd.py +0 -0
  176. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/getschema_cmd.py +0 -0
  177. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/graph_cmd.py +0 -0
  178. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/input_options.py +0 -0
  179. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/interrupts.py +0 -0
  180. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/probe_cmd.py +0 -0
  181. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/sample_cmd.py +0 -0
  182. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/schema_workshop.py +0 -0
  183. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/summarize_cmd.py +0 -0
  184. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/update_cmd.py +0 -0
  185. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/usage_cmd.py +0 -0
  186. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/where_cmd.py +0 -0
  187. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/cli/write_cmd.py +0 -0
  188. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/__init__.py +0 -0
  189. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/config/paths.py +0 -0
  190. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/core/__init__.py +0 -0
  191. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/core/errors.py +0 -0
  192. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/core/install_channel.py +0 -0
  193. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/core/jsontools.py +0 -0
  194. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/core/versions.py +0 -0
  195. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/__init__.py +0 -0
  196. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/blocking.py +0 -0
  197. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/chart.py +0 -0
  198. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/chunking.py +0 -0
  199. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/clustering.py +0 -0
  200. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/graphkg.py +0 -0
  201. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/graphout.py +0 -0
  202. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/preview.py +0 -0
  203. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/progressbar.py +0 -0
  204. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/ranking.py +0 -0
  205. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/repair.py +0 -0
  206. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/runner.py +0 -0
  207. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/schema_dsl.py +0 -0
  208. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/tally.py +0 -0
  209. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/temporal.py +0 -0
  210. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/timebin.py +0 -0
  211. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/units.py +0 -0
  212. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/engine/windows.py +0 -0
  213. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/__init__.py +0 -0
  214. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/arrow_menu.py +0 -0
  215. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/csvrows.py +0 -0
  216. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/diagnostics.py +0 -0
  217. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/inputs.py +0 -0
  218. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/leaderboard.py +0 -0
  219. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/metering.py +0 -0
  220. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/preview.py +0 -0
  221. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/progress.py +0 -0
  222. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/render.py +0 -0
  223. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/text.py +0 -0
  224. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/tty.py +0 -0
  225. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/io/usage.py +0 -0
  226. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/__init__.py +0 -0
  227. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/anthropic_adapter.py +0 -0
  228. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/base.py +0 -0
  229. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/cache.py +0 -0
  230. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/gemini_native.py +0 -0
  231. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/http_support.py +0 -0
  232. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/jina.py +0 -0
  233. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/local_embed.py +0 -0
  234. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/local_ner.py +0 -0
  235. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/ocr.py +0 -0
  236. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/ollama.py +0 -0
  237. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/openai_codex.py +0 -0
  238. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/openai_compat.py +0 -0
  239. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/openai_oauth.py +0 -0
  240. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/retry.py +0 -0
  241. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/stt.py +0 -0
  242. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/models/windows.py +0 -0
  243. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/parsing/__init__.py +0 -0
  244. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/parsing/detect.py +0 -0
  245. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/parsing/extract.py +0 -0
  246. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/py.typed +0 -0
  247. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/__init__.py +0 -0
  248. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/distinct.py +0 -0
  249. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/embed.py +0 -0
  250. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/extend.py +0 -0
  251. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/getschema.py +0 -0
  252. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/graph.py +0 -0
  253. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/graphfull.py +0 -0
  254. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/map.py +0 -0
  255. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/oversize.py +0 -0
  256. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/readable.py +0 -0
  257. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/sample.py +0 -0
  258. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/split.py +0 -0
  259. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/src/smartpipe/verbs/write.py +0 -0
  260. {smartpipe_cli-1.4.0rc2 → smartpipe_cli-1.4.0rc4}/tests/corpus/README.md +0 -0
@@ -5,11 +5,20 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning:
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+
8
9
  ## [1.4.0] — 2026-07-08
9
10
 
10
11
  The identity release.
11
12
 
12
13
  ### Knowledge graphs (the highlight)
14
+ - **The showcase**: a full verb page with the modality matrix and a
15
+ live-rendering Mermaid sample, a cookbook chapter written from real
16
+ runs against the downloadable playground corpus, the README highlight
17
+ with a screenshot of the case graph, agent SKILL recipes, and `graph`
18
+ on the welcome screen. Found en route: the playground download in the
19
+ docs pointed at the source tarball (no media inside) - all three
20
+ sites now fetch the actual 26 MB release asset.
21
+
13
22
  - **`smartpipe graph --fast` turns a corpus into a knowledge graph for
14
23
  exactly $0.** A local zero-shot NER model (GLiNER-small over ONNX -
15
24
  no new dependencies, no torch, a one-time ~190 MB download like the
@@ -44,6 +53,15 @@ The identity release.
44
53
  power path.
45
54
 
46
55
  ### The item — one law for everything in a pipe
56
+ - **Nested field paths, everywhere you read.** `where 'user.plan ==
57
+ "pro"'`, `sort --by metrics.score`, `chart items[0].category`,
58
+ `summarize 'avg(metrics.score) by user.plan'`, and `"Is {user.plan}
59
+ worth it?"` in prompts - one grammar (`a.b.c`, `items[0]`,
60
+ `a.b['weird key']`) across all five surfaces. A column literally
61
+ named `user.plan` always wins over the traversal, so CSV headers
62
+ with dots keep working. Extraction names stay flat - paths are for
63
+ reading, and the error says so.
64
+
47
65
  - **Dates are a type, and they come back ISO.** `{due date}` and
48
66
  `{ts datetime}` join the brace grammar. However the model phrases it
49
67
  ("Jan 15, 2026", "15/01/2026"), the field canonicalizes to
@@ -75,9 +93,20 @@ The identity release.
75
93
  double-underscore namespace that rides every record: `__source` (path plus
76
94
  HOW the item was cut - file, lines, jsonl, pages, minutes, segment index),
77
95
  `__media` (one transport object for bytes crossing a pipe), `__score`
78
- (join), `__invalid`/`__error`/`__raw` (kept failures). Known fields
79
- round-trip through saved files; unknown `__` fields warn once and carry.
80
- User data owns everything up to one leading underscore.
96
+ (top_k and join similarity), `__rank` (top_k), `__snapshot` (top_k
97
+ --stream markers), `__distance` (outliers), `__invalid`/`__error`/`__raw`
98
+ (kept failures). Known fields round-trip through saved files; unknown `__`
99
+ fields warn once and carry. User data owns everything up to one leading
100
+ underscore - which is why the last single-underscore stragglers moved:
101
+ pre-1.4 `top_k`/`outliers` wrote `_score`/`_rank`/`_snapshot`/`_distance`,
102
+ and those spellings stay readable for one release (CSV/TSV still sort them
103
+ into the trailing columns) but are never written again. In the same sweep,
104
+ `cluster --explode` overwriting an existing `cluster` field became a
105
+ disclosed overwrite (one stderr warning) instead of a silent one.
106
+ - **top_k ranks can no longer collide.** Ranking keyed on each item's
107
+ source index, so two page-1 records from different PDFs fought over one
108
+ slot and a result silently vanished. Ranks are now run-scoped ordinals in
109
+ arrival order, in both the embedded and precomputed-vector paths.
81
110
  - **Records in, records out.** A plain-prompt `map` over records now returns
82
111
  a record (`{"result": …}` plus the spine) instead of bare prose - structure
83
112
  and provenance survive transformation. Text lines still leave as text.
@@ -105,6 +134,22 @@ The identity release.
105
134
  `where`/`summarize` report rows that had no fields; `--strict-rows` turns
106
135
  the notes into errors. Multi-line plain output into a pipe warns that
107
136
  line framing is ambiguous (use `--output json`).
137
+ - **`.sem` files are strict about their rows now.** A saved pipeline is a
138
+ program, and a stray plain line in a record stream is a bug, not a
139
+ shrug: `.sem` runs default to `--strict-rows` and fail at ingestion
140
+ naming the exact line, before any spend. Opt out with
141
+ `strict-rows = false` (top-level or per-stage); ad-hoc terminal runs
142
+ keep the permissive census. Eleven verbs that accepted `--strict-rows`
143
+ without actually enforcing it now do, and a text-only `where` predicate
144
+ over a log no longer trips strict mode over "missing fields". A new
145
+ docs page explains the granularity ladder (file → split → lines/rows)
146
+ and when mixing happens.
147
+ - **Synthesized records tell you what they summarize.** join pairs carry
148
+ `__sources` (both parents' refs); reduce windows stamp
149
+ `{"as": "window", "span": [1, 100], "count": 100}`, groups
150
+ `{"as": "group", "group": …, "count": N}`; cluster and diff summary
151
+ rows carry `{"as": "cluster"|"diff", "count": N}`. An audit trail for
152
+ every row that speaks for other rows - and `--bare` strips all of it.
108
153
 
109
154
  ### Judgment you can gate, retry, and keep
110
155
  - **`--keep-invalid`** (map/extend): after the repair retry fails, keep the
@@ -114,6 +159,13 @@ The identity release.
114
159
  `--check FILE` validates rows (exit 0/1), `--example` prints a validating
115
160
  instance, bare stdin mode is a REPL. **`--dry-run`** (map/extend) prints
116
161
  the composed first request and exits before any model resolution.
162
+ - **`schema --check` stopped failing your own pipelines.** The check is
163
+ open-world now: rows from the documented extend workflow (original
164
+ fields kept, spine aboard) pass instead of tripping "additional
165
+ properties are not allowed" on every row, and `?`-marked fields may be
166
+ absent, not just null. Extras earn one dim hint; `--strict` restores
167
+ the closed world for contract enforcement. The schema sent to models
168
+ at extraction time is unchanged.
117
169
  - **Nullability is declared.** `?` on any type (`string?`, `number[]?`, bare
118
170
  `field?`) compiles to a null union; bare fields mean scalar-or-scalar-list
119
171
  and never admit null (D48, shipped earlier in this cycle).
@@ -162,6 +214,19 @@ The identity release.
162
214
  over alphabetical luck (cloud tags compete equally), and speaks in the
163
215
  same color voice as the other commands with a menu of detected local
164
216
  tags and provider-prefixed cloud examples.
217
+ - **Exit 141 is now deliberate, and the -13 flake is dead.** smartpipe used
218
+ to arm the default SIGPIPE handler, so a downstream `| head` killed it by
219
+ raw signal - and, one run in a few hundred, a stray EPIPE on asyncio's
220
+ own self-pipe killed a healthy run mid-teardown, skipping the receipt
221
+ (the CI flake that delayed rc3). SIGPIPE now stays ignored; a closed
222
+ stdout surfaces as BrokenPipeError and exits a silent, deliberate 141
223
+ with every finally honored. (click 8.4's own EPIPE-to-exit-1 trap is
224
+ defused on the way.) One visible delta: `kill -PIPE` no longer
225
+ terminates smartpipe; pipeline behavior is unchanged.
226
+ - **A files-then-stdin wait has a name.** Chaining positional files into a
227
+ stdin read used to end in a silent hang when nothing was piped. All three
228
+ chain paths now say once, on stderr:
229
+ `note: files done - now reading stdin (pipe data or close it; files-only: add < /dev/null)`.
165
230
  - **Docs bug, live-caught: `cluster | chart` drew flat bars.** The summary
166
231
  rows are one-per-cluster, so charting them counts every theme once. The
167
232
  README quick-tour step, the `cluster` help epilog, and the `.sem`
@@ -230,15 +295,24 @@ The identity release.
230
295
 
231
296
  ### Documents parse where they enter, vectors stay honest
232
297
  - **The `ocr-model` role: a document parser at ingestion.** Set
233
- `smartpipe config ocr-model mistral/mistral-ocr-latest` (or
234
- `SMARTPIPE_OCR_MODEL`, or `--ocr-model` per run) and ingested PDFs and
235
- images parse through it - one item per page on the `pages` cut,
236
- markdown as the text, disclosed per row and metered as a paid
237
- conversion. Mistral refs ride the dedicated `/v1/ocr` wire
238
- (live-verified, whole PDFs in one call); any other model ref works as
239
- chat-vision with extract-the-text framing, so `ollama/llava` is a free
240
- local OCR. Parse failures fall back to the local extraction ladder,
241
- disclosed, never fatal. Unset = exactly the old behavior.
298
+ `ocr-model = "mistral/mistral-ocr-latest"` in config.toml (the setup
299
+ flow's OCR stage stamps it; `SMARTPIPE_OCR_MODEL` and `--ocr-model`
300
+ override per run) and ingested PDFs and images parse through it - one
301
+ item per page on the `pages` cut, markdown as the text, disclosed per
302
+ row and metered as a paid conversion. Mistral refs ride the dedicated
303
+ `/v1/ocr` wire (live-verified, whole PDFs in one call); any other
304
+ model ref works as chat-vision with extract-the-text framing, so
305
+ `ollama/llava` is a free local OCR. Parse failures fall back to the
306
+ local extraction ladder, disclosed, never fatal. Unset = exactly the
307
+ old behavior.
308
+ - **Reader mode does what you configured.** `smartpipe scan.pdf` used to
309
+ be pinned "zero model calls" even when you had set an ocr-model - the
310
+ reader now honors the role with the same per-row disclosure, local
311
+ fallback, and `--max-calls` belt as the verbs (plus a preflight note
312
+ when more than 20 files will parse). No ocr-model configured = the
313
+ same free path as always, pinned by a zero-HTTP-calls test. Found en
314
+ route: the mistral OCR wire was never counted by `--max-calls`
315
+ anywhere - it is belted now.
242
316
  - **The `media-embed-model` role: one joint space for pixels and prose.**
243
317
  Text keeps `embed-model`; media routes to the joint-space model
244
318
  (jina-clip-v2 and friends). If a run would mix two vector spaces, the
@@ -256,6 +330,42 @@ The identity release.
256
330
  media-embedding capability.
257
331
 
258
332
  ### Setup that reads the room
333
+ - **Rich now backs `config show` and `doctor`.** It is a deliberate core
334
+ dependency under the no-extras policy, imported only while those human-facing
335
+ screens render so `--help`, pipes, and `NO_COLOR` keep their existing contracts.
336
+ - **The interactive config wizard can go backward.** Model, embedding, OCR, and
337
+ final review screens expose explicit Back rows; returning to a stage restores
338
+ its pre-stage checkpoint, and typed model prompts accept `back`, `b`, `no`, or
339
+ `n` instead of accidentally saving `ollama/n`.
340
+
341
+
342
+ - **Discarding config is terminal and interruption is ordinary.** Choosing
343
+ discard no longer opens the shell-completion prompt after saying "Not saved";
344
+ Ctrl-C or EOF at any Click prompt exits 130 instead of showing the internal-bug
345
+ screen.
346
+
347
+ - **`auth login` now connects every provider, not just ChatGPT.** Pick
348
+ from the full list - OpenAI appears twice because it really is two
349
+ wires (API key vs ChatGPT login, and the login wire has no
350
+ embeddings) - paste your key at a masked prompt after the create-a-key
351
+ URL, and it validates live before storing (with an honest
352
+ "store anyway - the provider may be having a bad minute" escape).
353
+ Keys live at `~/.local/share/smartpipe/auth.json`, owner-only
354
+ permissions from the first byte, masked everywhere they surface, and
355
+ the environment variable always wins. `auth list` shows what's
356
+ connected and which source is live; `auth logout` removes.
357
+ - **Setup walks three questions in order: text model, embeddings,
358
+ document OCR.** Every stage shows every provider - connected ones
359
+ badged, unconnected ones connectable inline without leaving the flow.
360
+ The embedding stage only lists wires that embed; OCR is optional and
361
+ skippable in one keypress. At the end, one consented verification
362
+ pass (~5 tiny requests) probes what your models can actually do -
363
+ and if the basic text check fails, smartpipe reports a setup fault
364
+ instead of pretending your model lacks modalities. Results feed the
365
+ capability chips you see in every picker from then on, alongside a
366
+ public model registry and your own declarations for self-hosted
367
+ models.
368
+
259
369
  - **The schema workshop.** `smartpipe schema` with no arguments at a
260
370
  terminal opens a small interactive draft loop - your schema pinned up
261
371
  top as colored braces, commands scrolling below: `/add name type`,
@@ -276,7 +386,26 @@ The identity release.
276
386
  overwrites one you chose yourself), and one y/N question adds a backup
277
387
  `fallback-model` for provider outages. After a `doctor --probe`,
278
388
  catalog entries carry capability chips (`sees, hears - probed 2d ago`)
279
- - probed facts, never claims. All the setter subcommands still work.
389
+ - probed facts, never claims.
390
+ - **`smartpipe use` - setup is one word now.** `use gemini` (or
391
+ `use claude-opus-4-8`, `use ollama/qwen3:8b`) stamps a coherent bundle
392
+ in one shot: the model, its paired embedder, and the captions posture,
393
+ each line disclosed with a ✓ and a reason. No credential for the named
394
+ provider = a clean refusal that names the exact `auth login` command,
395
+ nothing stamped. Bare `use` opens the interactive flow. `smartpipe
396
+ using` answers "what am I running?" with every setting, its value, and
397
+ WHERE it came from (flag, env, config file, default) in one aligned
398
+ grid. The config.toml you get is signed by its door -
399
+ `# stamped by: smartpipe use (2026-07-10T06:38Z)` - so a mystery
400
+ config explains itself. The old setter subcommands (`config model`,
401
+ `config embed-model`, …) and profiles are gone; an old config with
402
+ profile keys loads with one warning and cleans itself on the next
403
+ save.
404
+ - **The no-model dead end offers a hand.** At a real terminal, the
405
+ no-model error now ends with `run setup now? [Y/n]` - accept, walk the
406
+ same setup flow, and it closes with "saved - rerun your command".
407
+ Scripts and CI see byte-identical output to before (the offer is
408
+ TTY-gated), and the exit code stays honest.
280
409
 
281
410
  ### Getting it and keeping it current
282
411
  - **One-line install on every platform.**
@@ -7,5 +7,5 @@ authors:
7
7
  given-names: Prabal
8
8
  repository-code: "https://github.com/prabal-rje/smartpipe"
9
9
  license: Apache-2.0
10
- version: 1.4.0rc2
10
+ version: 1.4.0rc4
11
11
  date-released: '2026-07-08'
@@ -9,7 +9,7 @@ Requires [uv](https://docs.astral.sh/uv/) and Python ≥ 3.11 (uv can fetch one
9
9
 
10
10
  ```console
11
11
  $ git clone https://github.com/prabal-rje/smartpipe && cd smartpipe
12
- $ uv sync --all-extras # creates .venv with dev + optional deps
12
+ $ uv sync --all-extras # creates .venv with the project and dev tools
13
13
  $ uv run smartpipe # welcome screen = working install
14
14
  ```
15
15
 
@@ -64,12 +64,13 @@ Reverting to built-in search is emptying the three values again.
64
64
 
65
65
  ## New dependencies
66
66
 
67
- Core install weight is a feature: the runtime dependency list is `click`, `httpx`,
68
- `jsonschema`, `tomli-w` a snapshot test guards it. Anything heavier goes behind an
69
- optional extra, and heavy imports stay function-local (startup time is budgeted).
67
+ Core install weight is a feature, but D46 deliberately ships the complete
68
+ multimodal surface in core: there are no optional extras. The frozen dependency
69
+ snapshot makes every direct or transitive addition an explicit review decision.
70
+ Heavy imports stay function-local so startup remains budgeted.
70
71
 
71
72
  **New heavy import? Function-local or justify.** `--help` must never import
72
- `httpx`, `jsonschema`, `anthropic`, or `markitdown` —
73
+ `httpx`, `jsonschema`, `anthropic`, `markitdown`, or `rich` —
73
74
  `tests/test_startup_imports.py` is the enforcement (it runs `-X importtime` and
74
75
  fails on any banned module). `make startup` gives an advisory wall-clock number;
75
76
  the import test is the deterministic gate.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartpipe-cli
3
- Version: 1.4.0rc2
3
+ Version: 1.4.0rc4
4
4
  Summary: Semantic pipes and queries for your terminal - PDFs, images, audio, video, and text through Unix verbs that understand.
5
5
  Project-URL: Homepage, https://github.com/prabal-rje/smartpipe
6
6
  Project-URL: Changelog, https://github.com/prabal-rje/smartpipe/blob/main/CHANGELOG.md
@@ -32,6 +32,7 @@ Requires-Dist: matplotlib>=3.8
32
32
  Requires-Dist: pdfminer-six>=20231228
33
33
  Requires-Dist: plotext>=5
34
34
  Requires-Dist: pypdf>=5.0
35
+ Requires-Dist: rich>=13.9
35
36
  Requires-Dist: tomli-w>=1.0
36
37
  Description-Content-Type: text/markdown
37
38
 
@@ -48,9 +49,9 @@ Description-Content-Type: text/markdown
48
49
  Run PDFs, images, audio, video, and text through Unix verbs that understand
49
50
  their input.
50
51
 
51
- [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v3.gif)](https://prabal-rje.github.io/smartpipe/demo/)
52
+ [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v5.gif)](https://prabal-rje.github.io/smartpipe/demo/)
52
53
 
53
- *[▶ Watch the full 70-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
54
+ *[▶ Watch the full 86-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
54
55
 
55
56
  ## Install
56
57
 
@@ -92,7 +93,7 @@ and runs that tool's own upgrade.
92
93
  smartpipe auth login
93
94
  ```
94
95
 
95
- No ChatGPT plan? Use local [Ollama][ollama] or a cloud API key - see
96
+ No ChatGPT plan? Bring a cloud API key, or run local [Ollama][ollama] - see
96
97
  [Models & providers][models].
97
98
 
98
99
  ## Examples
@@ -139,6 +140,7 @@ into ordinary Unix tools. Every verb is documented at
139
140
  | [`distinct`][distinct] | fold near-duplicates; `--exact` is free | `sort -u`, by meaning |
140
141
  | [`diff`][diff] | what distinguishes two sets | the post-incident answer |
141
142
  | [`outliers`][outliers] | the items least like the rest | novelty, surfaced |
143
+ | [`graph`][graph] | corpus → entity/relationship graph; `--fast` is free | the case wall, with citations |
142
144
 
143
145
  **Free verbs** never call a model. Run them first to cut the corpus before any
144
146
  paid stage:
@@ -154,15 +156,16 @@ paid stage:
154
156
  | [`chart`][cli] | terminal bars, SVG, facets, time series | quick plots |
155
157
 
156
158
  Some semantic verbs have a **conditionally free mode**: `join --on` (key
157
- equality, no prompt), `distinct --exact` (hash-only folding), `map`/`extend`
158
- `--dry-run` (compose without sending), and `smartpipe schema` with a
159
- braces/DSL expression. Each stays at zero model calls by construction.
159
+ equality, no prompt), `distinct --exact` (hash-only folding), `graph --fast`
160
+ (local NER, on-device), `map`/`extend` `--dry-run` (compose without sending),
161
+ and `smartpipe schema` with a braces/DSL expression. Each stays at zero model
162
+ calls by construction.
160
163
 
161
164
  ## A one-minute tour
162
165
 
163
166
  ```bash
164
167
  # 1. point smartpipe at a model (ChatGPT login, a cloud key, or local Ollama)
165
- smartpipe config
168
+ smartpipe use
166
169
 
167
170
  # 2. ask one question across a folder of mixed documents
168
171
  smartpipe map "What does this say about pricing?" 'docs/*.pdf'
@@ -192,6 +195,9 @@ smartpipe map "Extract {vendor string, invoice_number string, total number}" 'in
192
195
  # 8. video RAG, no vector database: index a folder of recordings once, ask any day
193
196
  smartpipe embed 'sessions/**/*.mp4' > sessions.embeddings
194
197
  smartpipe top_k 3 --near "user gives up after the coupon fails" < sessions.embeddings
198
+
199
+ # 9. the corpus as a knowledge graph - $0: local NER, zero model calls
200
+ smartpipe graph --fast 'case-files/*.md' --save case.html
195
201
  ```
196
202
 
197
203
  A `.txt` on a pipe arrives one item per line; `--as file` treats the whole
@@ -206,6 +212,18 @@ Numbers 7 and 8 are full recipes -
206
212
  New to this? The [Learn track][quickstart] starts at zero and assumes nothing, including
207
213
  what a "model" is.
208
214
 
215
+ ### Highlight: the knowledge graph
216
+
217
+ Number 9 is new: `graph --fast` turns a folder of mixed files into an
218
+ interactive, **cited** knowledge graph without a single model call - a local
219
+ NER model finds the entities you name, co-occurrence weights the edges, and
220
+ hovering any edge shows the files behind it. A focus prompt upgrades the
221
+ strongest edges to model-read relations. Full story:
222
+ [the `graph` page](https://prabal-rje.github.io/smartpipe/verbs/graph/) and
223
+ [the cookbook recipe](docs/cookbook/knowledge-graph.md).
224
+
225
+ ![smartpipe graph --save case.html: an interactive knowledge graph with per-edge source citations](docs/assets/graph-hero.png)
226
+
209
227
  ## Try it on real files
210
228
 
211
229
  No corpus handy? [smartpipe-playground][playground] ships 26 MB of CC0 /
@@ -213,8 +231,8 @@ public-domain practice files - invoices, reports, photos, recordings, screen
213
231
  sessions, and JSONL data:
214
232
 
215
233
  ```bash
216
- curl -L https://github.com/prabal-rje/smartpipe-playground/archive/refs/tags/v1.tar.gz | tar xz
217
- cd smartpipe-playground-1
234
+ curl -L https://github.com/prabal-rje/smartpipe-playground/releases/download/v1/smartpipe-playground-v1.tar.gz | tar xz
235
+ cd smartpipe-playground
218
236
 
219
237
  smartpipe map "Extract {vendor, invoice_number, total number}" 'invoices/*.pdf'
220
238
  smartpipe filter "the customer sounds frustrated" 'recordings/*.mp3'
@@ -236,9 +254,11 @@ For chat, [Ollama][ollama] runs models on your machine. Any cloud model sends
236
254
  that run's data to its provider - `gpt-5.4-mini`, `claude-opus-4-8`,
237
255
  `gemini-3.1-flash-lite`, `mistral-large-latest`, `openrouter/…`.
238
256
 
239
- API keys come from environment variables and are never stored. ChatGPT
240
- subscribers can run `smartpipe auth login` instead. `smartpipe usage` keeps
241
- local run and token totals; see [Privacy & security][privacy] for the details.
257
+ API keys come from environment variables, or `smartpipe auth login` stores
258
+ one securely for you. ChatGPT subscribers can log in instead of using a key.
259
+ `smartpipe usage` keeps local run and token totals; see
260
+ [Privacy & security][privacy] for where credentials live and how to remove
261
+ them.
242
262
 
243
263
  ## Unix behavior
244
264
 
@@ -257,7 +277,7 @@ Full docs: **[prabal-rje.github.io/smartpipe][docs]**.
257
277
  - [Install][install] - packages and platforms
258
278
  - [Working with files & media][files] - PDFs, scans, images, audio, video
259
279
  - [CLI reference][cli] - every flag, format, and exit code
260
- - [Models & providers][models] - local Ollama, cloud keys, ChatGPT login
280
+ - [Models & providers][models] - ChatGPT login, cloud keys, local Ollama
261
281
  - [Privacy & security][privacy]
262
282
 
263
283
  ## How to cite
@@ -303,6 +323,7 @@ lives in [`qa/`](qa/README.md). The CLI surface is a SemVer contract.
303
323
  [distinct]: https://prabal-rje.github.io/smartpipe/verbs/distinct/
304
324
  [diff]: https://prabal-rje.github.io/smartpipe/verbs/diff/
305
325
  [outliers]: https://prabal-rje.github.io/smartpipe/verbs/outliers/
326
+ [graph]: https://prabal-rje.github.io/smartpipe/verbs/graph/
306
327
  [where]: https://prabal-rje.github.io/smartpipe/verbs/where/
307
328
  [summarize]: https://prabal-rje.github.io/smartpipe/verbs/summarize/
308
329
  [sort]: https://prabal-rje.github.io/smartpipe/verbs/sort/
@@ -11,9 +11,9 @@
11
11
  Run PDFs, images, audio, video, and text through Unix verbs that understand
12
12
  their input.
13
13
 
14
- [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v3.gif)](https://prabal-rje.github.io/smartpipe/demo/)
14
+ [![smartpipe demo - click to play with sound and controls](https://github.com/prabal-rje/smartpipe/releases/download/demo-assets/smartpipe-teaser-v5.gif)](https://prabal-rje.github.io/smartpipe/demo/)
15
15
 
16
- *[▶ Watch the full 70-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
16
+ *[▶ Watch the full 86-second demo](https://prabal-rje.github.io/smartpipe/demo/) - sound, controls, no download.*
17
17
 
18
18
  ## Install
19
19
 
@@ -55,7 +55,7 @@ and runs that tool's own upgrade.
55
55
  smartpipe auth login
56
56
  ```
57
57
 
58
- No ChatGPT plan? Use local [Ollama][ollama] or a cloud API key - see
58
+ No ChatGPT plan? Bring a cloud API key, or run local [Ollama][ollama] - see
59
59
  [Models & providers][models].
60
60
 
61
61
  ## Examples
@@ -102,6 +102,7 @@ into ordinary Unix tools. Every verb is documented at
102
102
  | [`distinct`][distinct] | fold near-duplicates; `--exact` is free | `sort -u`, by meaning |
103
103
  | [`diff`][diff] | what distinguishes two sets | the post-incident answer |
104
104
  | [`outliers`][outliers] | the items least like the rest | novelty, surfaced |
105
+ | [`graph`][graph] | corpus → entity/relationship graph; `--fast` is free | the case wall, with citations |
105
106
 
106
107
  **Free verbs** never call a model. Run them first to cut the corpus before any
107
108
  paid stage:
@@ -117,15 +118,16 @@ paid stage:
117
118
  | [`chart`][cli] | terminal bars, SVG, facets, time series | quick plots |
118
119
 
119
120
  Some semantic verbs have a **conditionally free mode**: `join --on` (key
120
- equality, no prompt), `distinct --exact` (hash-only folding), `map`/`extend`
121
- `--dry-run` (compose without sending), and `smartpipe schema` with a
122
- braces/DSL expression. Each stays at zero model calls by construction.
121
+ equality, no prompt), `distinct --exact` (hash-only folding), `graph --fast`
122
+ (local NER, on-device), `map`/`extend` `--dry-run` (compose without sending),
123
+ and `smartpipe schema` with a braces/DSL expression. Each stays at zero model
124
+ calls by construction.
123
125
 
124
126
  ## A one-minute tour
125
127
 
126
128
  ```bash
127
129
  # 1. point smartpipe at a model (ChatGPT login, a cloud key, or local Ollama)
128
- smartpipe config
130
+ smartpipe use
129
131
 
130
132
  # 2. ask one question across a folder of mixed documents
131
133
  smartpipe map "What does this say about pricing?" 'docs/*.pdf'
@@ -155,6 +157,9 @@ smartpipe map "Extract {vendor string, invoice_number string, total number}" 'in
155
157
  # 8. video RAG, no vector database: index a folder of recordings once, ask any day
156
158
  smartpipe embed 'sessions/**/*.mp4' > sessions.embeddings
157
159
  smartpipe top_k 3 --near "user gives up after the coupon fails" < sessions.embeddings
160
+
161
+ # 9. the corpus as a knowledge graph - $0: local NER, zero model calls
162
+ smartpipe graph --fast 'case-files/*.md' --save case.html
158
163
  ```
159
164
 
160
165
  A `.txt` on a pipe arrives one item per line; `--as file` treats the whole
@@ -169,6 +174,18 @@ Numbers 7 and 8 are full recipes -
169
174
  New to this? The [Learn track][quickstart] starts at zero and assumes nothing, including
170
175
  what a "model" is.
171
176
 
177
+ ### Highlight: the knowledge graph
178
+
179
+ Number 9 is new: `graph --fast` turns a folder of mixed files into an
180
+ interactive, **cited** knowledge graph without a single model call - a local
181
+ NER model finds the entities you name, co-occurrence weights the edges, and
182
+ hovering any edge shows the files behind it. A focus prompt upgrades the
183
+ strongest edges to model-read relations. Full story:
184
+ [the `graph` page](https://prabal-rje.github.io/smartpipe/verbs/graph/) and
185
+ [the cookbook recipe](docs/cookbook/knowledge-graph.md).
186
+
187
+ ![smartpipe graph --save case.html: an interactive knowledge graph with per-edge source citations](docs/assets/graph-hero.png)
188
+
172
189
  ## Try it on real files
173
190
 
174
191
  No corpus handy? [smartpipe-playground][playground] ships 26 MB of CC0 /
@@ -176,8 +193,8 @@ public-domain practice files - invoices, reports, photos, recordings, screen
176
193
  sessions, and JSONL data:
177
194
 
178
195
  ```bash
179
- curl -L https://github.com/prabal-rje/smartpipe-playground/archive/refs/tags/v1.tar.gz | tar xz
180
- cd smartpipe-playground-1
196
+ curl -L https://github.com/prabal-rje/smartpipe-playground/releases/download/v1/smartpipe-playground-v1.tar.gz | tar xz
197
+ cd smartpipe-playground
181
198
 
182
199
  smartpipe map "Extract {vendor, invoice_number, total number}" 'invoices/*.pdf'
183
200
  smartpipe filter "the customer sounds frustrated" 'recordings/*.mp3'
@@ -199,9 +216,11 @@ For chat, [Ollama][ollama] runs models on your machine. Any cloud model sends
199
216
  that run's data to its provider - `gpt-5.4-mini`, `claude-opus-4-8`,
200
217
  `gemini-3.1-flash-lite`, `mistral-large-latest`, `openrouter/…`.
201
218
 
202
- API keys come from environment variables and are never stored. ChatGPT
203
- subscribers can run `smartpipe auth login` instead. `smartpipe usage` keeps
204
- local run and token totals; see [Privacy & security][privacy] for the details.
219
+ API keys come from environment variables, or `smartpipe auth login` stores
220
+ one securely for you. ChatGPT subscribers can log in instead of using a key.
221
+ `smartpipe usage` keeps local run and token totals; see
222
+ [Privacy & security][privacy] for where credentials live and how to remove
223
+ them.
205
224
 
206
225
  ## Unix behavior
207
226
 
@@ -220,7 +239,7 @@ Full docs: **[prabal-rje.github.io/smartpipe][docs]**.
220
239
  - [Install][install] - packages and platforms
221
240
  - [Working with files & media][files] - PDFs, scans, images, audio, video
222
241
  - [CLI reference][cli] - every flag, format, and exit code
223
- - [Models & providers][models] - local Ollama, cloud keys, ChatGPT login
242
+ - [Models & providers][models] - ChatGPT login, cloud keys, local Ollama
224
243
  - [Privacy & security][privacy]
225
244
 
226
245
  ## How to cite
@@ -266,6 +285,7 @@ lives in [`qa/`](qa/README.md). The CLI surface is a SemVer contract.
266
285
  [distinct]: https://prabal-rje.github.io/smartpipe/verbs/distinct/
267
286
  [diff]: https://prabal-rje.github.io/smartpipe/verbs/diff/
268
287
  [outliers]: https://prabal-rje.github.io/smartpipe/verbs/outliers/
288
+ [graph]: https://prabal-rje.github.io/smartpipe/verbs/graph/
269
289
  [where]: https://prabal-rje.github.io/smartpipe/verbs/where/
270
290
  [summarize]: https://prabal-rje.github.io/smartpipe/verbs/summarize/
271
291
  [sort]: https://prabal-rje.github.io/smartpipe/verbs/sort/
@@ -0,0 +1,23 @@
1
+ # smartpipe demo video
2
+
3
+ A self-contained [Remotion](https://remotion.dev) project that renders the
4
+ 86-second smartpipe demo (1920x1080, 30 fps): eight scenes - cold open, the
5
+ hook, multimodal, cost honesty, index, search, graph, close - all driven by
6
+ one reusable `<Terminal>` component and the frame-math constants in
7
+ `src/config.ts` (tune scene lengths there). Run `npm install` once, then
8
+ `npm run studio` to preview in the browser or `npm run render` to produce
9
+ `out/smartpipe-demo.mp4`; each scene is also registered as its own
10
+ composition (`ColdOpen`, `Hook`, `Multimodal`, `CostHonesty`, `ScaleA`,
11
+ `ScaleB`, `Graph`, `Close`), so `npx remotion render Hook out/hook.mp4`
12
+ re-renders one scene independently. The narrated cut is the `MainNarrated`
13
+ composition: the script text lives in `src/narration/lines.json`, and
14
+ `RIME_API_KEY=... node scripts/fetch-narration.mjs` synthesizes the
15
+ voiceover wavs (Rime.AI, speaker cupola) into the gitignored
16
+ `public/narration/` and refreshes `src/narration/durations.json` - fetch
17
+ before rendering `MainNarrated`. The music bed is
18
+ `public/silicon-prism-waltz.m4a` (60 s, looped over the 86 s cut with a
19
+ fade-out, held far below the voice); if you ever need a
20
+ no-strings-attached replacement, `node scripts/make-music.mjs` (ffmpeg
21
+ required) synthesizes an original ambient track from scratch into
22
+ `public/music.m4a` - royalty-free by construction - and you can point the
23
+ `<Audio>` element in `src/Main.tsx` at it.
@@ -5,22 +5,34 @@ import { Background } from "./components/Background";
5
5
  import { Close } from "./scenes/Close";
6
6
  import { ColdOpen } from "./scenes/ColdOpen";
7
7
  import { CostHonesty } from "./scenes/CostHonesty";
8
+ import { Graph } from "./scenes/Graph";
8
9
  import { Hook } from "./scenes/Hook";
9
10
  import { Multimodal } from "./scenes/Multimodal";
10
- import { Scale } from "./scenes/Scale";
11
+ import { ScaleA } from "./scenes/ScaleA";
12
+ import { ScaleB } from "./scenes/ScaleB";
13
+ import { duckFactor, Narration } from "./Narration";
11
14
 
12
- /** The full ~70s cut: one persistent background, six scenes in series. */
13
- export const Main: React.FC = () => {
15
+ /** Music bed base gain. Owner order (2026-07-09): "lower BG volume much
16
+ * more" 0.55 0.14, about −12 dB. Texture, never presence. */
17
+ const MUSIC_BASE = 0.14;
18
+
19
+ export type MainProps = { narrated?: boolean };
20
+
21
+ /** The full 86s cut: one persistent background, eight scenes in series.
22
+ * With `narrated`, the Rime voiceover plays on top, a subtitle band shows
23
+ * the spoken words, and the music ducks a further few dB under speech. */
24
+ export const Main: React.FC<MainProps> = ({ narrated = false }) => {
14
25
  return (
15
26
  <AbsoluteFill>
16
- {/* Music bed: Silicon Prism Waltz (60s, looped to cover the 70s cut).
27
+ {/* Music bed: Silicon Prism Waltz (60s, looped to cover the 86s cut).
17
28
  Volume envelope: quick fade-in, steady bed, fade-out over the close.
18
29
  A fully synthesized fallback lives at scripts/make-music.mjs. */}
19
30
  <Audio
20
31
  loop
21
32
  src={staticFile("silicon-prism-waltz.m4a")}
22
33
  volume={(f) =>
23
- 0.55 *
34
+ MUSIC_BASE *
35
+ (narrated ? duckFactor(f) : 1) *
24
36
  interpolate(
25
37
  f,
26
38
  [0, 36, TOTAL_FRAMES - 96, TOTAL_FRAMES - 8],
@@ -43,13 +55,20 @@ export const Main: React.FC = () => {
43
55
  <Series.Sequence durationInFrames={SCENE.cost}>
44
56
  <CostHonesty />
45
57
  </Series.Sequence>
46
- <Series.Sequence durationInFrames={SCENE.scale}>
47
- <Scale />
58
+ <Series.Sequence durationInFrames={SCENE.scaleA}>
59
+ <ScaleA />
60
+ </Series.Sequence>
61
+ <Series.Sequence durationInFrames={SCENE.scaleB}>
62
+ <ScaleB />
63
+ </Series.Sequence>
64
+ <Series.Sequence durationInFrames={SCENE.graph}>
65
+ <Graph />
48
66
  </Series.Sequence>
49
67
  <Series.Sequence durationInFrames={SCENE.close}>
50
68
  <Close />
51
69
  </Series.Sequence>
52
70
  </Series>
71
+ {narrated ? <Narration /> : null}
53
72
  </AbsoluteFill>
54
73
  );
55
74
  };