create-yss-spec 3.5.2 → 3.5.3

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 (438) hide show
  1. package/package.json +1 -1
  2. package/src/template/asset-runtime.js +3 -1
  3. package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
  4. package/template/.agents/skills/codebase-design/SKILL.md +4 -0
  5. package/template/{.codex/skills/improve-codebase-architecture/SKILL.md → .agents/skills/codebase-design/references/architecture-audit.md} +3 -9
  6. package/template/.agents/skills/frontend-commit/SKILL.md +4 -93
  7. package/template/.agents/skills/git-commit-core/SKILL.md +18 -0
  8. package/template/.agents/skills/java-backend-commit/SKILL.md +4 -96
  9. package/template/.agents/skills/llm-wiki/SKILL.md +12 -13
  10. package/template/.agents/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  11. package/template/.agents/skills/llm-wiki/references/compile.md +21 -114
  12. package/template/.agents/skills/llm-wiki/references/ingest.md +8 -33
  13. package/template/.agents/skills/llm-wiki/references/lint.md +9 -46
  14. package/template/.agents/skills/llm-wiki/references/query.md +9 -18
  15. package/template/.agents/skills/llm-wiki/references/schema.md +56 -29
  16. package/template/.agents/skills/llm-wiki/references/transactions.md +48 -0
  17. package/template/.agents/skills/llm-wiki/references/writing.md +4 -4
  18. package/template/.agents/skills/llm-wiki/scripts/advise.mjs +46 -58
  19. package/template/.agents/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  20. package/template/.agents/skills/llm-wiki/scripts/core.mjs +262 -0
  21. package/template/.agents/skills/llm-wiki/scripts/extract.mjs +35 -18
  22. package/template/.agents/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  23. package/template/.agents/skills/llm-wiki/scripts/feedback.mjs +51 -0
  24. package/template/.agents/skills/llm-wiki/scripts/inventory.mjs +43 -171
  25. package/template/.agents/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  26. package/template/.agents/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  27. package/template/.agents/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  28. package/template/.agents/skills/llm-wiki/scripts/migrate.mjs +51 -0
  29. package/template/.agents/skills/llm-wiki/scripts/query.mjs +149 -0
  30. package/template/.agents/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  31. package/template/.agents/skills/llm-wiki/scripts/sources.mjs +166 -0
  32. package/template/.agents/skills/llm-wiki/scripts/transaction.mjs +384 -0
  33. package/template/.agents/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  34. package/template/.agents/skills/prototype/LOGIC.md +1 -1
  35. package/template/.agents/skills/prototype/SKILL.md +5 -19
  36. package/template/.agents/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  37. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  38. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  39. package/template/.agents/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  40. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +8 -8
  41. package/template/.agents/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  42. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  43. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  44. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  45. package/template/.agents/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  46. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +1 -1
  47. package/template/.agents/skills/yss-research/SKILL.md +4 -0
  48. package/template/.codex/skills/codebase-design/SKILL.md +4 -0
  49. package/template/{.pi/skills/improve-codebase-architecture/SKILL.md → .codex/skills/codebase-design/references/architecture-audit.md} +3 -9
  50. package/template/.codex/skills/frontend-commit/SKILL.md +4 -93
  51. package/template/.codex/skills/git-commit-core/SKILL.md +18 -0
  52. package/template/.codex/skills/java-backend-commit/SKILL.md +4 -96
  53. package/template/.codex/skills/llm-wiki/SKILL.md +12 -13
  54. package/template/.codex/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  55. package/template/.codex/skills/llm-wiki/references/compile.md +21 -114
  56. package/template/.codex/skills/llm-wiki/references/ingest.md +8 -33
  57. package/template/.codex/skills/llm-wiki/references/lint.md +9 -46
  58. package/template/.codex/skills/llm-wiki/references/query.md +9 -18
  59. package/template/.codex/skills/llm-wiki/references/schema.md +56 -29
  60. package/template/.codex/skills/llm-wiki/references/transactions.md +48 -0
  61. package/template/.codex/skills/llm-wiki/references/writing.md +4 -4
  62. package/template/.codex/skills/llm-wiki/scripts/advise.mjs +46 -58
  63. package/template/.codex/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  64. package/template/.codex/skills/llm-wiki/scripts/core.mjs +262 -0
  65. package/template/.codex/skills/llm-wiki/scripts/extract.mjs +35 -18
  66. package/template/.codex/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  67. package/template/.codex/skills/llm-wiki/scripts/feedback.mjs +51 -0
  68. package/template/.codex/skills/llm-wiki/scripts/inventory.mjs +43 -171
  69. package/template/.codex/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  70. package/template/.codex/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  71. package/template/.codex/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  72. package/template/.codex/skills/llm-wiki/scripts/migrate.mjs +51 -0
  73. package/template/.codex/skills/llm-wiki/scripts/query.mjs +149 -0
  74. package/template/.codex/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  75. package/template/.codex/skills/llm-wiki/scripts/sources.mjs +166 -0
  76. package/template/.codex/skills/llm-wiki/scripts/transaction.mjs +384 -0
  77. package/template/.codex/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  78. package/template/.codex/skills/prototype/LOGIC.md +1 -1
  79. package/template/.codex/skills/prototype/SKILL.md +5 -19
  80. package/template/.codex/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  81. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  82. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  83. package/template/.codex/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  84. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +8 -8
  85. package/template/.codex/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  86. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  87. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  88. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  89. package/template/.codex/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  90. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +1 -1
  91. package/template/.codex/skills/yss-research/SKILL.md +4 -0
  92. package/template/.cursor/skills/codebase-design/SKILL.md +4 -0
  93. package/template/.cursor/skills/{improve-codebase-architecture/SKILL.md → codebase-design/references/architecture-audit.md} +3 -9
  94. package/template/.cursor/skills/frontend-commit/SKILL.md +4 -93
  95. package/template/.cursor/skills/git-commit-core/SKILL.md +18 -0
  96. package/template/.cursor/skills/java-backend-commit/SKILL.md +4 -96
  97. package/template/.cursor/skills/llm-wiki/SKILL.md +12 -13
  98. package/template/.cursor/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  99. package/template/.cursor/skills/llm-wiki/references/compile.md +21 -114
  100. package/template/.cursor/skills/llm-wiki/references/ingest.md +8 -33
  101. package/template/.cursor/skills/llm-wiki/references/lint.md +9 -46
  102. package/template/.cursor/skills/llm-wiki/references/query.md +9 -18
  103. package/template/.cursor/skills/llm-wiki/references/schema.md +56 -29
  104. package/template/.cursor/skills/llm-wiki/references/transactions.md +48 -0
  105. package/template/.cursor/skills/llm-wiki/references/writing.md +4 -4
  106. package/template/.cursor/skills/llm-wiki/scripts/advise.mjs +46 -58
  107. package/template/.cursor/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  108. package/template/.cursor/skills/llm-wiki/scripts/core.mjs +262 -0
  109. package/template/.cursor/skills/llm-wiki/scripts/extract.mjs +35 -18
  110. package/template/.cursor/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  111. package/template/.cursor/skills/llm-wiki/scripts/feedback.mjs +51 -0
  112. package/template/.cursor/skills/llm-wiki/scripts/inventory.mjs +43 -171
  113. package/template/.cursor/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  114. package/template/.cursor/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  115. package/template/.cursor/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  116. package/template/.cursor/skills/llm-wiki/scripts/migrate.mjs +51 -0
  117. package/template/.cursor/skills/llm-wiki/scripts/query.mjs +149 -0
  118. package/template/.cursor/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  119. package/template/.cursor/skills/llm-wiki/scripts/sources.mjs +166 -0
  120. package/template/.cursor/skills/llm-wiki/scripts/transaction.mjs +384 -0
  121. package/template/.cursor/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  122. package/template/.cursor/skills/prototype/LOGIC.md +1 -1
  123. package/template/.cursor/skills/prototype/SKILL.md +5 -19
  124. package/template/.cursor/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  125. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  126. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  127. package/template/.cursor/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  128. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +8 -8
  129. package/template/.cursor/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  130. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  131. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  132. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  133. package/template/.cursor/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  134. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +1 -1
  135. package/template/.cursor/skills/yss-research/SKILL.md +4 -0
  136. package/template/.pi/skills/codebase-design/SKILL.md +4 -0
  137. package/template/{.agents/skills/improve-codebase-architecture/SKILL.md → .pi/skills/codebase-design/references/architecture-audit.md} +3 -9
  138. package/template/.pi/skills/frontend-commit/SKILL.md +4 -93
  139. package/template/.pi/skills/git-commit-core/SKILL.md +18 -0
  140. package/template/.pi/skills/java-backend-commit/SKILL.md +4 -96
  141. package/template/.pi/skills/llm-wiki/SKILL.md +12 -13
  142. package/template/.pi/skills/llm-wiki/assets/CLAUDE.md.template +7 -1
  143. package/template/.pi/skills/llm-wiki/references/compile.md +21 -114
  144. package/template/.pi/skills/llm-wiki/references/ingest.md +8 -33
  145. package/template/.pi/skills/llm-wiki/references/lint.md +9 -46
  146. package/template/.pi/skills/llm-wiki/references/query.md +9 -18
  147. package/template/.pi/skills/llm-wiki/references/schema.md +56 -29
  148. package/template/.pi/skills/llm-wiki/references/transactions.md +48 -0
  149. package/template/.pi/skills/llm-wiki/references/writing.md +4 -4
  150. package/template/.pi/skills/llm-wiki/scripts/advise.mjs +46 -58
  151. package/template/.pi/skills/llm-wiki/scripts/advise.test.mjs +11 -16
  152. package/template/.pi/skills/llm-wiki/scripts/core.mjs +262 -0
  153. package/template/.pi/skills/llm-wiki/scripts/extract.mjs +35 -18
  154. package/template/.pi/skills/llm-wiki/scripts/extract.test.mjs +5 -8
  155. package/template/.pi/skills/llm-wiki/scripts/feedback.mjs +51 -0
  156. package/template/.pi/skills/llm-wiki/scripts/inventory.mjs +43 -171
  157. package/template/.pi/skills/llm-wiki/scripts/inventory.test.mjs +25 -18
  158. package/template/.pi/skills/llm-wiki/scripts/lint-wikilinks.mjs +69 -92
  159. package/template/.pi/skills/llm-wiki/scripts/lint-wikilinks.test.mjs +25 -37
  160. package/template/.pi/skills/llm-wiki/scripts/migrate.mjs +51 -0
  161. package/template/.pi/skills/llm-wiki/scripts/query.mjs +149 -0
  162. package/template/.pi/skills/llm-wiki/scripts/regressions.test.mjs +101 -0
  163. package/template/.pi/skills/llm-wiki/scripts/sources.mjs +166 -0
  164. package/template/.pi/skills/llm-wiki/scripts/transaction.mjs +384 -0
  165. package/template/.pi/skills/llm-wiki/scripts/v2.test.mjs +354 -0
  166. package/template/.pi/skills/prototype/LOGIC.md +1 -1
  167. package/template/.pi/skills/prototype/SKILL.md +5 -19
  168. package/template/.pi/skills/setup-matt-pocock-skills/SKILL.md +3 -3
  169. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -0
  170. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +2 -3
  171. package/template/.pi/skills/yss-implementation-contract-compiler/references/yss-skill-execution-result.md +14 -0
  172. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +8 -8
  173. package/template/.pi/skills/yss-product-lifecycle/references/external-input-questionnaire.md +19 -0
  174. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +5 -5
  175. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +20 -4
  176. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +2 -2
  177. package/template/.pi/skills/yss-product-lifecycle/references/plan-requirements.md +10 -0
  178. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +1 -1
  179. package/template/.pi/skills/yss-research/SKILL.md +4 -0
  180. package/template/.template-spec/agents/README.md +1 -1
  181. package/template/.template-spec/agents/digital-human-roles.yaml +1 -1
  182. package/template/.template-spec/agents/skill-migrations.md +15 -0
  183. package/template/.template-spec/agents/yss-skill-registry.yaml +10 -29
  184. package/template/.template-spec/architecture/README.md +3 -34
  185. package/template/.template-spec/plan/templates/competitive-analysis-template.md +2 -2
  186. package/template/.template-spec/process/contract-reading.md +24 -0
  187. package/template/.template-spec/process/lifecycle-registry-baseline.json +3 -1
  188. package/template/.template-spec/process/lifecycle-registry.yaml +6 -0
  189. package/template/.template-spec/process/research-completion.md +23 -0
  190. package/template/.template-spec/process/schemas/digital-human-task-package.schema.json +202 -12
  191. package/template/.template-spec/process/schemas/frontend-implementation-evidence.schema.json +7 -15
  192. package/template/.template-spec/process/subagent-collaboration.md +8 -0
  193. package/template/.template-spec/process/templates/frontend-implementation-verification-template.yaml +15 -1
  194. package/template/AGENTS.md +1 -1
  195. package/template/CONTEXT.md +5 -1
  196. package/template/README.md +12 -24
  197. package/template/scripts/contract +5 -5
  198. package/template/scripts/lib/contract-views.mjs +57 -2
  199. package/template/scripts/lib/execution-evidence.mjs +51 -0
  200. package/template/scripts/lib/harness-execution-scope.mjs +1 -1
  201. package/template/scripts/lib/implementation-contract-compiler.mjs +2 -0
  202. package/template/scripts/lib/lifecycle-context-query.mjs +15 -3
  203. package/template/scripts/lib/lifecycle-status.mjs +32 -6
  204. package/template/scripts/lib/lifecycle-transition.mjs +19 -1
  205. package/template/scripts/lib/maintenance-research.mjs +63 -0
  206. package/template/scripts/lib/read-only-intake.mjs +132 -0
  207. package/template/scripts/lib/skill-registry.mjs +2 -1
  208. package/template/scripts/lib/skill-supply-chain.mjs +4 -0
  209. package/template/scripts/lib/slice-task-package.mjs +1 -1
  210. package/template/scripts/lib/task-package.mjs +9 -2
  211. package/template/scripts/lifecycle-status +2 -2
  212. package/template/scripts/prepare-read-only-intake +16 -0
  213. package/template/scripts/run-read-only-intake +14 -0
  214. package/template/scripts/verify-digital-human-task-package +2 -2
  215. package/template/scripts/verify-frontend-implementation-evidence +24 -1
  216. package/template/scripts/verify-maintenance-research +13 -0
  217. package/template/skills-lock.json +19 -76
  218. package/template.manifest.json +118 -29
  219. package/template.snapshot.json +5 -6
  220. package/template/.agents/skills/grill-with-docs/SKILL.md +0 -20
  221. package/template/.agents/skills/grill-with-docs/agents/openai.yaml +0 -5
  222. package/template/.agents/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  223. package/template/.agents/skills/prototype/UI.md +0 -112
  224. package/template/.agents/skills/setup-matt-pocock-skills/domain.md +0 -37
  225. package/template/.agents/skills/to-questionnaire/SKILL.md +0 -55
  226. package/template/.agents/skills/to-questionnaire/agents/openai.yaml +0 -5
  227. package/template/.agents/skills/wait-what/SKILL.md +0 -7
  228. package/template/.agents/skills/wait-what/agents/openai.yaml +0 -5
  229. package/template/.codex/skills/data-analytics/.app.json +0 -84
  230. package/template/.codex/skills/data-analytics/.codex-plugin/plugin.json +0 -66
  231. package/template/.codex/skills/data-analytics/.mcp.json +0 -30
  232. package/template/.codex/skills/data-analytics/AGENTS.md +0 -20
  233. package/template/.codex/skills/data-analytics/DEPENDENCIES.MD +0 -27
  234. package/template/.codex/skills/data-analytics/README.md +0 -60
  235. package/template/.codex/skills/data-analytics/__yss_dotfile__.gitignore +0 -2
  236. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html +0 -16
  237. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part001 +0 -1
  238. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part002 +0 -1
  239. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part003 +0 -1
  240. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part004 +0 -1
  241. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part005 +0 -1
  242. package/template/.codex/skills/data-analytics/assets/datascience-artifact-widget.html.gz.b64.part006 +0 -1
  243. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html +0 -16
  244. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part001 +0 -1
  245. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part002 +0 -1
  246. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part003 +0 -1
  247. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part004 +0 -1
  248. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part005 +0 -1
  249. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part006 +0 -1
  250. package/template/.codex/skills/data-analytics/assets/datascience-chart-widget.html.gz.b64.part007 +0 -1
  251. package/template/.codex/skills/data-analytics/assets/datascience-small.svg +0 -5
  252. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html +0 -16
  253. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part001 +0 -1
  254. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part002 +0 -1
  255. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part003 +0 -1
  256. package/template/.codex/skills/data-analytics/assets/datascience-table-widget.html.gz.b64.part004 +0 -1
  257. package/template/.codex/skills/data-analytics/assets/datascience.png +0 -0
  258. package/template/.codex/skills/data-analytics/assets/datascience.svg +0 -10
  259. package/template/.codex/skills/data-analytics/mcp/server.cjs +0 -2964
  260. package/template/.codex/skills/data-analytics/package-lock.json +0 -3048
  261. package/template/.codex/skills/data-analytics/package.json +0 -43
  262. package/template/.codex/skills/data-analytics/scripts/normalize-widget-assets.mjs +0 -75
  263. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +0 -137
  264. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/agents/openai.yaml +0 -6
  265. package/template/.codex/skills/data-analytics/skills/analyze-data-quality/references/quality-checks.md +0 -29
  266. package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +0 -148
  267. package/template/.codex/skills/data-analytics/skills/build-dashboard/agents/openai.yaml +0 -6
  268. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/bi-platform-dashboard.md +0 -18
  269. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/html-dashboard.md +0 -24
  270. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/mcp-artifact-dashboard.md +0 -71
  271. package/template/.codex/skills/data-analytics/skills/build-dashboard/specifications/streamlit-dashboard.md +0 -85
  272. package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +0 -207
  273. package/template/.codex/skills/data-analytics/skills/build-report/agents/openai.yaml +0 -6
  274. package/template/.codex/skills/data-analytics/skills/build-report/assets/executive-report-shell.html +0 -70
  275. package/template/.codex/skills/data-analytics/skills/build-report/assets/technical-report-shell.html +0 -66
  276. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/SKILL.md +0 -108
  277. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/agents/openai.yaml +0 -6
  278. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/__init__.py +0 -1
  279. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/cli.py +0 -52
  280. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/constants.py +0 -61
  281. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/docx_writer.py +0 -362
  282. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/html_parser.py +0 -829
  283. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/model.py +0 -30
  284. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/plan.py +0 -127
  285. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/quality.py +0 -374
  286. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/rendering.py +0 -613
  287. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/table_utils.py +0 -54
  288. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc/utils.py +0 -16
  289. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/scripts/report_to_google_doc_plan.py +0 -9
  290. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-doc/tests/test_delivery_plan.py +0 -45
  291. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/SKILL.md +0 -77
  292. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/agents/openai.yaml +0 -6
  293. package/template/.codex/skills/data-analytics/skills/build-report/report-to-google-slides/scripts/report_to_google_slides.py +0 -2379
  294. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/SKILL.md +0 -88
  295. package/template/.codex/skills/data-analytics/skills/build-report/report-to-pdf/agents/openai.yaml +0 -6
  296. package/template/.codex/skills/data-analytics/skills/build-report/specifications/executive-report.md +0 -97
  297. package/template/.codex/skills/data-analytics/skills/build-report/specifications/mcp-app-report.md +0 -59
  298. package/template/.codex/skills/data-analytics/skills/build-report/specifications/technical-report.md +0 -75
  299. package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +0 -103
  300. package/template/.codex/skills/data-analytics/skills/design-kpis/agents/openai.yaml +0 -6
  301. package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +0 -68
  302. package/template/.codex/skills/data-analytics/skills/gather-business-context/agents/openai.yaml +0 -6
  303. package/template/.codex/skills/data-analytics/skills/index/SKILL.md +0 -251
  304. package/template/.codex/skills/data-analytics/skills/index/agents/openai.yaml +0 -6
  305. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +0 -131
  306. package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/agents/openai.yaml +0 -6
  307. package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +0 -141
  308. package/template/.codex/skills/data-analytics/skills/kpi-reporting/agents/openai.yaml +0 -6
  309. package/template/.codex/skills/data-analytics/skills/kpi-reporting/references/report-templates.md +0 -32
  310. package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +0 -106
  311. package/template/.codex/skills/data-analytics/skills/market-sizing/agents/openai.yaml +0 -6
  312. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +0 -130
  313. package/template/.codex/skills/data-analytics/skills/metric-diagnostics/agents/openai.yaml +0 -6
  314. package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +0 -141
  315. package/template/.codex/skills/data-analytics/skills/product-business-analysis/agents/openai.yaml +0 -6
  316. package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +0 -178
  317. package/template/.codex/skills/data-analytics/skills/spreadsheets/agents/openai.yaml +0 -9
  318. package/template/.codex/skills/data-analytics/skills/spreadsheets/assets/file-spreadsheet.png +0 -0
  319. package/template/.codex/skills/data-analytics/skills/spreadsheets/charts.md +0 -31
  320. package/template/.codex/skills/data-analytics/skills/spreadsheets/references/artifact_tool_api.md +0 -466
  321. package/template/.codex/skills/data-analytics/skills/spreadsheets/style_guidelines.md +0 -99
  322. package/template/.codex/skills/data-analytics/skills/user-context/SKILL.md +0 -197
  323. package/template/.codex/skills/data-analytics/skills/user-context/agents/openai.yaml +0 -6
  324. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/automation-config.md +0 -26
  325. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/source-category-config.json +0 -51
  326. package/template/.codex/skills/data-analytics/skills/user-context/plugin-author-config/user-context-config.md +0 -66
  327. package/template/.codex/skills/data-analytics/skills/user-context/references/automation.md +0 -69
  328. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-examples.md +0 -204
  329. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding-state-template.json +0 -87
  330. package/template/.codex/skills/data-analytics/skills/user-context/references/onboarding.md +0 -497
  331. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/connector-playbook.md +0 -74
  332. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/setup.md +0 -65
  333. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/skill-template.md +0 -160
  334. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/source-intake.md +0 -75
  335. package/template/.codex/skills/data-analytics/skills/user-context/references/semantic-layer/weekly-polling-automation.md +0 -96
  336. package/template/.codex/skills/data-analytics/skills/user-context/references/source-category-runtime.md +0 -263
  337. package/template/.codex/skills/data-analytics/skills/user-context/scripts/data_analytics_preflight.py +0 -1462
  338. package/template/.codex/skills/data-analytics/skills/user-context/scripts/init_user_context_state.py +0 -128
  339. package/template/.codex/skills/data-analytics/skills/user-context/scripts/reset_user_context_state.py +0 -101
  340. package/template/.codex/skills/data-analytics/skills/user-context/scripts/validate_user_context_preflight.py +0 -499
  341. package/template/.codex/skills/data-analytics/skills/user-context/tests/test_state_helpers.py +0 -978
  342. package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +0 -126
  343. package/template/.codex/skills/data-analytics/skills/validate-data/agents/openai.yaml +0 -6
  344. package/template/.codex/skills/data-analytics/skills/validate-data/references/validation-methods.md +0 -70
  345. package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +0 -157
  346. package/template/.codex/skills/data-analytics/skills/visualize-data/agents/openai.yaml +0 -6
  347. package/template/.codex/skills/data-analytics/skills/visualize-data/references/seaborn-templates.md +0 -774
  348. package/template/.codex/skills/data-analytics/src/DESIGN.md +0 -222
  349. package/template/.codex/skills/data-analytics/src/analytics-app/App.tsx +0 -3666
  350. package/template/.codex/skills/data-analytics/src/analytics-app/analytics-layout.test.mjs +0 -136
  351. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartFrame.tsx +0 -54
  352. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartLegend.tsx +0 -96
  353. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartRenderer.tsx +0 -1647
  354. package/template/.codex/skills/data-analytics/src/analytics-app/charting/ChartTooltip.tsx +0 -245
  355. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-app-helpers.tsx +0 -462
  356. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-capabilities.ts +0 -107
  357. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-compatibility.ts +0 -164
  358. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-contract.ts +0 -192
  359. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-theme.ts +0 -203
  360. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-tokens.css +0 -619
  361. package/template/.codex/skills/data-analytics/src/analytics-app/charting/chart-transforms.ts +0 -402
  362. package/template/.codex/skills/data-analytics/src/analytics-app/fonts/SystemSansVariableVF.woff2 +0 -0
  363. package/template/.codex/skills/data-analytics/src/analytics-app/imageExport.ts +0 -370
  364. package/template/.codex/skills/data-analytics/src/analytics-app/layout/AnalyticsLayoutCanvas.tsx +0 -536
  365. package/template/.codex/skills/data-analytics/src/analytics-app/layout/RichMarkdown.tsx +0 -681
  366. package/template/.codex/skills/data-analytics/src/analytics-app/layout/analyticsLayoutCore.ts +0 -164
  367. package/template/.codex/skills/data-analytics/src/analytics-app/main.tsx +0 -21
  368. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/chart_contract.py +0 -472
  369. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/check_analytics_app_runtime_links.py +0 -75
  370. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/design_contract.py +0 -142
  371. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/package_utils.py +0 -142
  372. package/template/.codex/skills/data-analytics/src/analytics-app/scripts/tests/test_package_utils.py +0 -377
  373. package/template/.codex/skills/data-analytics/src/analytics-app/styles.css +0 -3468
  374. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.d.ts +0 -44
  375. package/template/.codex/skills/data-analytics/src/analytics-app/tables/DataTable.jsx +0 -639
  376. package/template/.codex/skills/data-analytics/src/analytics-app/tables/data-table.css +0 -327
  377. package/template/.codex/skills/data-analytics/src/analytics-app/tokens.css +0 -225
  378. package/template/.codex/skills/data-analytics/src/analytics-app/types.ts +0 -204
  379. package/template/.codex/skills/data-analytics/src/analytics-app-core.md +0 -85
  380. package/template/.codex/skills/data-analytics/src/codex-style-contract.md +0 -30
  381. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.html +0 -12
  382. package/template/.codex/skills/data-analytics/src/datascience-artifact-widget.jsx +0 -1008
  383. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.css +0 -2117
  384. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.html +0 -122
  385. package/template/.codex/skills/data-analytics/src/datascience-chart-widget.js +0 -3588
  386. package/template/.codex/skills/data-analytics/src/datascience-table-widget.css +0 -483
  387. package/template/.codex/skills/data-analytics/src/datascience-table-widget.html +0 -32
  388. package/template/.codex/skills/data-analytics/src/datascience-table-widget.js +0 -333
  389. package/template/.codex/skills/data-analytics/src/mcp-host.js +0 -153
  390. package/template/.codex/skills/data-analytics/src/recharts-config.js +0 -315
  391. package/template/.codex/skills/data-analytics/src/recharts-renderer.jsx +0 -294
  392. package/template/.codex/skills/data-analytics/src/sql-source-view.css +0 -33
  393. package/template/.codex/skills/data-analytics/src/sql-source-view.js +0 -157
  394. package/template/.codex/skills/data-analytics/src/styles/codex-theme.css +0 -121
  395. package/template/.codex/skills/data-analytics/src/table-renderer.jsx +0 -28
  396. package/template/.codex/skills/data-analytics/tests/chart-transforms.test.mjs +0 -87
  397. package/template/.codex/skills/data-analytics/tests/funnel-smoke.html +0 -105
  398. package/template/.codex/skills/data-analytics/tests/inline-widget-compare.html +0 -233
  399. package/template/.codex/skills/data-analytics/tests/mcp-server.test.mjs +0 -1500
  400. package/template/.codex/skills/data-analytics/tests/native-style-contract.test.mjs +0 -219
  401. package/template/.codex/skills/data-analytics/tests/recharts-config.test.mjs +0 -144
  402. package/template/.codex/skills/data-analytics/tests/recharts-renderer.test.mjs +0 -11
  403. package/template/.codex/skills/data-analytics/tests/rich-markdown.test.mjs +0 -54
  404. package/template/.codex/skills/data-analytics/tests/widget-render-harness.html +0 -321
  405. package/template/.codex/skills/data-analytics/tsconfig.json +0 -19
  406. package/template/.codex/skills/data-analytics/vite.config.ts +0 -46
  407. package/template/.codex/skills/grill-with-docs/SKILL.md +0 -20
  408. package/template/.codex/skills/grill-with-docs/agents/openai.yaml +0 -5
  409. package/template/.codex/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  410. package/template/.codex/skills/prototype/UI.md +0 -112
  411. package/template/.codex/skills/setup-matt-pocock-skills/domain.md +0 -37
  412. package/template/.codex/skills/to-questionnaire/SKILL.md +0 -55
  413. package/template/.codex/skills/to-questionnaire/agents/openai.yaml +0 -5
  414. package/template/.codex/skills/wait-what/SKILL.md +0 -7
  415. package/template/.codex/skills/wait-what/agents/openai.yaml +0 -5
  416. package/template/.cursor/skills/grill-with-docs/SKILL.md +0 -20
  417. package/template/.cursor/skills/grill-with-docs/agents/openai.yaml +0 -5
  418. package/template/.cursor/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  419. package/template/.cursor/skills/prototype/UI.md +0 -112
  420. package/template/.cursor/skills/setup-matt-pocock-skills/domain.md +0 -37
  421. package/template/.cursor/skills/to-questionnaire/SKILL.md +0 -55
  422. package/template/.cursor/skills/to-questionnaire/agents/openai.yaml +0 -5
  423. package/template/.cursor/skills/wait-what/SKILL.md +0 -7
  424. package/template/.cursor/skills/wait-what/agents/openai.yaml +0 -5
  425. package/template/.pi/skills/grill-with-docs/SKILL.md +0 -20
  426. package/template/.pi/skills/grill-with-docs/agents/openai.yaml +0 -5
  427. package/template/.pi/skills/improve-codebase-architecture/agents/openai.yaml +0 -5
  428. package/template/.pi/skills/prototype/UI.md +0 -112
  429. package/template/.pi/skills/setup-matt-pocock-skills/domain.md +0 -37
  430. package/template/.pi/skills/to-questionnaire/SKILL.md +0 -55
  431. package/template/.pi/skills/to-questionnaire/agents/openai.yaml +0 -5
  432. package/template/.pi/skills/wait-what/SKILL.md +0 -7
  433. package/template/.pi/skills/wait-what/agents/openai.yaml +0 -5
  434. package/template/.template-spec/agents/domain.md +0 -31
  435. /package/template/.agents/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  436. /package/template/.codex/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  437. /package/template/.cursor/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
  438. /package/template/.pi/skills/{improve-codebase-architecture → codebase-design/references}/HTML-REPORT.md +0 -0
@@ -1,1462 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Read Data Analytics local state and emit a deterministic preflight payload."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- import hashlib
8
- import json
9
- import os
10
- import re
11
- import sys
12
- from datetime import datetime, timezone
13
- from pathlib import Path
14
- from typing import Any
15
-
16
- PLUGIN_ROOT = Path(__file__).resolve().parents[3]
17
- ONBOARDING_REFERENCE = PLUGIN_ROOT / "skills/user-context/references/onboarding.md"
18
- SOURCE_CATEGORY_CONFIG_REFERENCE = (
19
- PLUGIN_ROOT / "skills/user-context/plugin-author-config/source-category-config.json"
20
- )
21
- APP_MANIFEST_REFERENCE = PLUGIN_ROOT / ".app.json"
22
- DEFAULT_MAX_CONTEXT_BYTES = 200_000
23
- CORE_CATEGORY_IDS = ("structured_data", "team_communication", "company_docs")
24
- ONBOARDING_RESOLVED_SOURCE_STATUSES = {
25
- "declined",
26
- "deferred",
27
- "deferred_environment_api_limitations",
28
- "not_applicable",
29
- "skipped",
30
- "skipped_for_now",
31
- "unavailable",
32
- }
33
- SOURCE_CLASSIFIED_STATUSES = {
34
- "active",
35
- "needs_confirmation",
36
- "missing",
37
- *ONBOARDING_RESOLVED_SOURCE_STATUSES,
38
- }
39
- SOURCE_ACTION_REQUIRED_STATUSES = {"needs_confirmation", "missing"}
40
- CORE_SOURCE_EXPLICIT_FALLBACK_RESOLUTIONS = {
41
- "user_continued_with_known_gap",
42
- "user_declined",
43
- "user_deferred",
44
- "user_marked_unavailable",
45
- "user_skipped",
46
- "user_confirmed_not_applicable",
47
- }
48
- SEMANTIC_SETUP_COMPLETE_STATUSES = {
49
- "created",
50
- "refreshed",
51
- "inspected",
52
- "repaired",
53
- "planned",
54
- "skipped",
55
- "deferred",
56
- "unavailable",
57
- "blocked",
58
- }
59
- SEMANTIC_SETUP_TARGET_STATUSES = {"created", "refreshed", "inspected", "repaired", "planned"}
60
- SEMANTIC_REFRESH_COMPLETE_STATUSES = {
61
- "accepted",
62
- "declined",
63
- "deferred",
64
- "unavailable",
65
- "skipped",
66
- "blocked",
67
- }
68
- HERO_PROMPT_COMPLETE_STATUSES = {"tried", "skipped", "deferred", "completed"}
69
- HERO_SKILLS = ("metric-diagnostics", "product-business-analysis", "kpi-reporting")
70
- SOURCE_ROUTING_PREFERENCES_HEADING = "data analytics source routing preferences"
71
-
72
-
73
- def parse_args() -> argparse.Namespace:
74
- parser = argparse.ArgumentParser(
75
- description=(
76
- "Read Data Analytics user-context and onboarding-state files and return "
77
- "context plus workflow control obligations as JSON."
78
- )
79
- )
80
- parser.add_argument("--workflow", default="ordinary")
81
- parser.add_argument(
82
- "--request-mode",
83
- choices=("ordinary_workflow", "direct_onboarding_status", "guided_onboarding_workflow"),
84
- default="ordinary_workflow",
85
- )
86
- parser.add_argument("--codex-home", type=Path, default=None)
87
- parser.add_argument("--state-dir", type=Path, default=None)
88
- parser.add_argument("--max-context-bytes", type=int, default=DEFAULT_MAX_CONTEXT_BYTES)
89
- parser.add_argument("--section", action="append", default=[])
90
- return parser.parse_args()
91
-
92
-
93
- def default_codex_home() -> Path:
94
- env_home = os.environ.get("CODEX_HOME")
95
- if env_home:
96
- return Path(env_home).expanduser()
97
- return Path.home() / ".codex"
98
-
99
-
100
- def state_dir_from_args(args: argparse.Namespace) -> Path:
101
- if args.state_dir:
102
- return args.state_dir.expanduser()
103
- codex_home = args.codex_home.expanduser() if args.codex_home else default_codex_home()
104
- return codex_home / "state/plugins/data-analytics"
105
-
106
-
107
- def sha256_text(text: str) -> str:
108
- return hashlib.sha256(text.encode("utf-8")).hexdigest()
109
-
110
-
111
- def file_mtime(path: Path) -> str | None:
112
- try:
113
- return datetime.fromtimestamp(path.stat().st_mtime, tz=timezone.utc).isoformat()
114
- except OSError:
115
- return None
116
-
117
-
118
- def section_bounds(markdown: str) -> dict[str, tuple[int, int, str]]:
119
- matches = list(re.finditer(r"(?m)^(#{1,6})\s+(.+?)\s*$", markdown))
120
- bounds: dict[str, tuple[int, int, str]] = {}
121
- for index, match in enumerate(matches):
122
- start = match.start()
123
- level = len(match.group(1))
124
- end = len(markdown)
125
- for next_match in matches[index + 1 :]:
126
- if len(next_match.group(1)) <= level:
127
- end = next_match.start()
128
- break
129
- heading = match.group(2).strip()
130
- bounds[heading.casefold()] = (start, end, heading)
131
- return bounds
132
-
133
-
134
- def extract_sections(markdown: str, requested: list[str]) -> list[dict[str, str]]:
135
- if not requested:
136
- return []
137
- bounds = section_bounds(markdown)
138
- sections: list[dict[str, str]] = []
139
- for heading in requested:
140
- bound = bounds.get(heading.casefold())
141
- if not bound:
142
- sections.append({"heading": heading, "status": "missing", "content": ""})
143
- continue
144
- start, end, canonical_heading = bound
145
- sections.append(
146
- {
147
- "heading": canonical_heading,
148
- "status": "present",
149
- "content": markdown[start:end].strip(),
150
- }
151
- )
152
- return sections
153
-
154
-
155
- def normalize_source_name(value: Any) -> str:
156
- return re.sub(r"[^a-z0-9]+", "", str(value or "").casefold())
157
-
158
-
159
- def parse_source_preference_values(raw_value: str) -> list[str]:
160
- return [value.strip() for value in raw_value.split(",") if value.strip()]
161
-
162
-
163
- def extract_saved_source_preferences(
164
- markdown: str | None,
165
- source_category_config: dict[str, dict[str, Any]],
166
- ) -> dict[str, dict[str, list[str]]]:
167
- """Read durable Data Analytics source-routing choices from user-context.md."""
168
- if not markdown:
169
- return {}
170
- bounds = section_bounds(markdown)
171
- source_routing_section = bounds.get(SOURCE_ROUTING_PREFERENCES_HEADING)
172
- if not source_routing_section:
173
- return {}
174
- start, end, _ = source_routing_section
175
- section = markdown[start:end]
176
- preferences: dict[str, dict[str, list[str]]] = {}
177
- current_category: str | None = None
178
- for raw_line in section.splitlines():
179
- line = raw_line.strip()
180
- category_match = re.match(r"^##\s+([a-z0-9_]+)\s*$", line)
181
- if category_match:
182
- category_id = category_match.group(1)
183
- current_category = category_id if category_id in source_category_config else None
184
- continue
185
- if not current_category:
186
- continue
187
- preference_match = re.match(r"^-\s*(Prefer|Avoid):\s*(.*?)\s*$", line)
188
- if not preference_match:
189
- continue
190
- disposition = "preferred" if preference_match.group(1) == "Prefer" else "avoid"
191
- configured_sources = {
192
- normalize_source_name(str(source)): str(source)
193
- for source in preferred_source_routes(source_category_config[current_category])
194
- }
195
- for source_name in parse_source_preference_values(preference_match.group(2)):
196
- configured_source = configured_sources.get(normalize_source_name(source_name))
197
- if not configured_source:
198
- continue
199
- category_preferences = preferences.setdefault(current_category, {})
200
- values = category_preferences.setdefault(disposition, [])
201
- if configured_source not in values:
202
- values.append(configured_source)
203
- return preferences
204
-
205
-
206
- def summarize_user_context(
207
- markdown: str | None,
208
- source_category_config: dict[str, dict[str, Any]],
209
- ) -> dict[str, Any]:
210
- """Return the narrow normalized Data Analytics user-context surface."""
211
- return {
212
- "scope": "source_routing_preferences_and_semantic_layer_registry",
213
- "source_routing_preferences": extract_saved_source_preferences(
214
- markdown,
215
- source_category_config,
216
- ),
217
- "semantic_layer_count": len(semantic_layer_registry(markdown)),
218
- "normalization_complete": markdown is not None,
219
- }
220
-
221
-
222
- def read_text_payload(path: Path, max_context_bytes: int, sections: list[str]) -> dict[str, Any]:
223
- payload: dict[str, Any] = {
224
- "path": str(path),
225
- "status": "missing",
226
- "bytes": 0,
227
- "sha256": None,
228
- "mtime": None,
229
- "content": None,
230
- "sections": [],
231
- "omitted": False,
232
- "error": None,
233
- }
234
- if not path.exists():
235
- return payload
236
- try:
237
- text = path.read_text(encoding="utf-8")
238
- except (OSError, UnicodeDecodeError) as exc:
239
- payload["status"] = "unreadable"
240
- payload["error"] = str(exc)
241
- return payload
242
-
243
- encoded_len = len(text.encode("utf-8"))
244
- payload.update(
245
- {
246
- "status": "present",
247
- "bytes": encoded_len,
248
- "sha256": sha256_text(text),
249
- "mtime": file_mtime(path),
250
- "sections": extract_sections(text, sections),
251
- "_content": text,
252
- }
253
- )
254
- if encoded_len <= max_context_bytes:
255
- payload["content"] = text
256
- else:
257
- payload["omitted"] = True
258
- payload["omission_reason"] = (
259
- f"file exceeds max_context_bytes ({encoded_len} > {max_context_bytes})"
260
- )
261
- return payload
262
-
263
-
264
- def payload_text(payload: dict[str, Any]) -> str | None:
265
- text = payload.get("_content")
266
- if isinstance(text, str):
267
- return text
268
- content = payload.get("content")
269
- return content if isinstance(content, str) else None
270
-
271
-
272
- def public_file_payload(
273
- payload: dict[str, Any],
274
- *,
275
- include_content: bool,
276
- ) -> dict[str, Any]:
277
- public = {
278
- key: value for key, value in payload.items() if key not in {"_content", "data"}
279
- }
280
- if not include_content:
281
- public.pop("content", None)
282
- return public
283
-
284
-
285
- def read_json_payload(path: Path, max_context_bytes: int) -> dict[str, Any]:
286
- payload = read_text_payload(path, max_context_bytes=max_context_bytes, sections=[])
287
- payload["data"] = None
288
- if payload["status"] != "present":
289
- return payload
290
- try:
291
- payload["data"] = json.loads(payload_text(payload) or path.read_text(encoding="utf-8"))
292
- except json.JSONDecodeError as exc:
293
- payload["status"] = "unreadable"
294
- payload["error"] = f"invalid json: {exc}"
295
- return payload
296
-
297
-
298
- def markdown_template_from_onboarding_reference(heading_name: str) -> str:
299
- text = ONBOARDING_REFERENCE.read_text(encoding="utf-8")
300
- heading = re.search(rf"(?m)^## {re.escape(heading_name)}\s*$", text)
301
- if not heading:
302
- raise RuntimeError(f"{heading_name} heading not found")
303
- following = text[heading.end() :]
304
- code_block = re.search(r"```md\n(.*?)\n```", following, flags=re.DOTALL)
305
- if not code_block:
306
- raise RuntimeError(f"{heading_name} markdown block not found")
307
- return code_block.group(1).strip()
308
-
309
-
310
- def load_source_category_config() -> dict[str, Any]:
311
- return json.loads(SOURCE_CATEGORY_CONFIG_REFERENCE.read_text(encoding="utf-8"))["categories"]
312
-
313
-
314
- def unique_strings(values: list[Any]) -> list[str]:
315
- return list(dict.fromkeys(str(value) for value in values if isinstance(value, str) and value))
316
-
317
-
318
- def preferred_source_routes(metadata: dict[str, Any]) -> list[str]:
319
- return unique_strings(
320
- [
321
- *(metadata.get("preferred_plugins") or []),
322
- *(metadata.get("preferred_apps") or []),
323
- ]
324
- )
325
-
326
-
327
- def normalize_source_kind(value: Any) -> str | None:
328
- source_kind = str(value or "").casefold()
329
- if source_kind in {"plugin", "app", "connector", "manual"}:
330
- return source_kind
331
- return None
332
-
333
-
334
- PLUGIN_INSTALL_EVIDENCE = {
335
- "installed_plugin_skill_visible",
336
- "plugin_in_available_plugins",
337
- "plugin_owned_skill_visible",
338
- "request_plugin_install_completed",
339
- "user_confirmed_installed_plugin",
340
- }
341
-
342
- PLUGIN_SKILL_SURFACE_EVIDENCE = {
343
- "plugin_skills_visible",
344
- "plugin_owned_skill_visible",
345
- "plugin_owned_skills_visible",
346
- }
347
-
348
- PLUGIN_TOOL_SURFACE_EVIDENCE = {
349
- "callable_app_tools_visible",
350
- "callable_plugin_tools_visible",
351
- "plugin_tools_visible",
352
- }
353
-
354
- PLUGIN_FIRST_SETUP_STATUSES = {
355
- "active",
356
- "missing",
357
- "needs_confirmation",
358
- "unavailable",
359
- "deferred",
360
- "deferred_environment_api_limitations",
361
- "skipped_for_now",
362
- }
363
-
364
-
365
- def compact_mapping(value: Any) -> dict[str, Any] | None:
366
- if not isinstance(value, dict):
367
- return None
368
- compact = {
369
- str(key): item
370
- for key, item in value.items()
371
- if isinstance(key, str) and (isinstance(item, (str, int, float, bool)) or item is None)
372
- }
373
- return compact or None
374
-
375
-
376
- def default_skill_surface(source_kind: str | None, metadata: dict[str, Any]) -> str | None:
377
- if source_kind == "plugin":
378
- return "plugin_owned"
379
- if source_kind in {"app", "connector"}:
380
- if metadata.get("relevant_skills"):
381
- return "data_analytics_vendored_helper"
382
- return "direct_tool"
383
- if source_kind == "manual":
384
- return "manual"
385
- return None
386
-
387
-
388
- def default_runtime_action(source_kind: str | None, skill_surface: str | None) -> str | None:
389
- if source_kind == "plugin":
390
- return "use_plugin_owned_skill_or_tools"
391
- if source_kind in {"app", "connector"}:
392
- if skill_surface == "data_analytics_vendored_helper":
393
- return "use_connector_or_app_with_data_analytics_helper_guidance"
394
- return "use_direct_tool_when_workflow_needs_source"
395
- if source_kind == "manual":
396
- return "use_manual_or_exported_context"
397
- return None
398
-
399
-
400
- def copy_configured_route_metadata(
401
- entry: dict[str, Any],
402
- raw_entry: dict[str, Any],
403
- metadata: dict[str, Any],
404
- ) -> None:
405
- source_kind = normalize_source_kind(raw_entry.get("source_kind"))
406
- if source_kind is None:
407
- if isinstance(raw_entry.get("plugin"), dict):
408
- source_kind = "plugin"
409
- elif isinstance(raw_entry.get("connector"), dict):
410
- source_kind = "connector"
411
- elif isinstance(raw_entry.get("app"), dict):
412
- source_kind = "app"
413
- elif isinstance(raw_entry.get("manual"), dict) or raw_entry.get("manual_source"):
414
- source_kind = "manual"
415
- elif entry.get("status") == "active" and entry.get("preferred"):
416
- source_kind = "connector"
417
-
418
- if source_kind:
419
- entry["source_kind"] = source_kind
420
-
421
- for key in ("plugin", "app", "connector", "manual"):
422
- compact = compact_mapping(raw_entry.get(key))
423
- if compact is not None:
424
- entry[key] = compact
425
-
426
- manual_source = raw_entry.get("manual_source")
427
- if isinstance(manual_source, str) and manual_source:
428
- entry["manual_source"] = manual_source
429
-
430
- skill_surface = str(raw_entry.get("skill_surface") or "") or default_skill_surface(
431
- source_kind,
432
- metadata,
433
- )
434
- if skill_surface:
435
- entry["skill_surface"] = skill_surface
436
-
437
- runtime_action = str(raw_entry.get("runtime_action") or "") or default_runtime_action(
438
- source_kind,
439
- skill_surface,
440
- )
441
- if runtime_action:
442
- entry["runtime_action"] = runtime_action
443
-
444
- for evidence_key in (
445
- "installed_evidence",
446
- "plugin_install_evidence",
447
- "app_surface_evidence",
448
- "connector_surface_evidence",
449
- "skill_surface_evidence",
450
- "tool_surface_evidence",
451
- ):
452
- evidence_value = raw_entry.get(evidence_key)
453
- if isinstance(evidence_value, str) and evidence_value:
454
- entry[evidence_key] = evidence_value
455
-
456
-
457
- def copy_source_resolution_metadata(
458
- entry: dict[str, Any],
459
- raw_entry: dict[str, Any],
460
- ) -> None:
461
- for key in ("resolution", "resolved_at", "resolution_note"):
462
- value = raw_entry.get(key)
463
- if isinstance(value, str) and value:
464
- entry[key] = value
465
-
466
-
467
- def core_source_fallback_is_explicit(entry: dict[str, Any]) -> bool:
468
- return (
469
- str(entry.get("resolution") or "").casefold()
470
- in CORE_SOURCE_EXPLICIT_FALLBACK_RESOLUTIONS
471
- )
472
-
473
-
474
- def normalize_unacknowledged_core_source_fallback(
475
- category_id: str,
476
- entry: dict[str, Any],
477
- metadata: dict[str, Any],
478
- ) -> None:
479
- if category_id not in CORE_CATEGORY_IDS:
480
- return
481
- if entry.get("status") not in ONBOARDING_RESOLVED_SOURCE_STATUSES:
482
- return
483
- if core_source_fallback_is_explicit(entry):
484
- return
485
-
486
- recorded_status = str(entry["status"])
487
- previous_setup_action = str(
488
- entry.get("fallback_setup_action") or entry.get("setup_action") or ""
489
- )
490
- preferred_routes = preferred_source_routes(metadata)
491
- entry["recorded_status"] = recorded_status
492
- entry["status"] = "needs_confirmation"
493
- entry["candidates"] = preferred_routes
494
- entry["setup_action"] = "run_plugin_first_source_setup"
495
- if previous_setup_action and previous_setup_action != entry["setup_action"]:
496
- entry["fallback_setup_action"] = previous_setup_action
497
- entry["setup_note"] = "core_source_requires_explicit_user_resolution_before_fallback"
498
- entry["plugin_preference_order"] = preferred_routes
499
- entry["setup_recovery"] = plugin_first_setup_recovery(metadata, previous_setup_action)
500
-
501
-
502
- def compact_source_route(raw_route: Any, metadata: dict[str, Any]) -> dict[str, Any] | None:
503
- if not isinstance(raw_route, dict):
504
- return None
505
- route: dict[str, Any] = {}
506
- for key in ("status", "preferred", "name", "label", "fallback", "setup_action"):
507
- value = raw_route.get(key)
508
- if isinstance(value, str) and value:
509
- route[key] = value
510
- copy_configured_route_metadata(route, raw_route, metadata)
511
- if "preferred" not in route:
512
- for route_key in ("plugin", "app", "connector", "manual"):
513
- raw_value = raw_route.get(route_key)
514
- if isinstance(raw_value, str) and raw_value:
515
- route["preferred"] = raw_value
516
- break
517
- if isinstance(raw_value, dict):
518
- for name_key in ("name", "display_name", "id"):
519
- name_value = raw_value.get(name_key)
520
- if isinstance(name_value, str) and name_value:
521
- route["preferred"] = name_value
522
- break
523
- if "preferred" in route:
524
- break
525
- if "runtime_action" not in route and route.get("source_kind"):
526
- runtime_action = default_runtime_action(
527
- str(route.get("source_kind") or ""),
528
- str(route.get("skill_surface") or ""),
529
- )
530
- if runtime_action:
531
- route["runtime_action"] = runtime_action
532
- return route or None
533
-
534
-
535
- def active_plugin_route_present(entry: dict[str, Any]) -> bool:
536
- if entry.get("source_kind") == "plugin":
537
- return True
538
- routes = entry.get("routes")
539
- if not isinstance(routes, list):
540
- return False
541
- return any(isinstance(route, dict) and route.get("source_kind") == "plugin" for route in routes)
542
-
543
-
544
- def unproven_plugin_route(entry: dict[str, Any]) -> bool:
545
- if entry.get("source_kind") != "plugin":
546
- return False
547
- installed_evidence = str(entry.get("installed_evidence") or "")
548
- plugin_install_evidence = str(entry.get("plugin_install_evidence") or "")
549
- if installed_evidence in PLUGIN_INSTALL_EVIDENCE:
550
- return False
551
- if plugin_install_evidence not in PLUGIN_INSTALL_EVIDENCE:
552
- return True
553
- if entry.get("skill_surface") == "plugin_owned":
554
- skill_surface_evidence = str(entry.get("skill_surface_evidence") or "")
555
- if skill_surface_evidence not in PLUGIN_SKILL_SURFACE_EVIDENCE:
556
- return True
557
- surface_evidence = {
558
- str(entry.get("app_surface_evidence") or ""),
559
- str(entry.get("tool_surface_evidence") or ""),
560
- str(entry.get("skill_surface_evidence") or ""),
561
- }
562
- return not surface_evidence.intersection(
563
- PLUGIN_TOOL_SURFACE_EVIDENCE | PLUGIN_SKILL_SURFACE_EVIDENCE
564
- )
565
-
566
-
567
- def list_from_inventory(inventory: dict[str, Any], *keys: str) -> list[str]:
568
- values: list[str] = []
569
- for key in keys:
570
- raw = inventory.get(key)
571
- if isinstance(raw, list):
572
- values.extend(str(item) for item in raw if isinstance(item, str) and item)
573
- return values
574
-
575
-
576
- def matching_configured_sources(preferred_sources: list[str], candidates: set[str]) -> list[str]:
577
- return [
578
- source for source in preferred_sources if normalize_source_name(source) in candidates
579
- ]
580
-
581
-
582
- def missing_source_it_options(preferred_sources: list[str]) -> list[str]:
583
- source_list = ", ".join(preferred_sources) if preferred_sources else "a matching source"
584
- return [
585
- f"Ask IT or a workspace admin to install or enable one of: {source_list}.",
586
- "Use exported, pasted, or manually supplied context for the current workflow.",
587
- ]
588
-
589
-
590
- def load_app_connector_ids() -> dict[str, str]:
591
- manifest = json.loads(APP_MANIFEST_REFERENCE.read_text(encoding="utf-8"))
592
- apps = manifest.get("apps") if isinstance(manifest, dict) else None
593
- if not isinstance(apps, dict):
594
- return {}
595
- return {
596
- normalize_source_name(app_name): str(metadata["id"])
597
- for app_name, metadata in apps.items()
598
- if isinstance(app_name, str)
599
- and isinstance(metadata, dict)
600
- and isinstance(metadata.get("id"), str)
601
- and metadata["id"]
602
- }
603
-
604
-
605
- def plugin_connector_ids(
606
- plugin_name: str,
607
- metadata: dict[str, Any],
608
- app_connector_ids: dict[str, str],
609
- ) -> set[str]:
610
- plugin_alias = normalize_source_name(plugin_name)
611
- return {
612
- connector_id
613
- for source_name in preferred_source_routes(metadata)
614
- if normalize_source_name(source_name) == plugin_alias
615
- for connector_id in [app_connector_ids.get(normalize_source_name(source_name))]
616
- if connector_id
617
- }
618
-
619
-
620
- def compact_install_candidate(candidate: dict[str, Any]) -> dict[str, Any]:
621
- return {
622
- key: candidate[key]
623
- for key in (
624
- "id",
625
- "name",
626
- "display_name",
627
- "tool_type",
628
- "has_skills",
629
- "app_connector_ids",
630
- )
631
- if key in candidate
632
- }
633
-
634
-
635
- def match_installable_plugin_candidates(
636
- source_category_config: dict[str, Any],
637
- candidates: list[dict[str, Any]] | dict[str, Any],
638
- app_connector_ids: dict[str, str] | None = None,
639
- ) -> dict[str, list[dict[str, Any]]]:
640
- """Rank installable plugins using config order, plugin slugs, and connector ids."""
641
- if isinstance(candidates, dict):
642
- raw_candidates = candidates.get("tools")
643
- candidates = raw_candidates if isinstance(raw_candidates, list) else []
644
- connector_ids = app_connector_ids if app_connector_ids is not None else load_app_connector_ids()
645
- matches: dict[str, list[dict[str, Any]]] = {}
646
- for category_id, metadata in source_category_config.items():
647
- category_matches: list[dict[str, Any]] = []
648
- for rank, plugin_name in enumerate(metadata.get("preferred_plugins") or []):
649
- plugin_alias = normalize_source_name(plugin_name)
650
- configured_connector_ids = plugin_connector_ids(plugin_name, metadata, connector_ids)
651
- for candidate in candidates:
652
- if not isinstance(candidate, dict) or candidate.get("tool_type") != "plugin":
653
- continue
654
- candidate_aliases = {
655
- normalize_source_name(candidate.get("name")),
656
- normalize_source_name(candidate.get("display_name")),
657
- normalize_source_name(str(candidate.get("id") or "").split("@", 1)[0]),
658
- }
659
- candidate_connector_ids = {
660
- str(connector_id)
661
- for connector_id in candidate.get("app_connector_ids") or []
662
- if isinstance(connector_id, str)
663
- }
664
- reasons: list[str] = []
665
- if plugin_alias and plugin_alias in candidate_aliases:
666
- reasons.append("plugin_name")
667
- if configured_connector_ids & candidate_connector_ids:
668
- reasons.append("app_connector_id")
669
- if not reasons:
670
- continue
671
- category_matches.append(
672
- {
673
- "preferred_plugin": plugin_name,
674
- "preference_rank": rank,
675
- "match_reasons": reasons,
676
- "candidate": compact_install_candidate(candidate),
677
- }
678
- )
679
- break
680
- if category_matches:
681
- matches[category_id] = category_matches
682
- return matches
683
-
684
-
685
- def plugin_first_setup_recovery(
686
- metadata: dict[str, Any],
687
- fallback_setup_action: str,
688
- ) -> dict[str, Any]:
689
- recovery = {
690
- "type": "plugin_first_source_setup",
691
- "preferred_plugins": unique_strings(metadata.get("preferred_plugins") or []),
692
- "configured_source_routes": preferred_source_routes(metadata),
693
- "candidate_lookup": "host_available_plugin_catalog",
694
- "candidate_match": "plugin_name_slug_or_app_connector_id_intersection",
695
- "install_request": "host_authorized_plugin_install",
696
- "install_requires_user_approval": True,
697
- "fallback_setup_action": fallback_setup_action,
698
- }
699
- legacy_app_fallbacks = unique_strings(metadata.get("preferred_apps") or [])
700
- if legacy_app_fallbacks:
701
- recovery["legacy_app_fallbacks"] = legacy_app_fallbacks
702
- return recovery
703
-
704
-
705
- def connector_confirmation_base_entry(
706
- category_id: str,
707
- metadata: dict[str, Any],
708
- ) -> dict[str, Any]:
709
- preferred_plugins = unique_strings(metadata.get("preferred_plugins") or [])
710
- preferred_apps = unique_strings(metadata.get("preferred_apps") or [])
711
- entry: dict[str, Any] = {
712
- "id": category_id,
713
- "label": metadata["label"],
714
- "state_scope": "onboarding_only_not_durable_connector_readiness",
715
- "workflow_time_behavior": "attempt_actual_reads_only_when_a_workflow_needs_the_source",
716
- "eager_read": False,
717
- }
718
- if preferred_plugins:
719
- entry["preferred_plugins"] = preferred_plugins
720
- if preferred_apps:
721
- entry["preferred_apps"] = preferred_apps
722
- return entry
723
-
724
-
725
- def onboarding_status(onboarding_state: dict[str, Any] | None) -> str:
726
- if not onboarding_state:
727
- return "missing"
728
- return str(onboarding_state.get("status") or "active")
729
-
730
-
731
- def connector_categories(onboarding_state: dict[str, Any] | None) -> dict[str, dict[str, Any]]:
732
- state = onboarding_state or {}
733
- connector_confirmation = state.get("connector_confirmation") or {}
734
- if not isinstance(connector_confirmation, dict):
735
- return {}
736
- categories = connector_confirmation.get("categories")
737
- if isinstance(categories, dict):
738
- return categories
739
- return {
740
- str(category_id): entry
741
- for category_id, entry in connector_confirmation.items()
742
- if category_id not in {"status", "last_shown", "preferences"}
743
- and isinstance(entry, dict)
744
- }
745
-
746
-
747
- def source_status(entry: dict[str, Any] | None) -> str:
748
- raw_status = str((entry or {}).get("status") or "needs_confirmation").casefold()
749
- aliases = {
750
- "available": "needs_confirmation",
751
- "blocked": "unavailable",
752
- "choose_source": "needs_confirmation",
753
- "connected": "active",
754
- "manual": "active",
755
- "needs_setup_probe": "needs_confirmation",
756
- "not_available": "missing",
757
- "selected": "needs_confirmation",
758
- "selected_for_verification": "needs_confirmation",
759
- "selected_needs_auth": "needs_confirmation",
760
- }
761
- return aliases.get(raw_status, raw_status)
762
-
763
-
764
- def source_setup_action(status: str) -> str:
765
- actions = {
766
- "active": "none_try_on_use",
767
- "needs_confirmation": "ask_user_to_choose_or_confirm_source",
768
- "missing": "explain_workflow_impact_and_it_admin_options",
769
- "unavailable": "ask_admin_or_manual_fallback",
770
- "declined": "none_declined",
771
- "skipped": "none_skipped",
772
- "skipped_for_now": "none_skipped",
773
- "deferred": "none_deferred",
774
- "deferred_environment_api_limitations": "none_deferred",
775
- "not_applicable": "none_not_applicable",
776
- }
777
- return actions.get(status, "ask_user_to_choose_or_confirm_source")
778
-
779
-
780
- def normalized_connector_confirmation(
781
- source_category_config: dict[str, Any],
782
- onboarding_state: dict[str, Any] | None,
783
- ) -> dict[str, dict[str, Any]]:
784
- raw_categories = connector_categories(onboarding_state)
785
- state = onboarding_state or {}
786
- raw_confirmation = state.get("connector_confirmation") or {}
787
- raw_preferences = raw_confirmation.get("preferences") if isinstance(raw_confirmation, dict) else {}
788
- if not isinstance(raw_preferences, dict):
789
- raw_preferences = {}
790
- inventory = state.get("connector_inventory") or {}
791
- if not isinstance(inventory, dict):
792
- inventory = {}
793
- confirmation: dict[str, dict[str, Any]] = {}
794
- for category_id, metadata in source_category_config.items():
795
- raw_entry = raw_categories.get(category_id)
796
- if raw_entry is None:
797
- raw_entry = raw_preferences.get(category_id)
798
- raw_entry = raw_entry if isinstance(raw_entry, dict) else {}
799
- preferred_plugins = unique_strings(metadata.get("preferred_plugins") or [])
800
- preferred_routes = preferred_source_routes(metadata)
801
- entry = connector_confirmation_base_entry(category_id, metadata)
802
-
803
- if raw_entry:
804
- status = source_status(raw_entry)
805
- if status in ONBOARDING_RESOLVED_SOURCE_STATUSES:
806
- entry["status"] = status
807
- entry["setup_action"] = source_setup_action(status)
808
- copy_configured_route_metadata(entry, raw_entry, metadata)
809
- copy_source_resolution_metadata(entry, raw_entry)
810
- elif status in {"active", "needs_confirmation", "missing"}:
811
- entry["status"] = status
812
- preferred = raw_entry.get("preferred") or raw_entry.get("app")
813
- if isinstance(preferred, str) and preferred:
814
- entry["preferred"] = preferred
815
- fallback = raw_entry.get("fallback") or raw_entry.get("backup")
816
- if isinstance(fallback, str) and fallback:
817
- entry["fallback"] = fallback
818
- if status == "active":
819
- raw_routes = raw_entry.get("routes")
820
- if isinstance(raw_routes, list):
821
- compacted_routes = [
822
- route
823
- for route in (
824
- compact_source_route(raw_route, metadata) for raw_route in raw_routes
825
- )
826
- if route is not None
827
- ]
828
- routes = [
829
- route
830
- for route in compacted_routes
831
- if not unproven_plugin_route(route)
832
- ]
833
- if routes:
834
- entry["routes"] = routes
835
- if "preferred" not in entry:
836
- first_preferred = routes[0].get("preferred")
837
- if isinstance(first_preferred, str) and first_preferred:
838
- entry["preferred"] = first_preferred
839
- elif compacted_routes:
840
- entry = connector_confirmation_base_entry(category_id, metadata)
841
- entry.update(
842
- {
843
- "status": "needs_confirmation",
844
- "candidates": preferred_routes,
845
- "setup_action": "run_plugin_first_source_setup",
846
- "setup_note": (
847
- "plugin_route_requires_plugin_install_and_surface_evidence_before_active"
848
- ),
849
- }
850
- )
851
- if entry.get("status") == "active":
852
- if raw_entry.get("confirmed_at"):
853
- entry["confirmed_at"] = raw_entry["confirmed_at"]
854
- entry["setup_action"] = "none_try_on_use"
855
- copy_configured_route_metadata(entry, raw_entry, metadata)
856
- copy_source_resolution_metadata(entry, raw_entry)
857
- if unproven_plugin_route(entry):
858
- entry = connector_confirmation_base_entry(category_id, metadata)
859
- entry.update(
860
- {
861
- "status": "needs_confirmation",
862
- "candidates": preferred_routes,
863
- "setup_action": "run_plugin_first_source_setup",
864
- "setup_note": (
865
- "plugin_route_requires_plugin_install_and_surface_evidence_before_active"
866
- ),
867
- }
868
- )
869
- elif status == "needs_confirmation":
870
- candidates = raw_entry.get("candidates")
871
- if not isinstance(candidates, list) or not candidates:
872
- if preferred:
873
- candidates = [preferred]
874
- else:
875
- candidates = preferred_routes
876
- entry["candidates"] = unique_strings(candidates)
877
- entry["setup_action"] = source_setup_action(status)
878
- copy_configured_route_metadata(entry, raw_entry, metadata)
879
- copy_source_resolution_metadata(entry, raw_entry)
880
- else:
881
- options = raw_entry.get("options")
882
- if not isinstance(options, list) or not options:
883
- options = preferred_routes
884
- entry["options"] = unique_strings(options)
885
- entry["it_admin_options"] = raw_entry.get(
886
- "it_admin_options"
887
- ) or missing_source_it_options(entry["options"])
888
- entry["setup_action"] = source_setup_action(status)
889
- copy_configured_route_metadata(entry, raw_entry, metadata)
890
- copy_source_resolution_metadata(entry, raw_entry)
891
- else:
892
- entry["status"] = "needs_confirmation"
893
- entry["candidates"] = preferred_routes
894
- entry["setup_action"] = source_setup_action("needs_confirmation")
895
- else:
896
- configured_apps = {
897
- normalize_source_name(app)
898
- for app in list_from_inventory(
899
- inventory,
900
- "active_apps",
901
- "active",
902
- "installed_and_active",
903
- "connected_apps",
904
- "available_apps",
905
- "available",
906
- "installed_apps",
907
- "surfaced_apps",
908
- )
909
- }
910
- available_matches = matching_configured_sources(preferred_routes, configured_apps)
911
- if available_matches:
912
- entry["status"] = "needs_confirmation"
913
- entry["candidates"] = available_matches
914
- entry["setup_action"] = source_setup_action("needs_confirmation")
915
- elif inventory:
916
- entry["status"] = "missing"
917
- entry["options"] = preferred_routes
918
- entry["it_admin_options"] = missing_source_it_options(preferred_routes)
919
- entry["setup_action"] = source_setup_action("missing")
920
- else:
921
- entry["status"] = "needs_confirmation"
922
- entry["candidates"] = preferred_routes
923
- entry["setup_action"] = source_setup_action("needs_confirmation")
924
-
925
- if entry.get("status") == "active" and raw_entry.get("status") == "manual":
926
- entry.setdefault("source_kind", "manual")
927
- entry.setdefault("skill_surface", "manual")
928
- entry.setdefault("runtime_action", "use_manual_or_exported_context")
929
-
930
- if "preferred" not in entry:
931
- entry["preferred"] = raw_entry.get("preferred")
932
-
933
- relevant_skills = metadata.get("relevant_skills") or []
934
- if relevant_skills and str(entry.get("source_kind") or "").casefold() != "plugin":
935
- entry["helper_skills"] = relevant_skills
936
- entry["helper_skills_apply_when"] = ["app", "connector"]
937
-
938
- plugin_preference_order = preferred_source_routes(metadata)
939
- if (
940
- preferred_plugins
941
- and plugin_preference_order
942
- and entry["status"] in PLUGIN_FIRST_SETUP_STATUSES
943
- ):
944
- entry["plugin_preference_order"] = plugin_preference_order
945
- if not active_plugin_route_present(entry):
946
- previous_setup_action = entry.get("setup_action")
947
- entry["setup_action"] = "run_plugin_first_source_setup"
948
- if previous_setup_action and previous_setup_action != entry["setup_action"]:
949
- entry["fallback_setup_action"] = previous_setup_action
950
- entry["setup_recovery"] = plugin_first_setup_recovery(
951
- metadata,
952
- str(previous_setup_action or source_setup_action(entry["status"])),
953
- )
954
- normalize_unacknowledged_core_source_fallback(category_id, entry, metadata)
955
- confirmation[category_id] = entry
956
- return confirmation
957
-
958
-
959
- def connector_confirmation_status(
960
- source_category_config: dict[str, Any],
961
- onboarding_state: dict[str, Any] | None,
962
- ) -> str:
963
- state = onboarding_state or {}
964
- if not connector_categories(onboarding_state) and not state.get("connector_inventory"):
965
- return "pending"
966
- confirmation = normalized_connector_confirmation(source_category_config, onboarding_state)
967
- statuses = [confirmation[category_id]["status"] for category_id in CORE_CATEGORY_IDS]
968
- if statuses and all(status in SOURCE_CLASSIFIED_STATUSES for status in statuses):
969
- return "completed"
970
- if any(status for status in statuses):
971
- return "in_progress"
972
- return "pending"
973
-
974
-
975
- def connector_confirmation_action_required(
976
- source_category_config: dict[str, Any],
977
- onboarding_state: dict[str, Any] | None,
978
- ) -> bool:
979
- if connector_confirmation_status(source_category_config, onboarding_state) == "pending":
980
- return False
981
- confirmation = normalized_connector_confirmation(source_category_config, onboarding_state)
982
- return any(
983
- confirmation[category_id]["status"] in SOURCE_ACTION_REQUIRED_STATUSES
984
- for category_id in CORE_CATEGORY_IDS
985
- )
986
-
987
-
988
- def connector_setup_confirmation_status(
989
- source_category_config: dict[str, Any],
990
- onboarding_state: dict[str, Any] | None,
991
- ) -> str:
992
- confirmation_status = connector_confirmation_status(source_category_config, onboarding_state)
993
- if confirmation_status == "pending":
994
- return "pending"
995
- if connector_confirmation_action_required(source_category_config, onboarding_state):
996
- return "in_progress"
997
- return "completed"
998
-
999
-
1000
- def compact_connector_setup_summary_entry(entry: dict[str, Any]) -> dict[str, Any]:
1001
- compact = {
1002
- key: entry[key]
1003
- for key in (
1004
- "id",
1005
- "label",
1006
- "status",
1007
- "preferred",
1008
- "setup_action",
1009
- "fallback_setup_action",
1010
- "source_kind",
1011
- )
1012
- if key in entry
1013
- }
1014
- for key in ("candidates", "options"):
1015
- values = entry.get(key)
1016
- if isinstance(values, list) and values:
1017
- compact[key] = unique_strings(values)
1018
- return compact
1019
-
1020
-
1021
- def build_connector_setup_summary(
1022
- source_category_config: dict[str, Any],
1023
- onboarding_state: dict[str, Any] | None,
1024
- ) -> dict[str, Any]:
1025
- confirmation = normalized_connector_confirmation(source_category_config, onboarding_state)
1026
- ready: list[dict[str, Any]] = []
1027
- needs_attention: list[dict[str, Any]] = []
1028
- fallback_or_closed: list[dict[str, Any]] = []
1029
- plugin_setup_opportunities: list[dict[str, Any]] = []
1030
- unresolved_core_ids: list[str] = []
1031
- for category_id, entry in confirmation.items():
1032
- status = entry["status"]
1033
- summary_entry = compact_connector_setup_summary_entry(entry)
1034
- if status == "active":
1035
- ready.append(summary_entry)
1036
- elif status in ONBOARDING_RESOLVED_SOURCE_STATUSES:
1037
- fallback_or_closed.append(summary_entry)
1038
- else:
1039
- needs_attention.append(summary_entry)
1040
- if entry.get("setup_action") == "run_plugin_first_source_setup":
1041
- plugin_setup_opportunities.append(summary_entry)
1042
- if category_id in CORE_CATEGORY_IDS and status in SOURCE_ACTION_REQUIRED_STATUSES:
1043
- unresolved_core_ids.append(category_id)
1044
- next_entry = needs_attention[0] if needs_attention else None
1045
- return {
1046
- "status": connector_setup_confirmation_status(source_category_config, onboarding_state),
1047
- "classification_status": connector_confirmation_status(
1048
- source_category_config,
1049
- onboarding_state,
1050
- ),
1051
- "action_required": connector_confirmation_action_required(
1052
- source_category_config,
1053
- onboarding_state,
1054
- ),
1055
- "has_setup_gaps": bool(needs_attention or plugin_setup_opportunities),
1056
- "ready": ready,
1057
- "active": ready,
1058
- "needs_attention": needs_attention,
1059
- "needs_choice": needs_attention,
1060
- "fallback_or_closed": fallback_or_closed,
1061
- "not_set_up": fallback_or_closed,
1062
- "plugin_setup_opportunities": plugin_setup_opportunities,
1063
- "unresolved_core_ids": unresolved_core_ids,
1064
- "core_complete": connector_setup_confirmation_status(
1065
- source_category_config,
1066
- onboarding_state,
1067
- )
1068
- == "completed",
1069
- "next_action": (
1070
- {
1071
- "category_id": next_entry["id"],
1072
- "label": next_entry["label"],
1073
- "status": next_entry["status"],
1074
- "preferred": next_entry["preferred"],
1075
- "setup_action": next_entry["setup_action"],
1076
- }
1077
- if next_entry
1078
- else None
1079
- ),
1080
- "user_facing_guidance": (
1081
- "Use this summary for capability or setup-status answers. During onboarding, "
1082
- "resolve one highest-value source action at a time. Active sources are FYI only; "
1083
- "attempt actual reads only when a workflow needs the source."
1084
- ),
1085
- }
1086
-
1087
-
1088
- def semantic_layer_setup_status(onboarding_state: dict[str, Any] | None) -> str:
1089
- state = onboarding_state or {}
1090
- return str((state.get("semantic_layer_setup") or {}).get("status") or "pending")
1091
-
1092
-
1093
- def semantic_layer_refresh_status(onboarding_state: dict[str, Any] | None) -> str:
1094
- state = onboarding_state or {}
1095
- return str((state.get("semantic_layer_refresh") or {}).get("status") or "pending")
1096
-
1097
-
1098
- def semantic_layer_setup_resolved(onboarding_state: dict[str, Any] | None) -> bool:
1099
- setup_status = semantic_layer_setup_status(onboarding_state)
1100
- if setup_status not in SEMANTIC_SETUP_COMPLETE_STATUSES:
1101
- return False
1102
- if setup_status in SEMANTIC_SETUP_TARGET_STATUSES:
1103
- return semantic_layer_refresh_status(onboarding_state) in SEMANTIC_REFRESH_COMPLETE_STATUSES
1104
- return True
1105
-
1106
-
1107
- def hero_prompt_state(onboarding_state: dict[str, Any] | None) -> dict[str, Any]:
1108
- state = onboarding_state or {}
1109
- choice = state.get("hero_prompt_choice")
1110
- if isinstance(choice, dict):
1111
- return choice
1112
- legacy = state.get("hero_prompts")
1113
- return legacy if isinstance(legacy, dict) else {}
1114
-
1115
-
1116
- def first_hero_prompt_status(onboarding_state: dict[str, Any] | None) -> str:
1117
- choice = hero_prompt_state(onboarding_state)
1118
- status = str(choice.get("status") or "")
1119
- if status in HERO_PROMPT_COMPLETE_STATUSES:
1120
- return "completed"
1121
- if status == "selected":
1122
- return "in_progress"
1123
- skill_experience = (onboarding_state or {}).get("skill_experience") or {}
1124
- if any(
1125
- isinstance(skill_experience.get(skill), dict)
1126
- and skill_experience[skill].get("first_tried_at")
1127
- for skill in HERO_SKILLS
1128
- ):
1129
- return "completed"
1130
- if (onboarding_state or {}).get("completed_hero_prompts"):
1131
- return "completed"
1132
- return "pending"
1133
-
1134
-
1135
- def core_onboarding_complete(
1136
- source_category_config: dict[str, Any],
1137
- onboarding_state: dict[str, Any] | None,
1138
- ) -> bool:
1139
- if not onboarding_state:
1140
- return False
1141
- explicit_status = str(
1142
- (onboarding_state.get("core_onboarding") or {}).get("status") or ""
1143
- ).casefold()
1144
- if explicit_status in {"completed", "complete", "complete_with_fallback"}:
1145
- return True
1146
- return (
1147
- connector_setup_confirmation_status(source_category_config, onboarding_state)
1148
- == "completed"
1149
- and semantic_layer_setup_resolved(onboarding_state)
1150
- )
1151
-
1152
-
1153
- def progress_task_list(
1154
- source_category_config: dict[str, Any],
1155
- onboarding_state: dict[str, Any] | None,
1156
- ) -> list[dict[str, str]]:
1157
- state = onboarding_state or {}
1158
- status = onboarding_status(onboarding_state)
1159
- task_specs = (
1160
- (
1161
- "orientation",
1162
- "Orientation",
1163
- (state.get("orientation") or {}).get("status") in {"shown", "completed"},
1164
- ),
1165
- (
1166
- "source_setup_confirmation",
1167
- "Check main analytics sources",
1168
- connector_setup_confirmation_status(source_category_config, onboarding_state)
1169
- == "completed",
1170
- ),
1171
- (
1172
- "semantic_layer_setup",
1173
- "Set Up Data Context",
1174
- semantic_layer_setup_resolved(onboarding_state),
1175
- ),
1176
- ("hero_prompt", "Hero prompt", first_hero_prompt_status(onboarding_state) == "completed"),
1177
- )
1178
- found_in_progress = False
1179
- task_list: list[dict[str, str]] = []
1180
- for task_id, label, completed in task_specs:
1181
- if completed:
1182
- task_status = "completed"
1183
- elif not found_in_progress and status not in {"complete", "quiet"}:
1184
- task_status = "in_progress"
1185
- found_in_progress = True
1186
- else:
1187
- task_status = "pending"
1188
- task_list.append({"id": task_id, "label": label, "status": task_status})
1189
- return task_list
1190
-
1191
-
1192
- def next_onboarding_action(
1193
- source_category_config: dict[str, Any],
1194
- onboarding_state: dict[str, Any] | None,
1195
- ) -> dict[str, str] | None:
1196
- tasks = progress_task_list(source_category_config, onboarding_state)
1197
- for task in tasks:
1198
- if task["status"] == "completed":
1199
- continue
1200
- mapping = {
1201
- "orientation": ("start_data_analytics_onboarding", "show orientation"),
1202
- "source_setup_confirmation": (
1203
- "confirm_analytics_sources",
1204
- "confirm active or missing sources",
1205
- ),
1206
- "semantic_layer_setup": (
1207
- "introduce_semantic_layer_setup",
1208
- "set up data context",
1209
- ),
1210
- "hero_prompt": ("offer_first_hero_prompt", "run or resolve the first hero prompt"),
1211
- }
1212
- action_id, label = mapping[task["id"]]
1213
- return {"id": action_id, "label": label}
1214
- return None
1215
-
1216
-
1217
- def semantic_layer_registry(user_context_text: str | None) -> list[dict[str, str]]:
1218
- if not user_context_text:
1219
- return []
1220
- bounds = section_bounds(user_context_text)
1221
- semantic_section = bounds.get("semantic layers")
1222
- if not semantic_section:
1223
- return []
1224
- start, end, _ = semantic_section
1225
- section = user_context_text[start:end]
1226
- entries: list[dict[str, str]] = []
1227
- for block in re.split(r"(?m)^- Area:\s*", section)[1:]:
1228
- lines = block.splitlines()
1229
- area = lines[0].strip()
1230
- entry: dict[str, str] = {"area": area}
1231
- for line in lines[1:]:
1232
- match = re.match(
1233
- r"\s*-\s*(Skill Name|Skill Path|Source Inventory Path|Last Updated):\s*(.+?)\s*$",
1234
- line,
1235
- )
1236
- if match:
1237
- entry[match.group(1).lower().replace(" ", "_")] = match.group(2)
1238
- if "skill_path" in entry:
1239
- entries.append(entry)
1240
- return entries
1241
-
1242
-
1243
- def saved_anchor_values(user_context_text: str | None) -> dict[str, list[str]]:
1244
- if not user_context_text:
1245
- return {"areas": [], "metrics": [], "dashboards": [], "tables": [], "goals": []}
1246
- return {
1247
- "areas": [entry["area"] for entry in semantic_layer_registry(user_context_text)],
1248
- "metrics": [],
1249
- "dashboards": [],
1250
- "tables": [],
1251
- "goals": [],
1252
- }
1253
-
1254
-
1255
- def build_hero_prompt_candidates(
1256
- user_context_text: str | None,
1257
- onboarding_state: dict[str, Any] | None,
1258
- ) -> list[dict[str, str]]:
1259
- anchors = saved_anchor_values(user_context_text)
1260
- semantic_setup = (onboarding_state or {}).get("semantic_layer_setup") or {}
1261
- area = semantic_setup.get("area") or (anchors["areas"][0] if anchors["areas"] else None)
1262
- metric = anchors["metrics"][0] if anchors["metrics"] else None
1263
- dashboard = anchors["dashboards"][0] if anchors["dashboards"] else None
1264
- goal = anchors["goals"][0] if anchors["goals"] else None
1265
- target = area or goal or dashboard or metric
1266
- if not target:
1267
- return []
1268
-
1269
- return [
1270
- {
1271
- "skill": "product-business-analysis",
1272
- "label": "Build a decision-ready report",
1273
- "prompt": (
1274
- f"Build a decision-ready report for {target}: explain what is happening, "
1275
- "identify the main drivers, recommend where the team should focus next, "
1276
- "and include sources, caveats, and useful charts."
1277
- ),
1278
- }
1279
- ]
1280
-
1281
-
1282
- def reorder_hero_prompt_candidates(
1283
- candidates: list[dict[str, str]],
1284
- onboarding_state: dict[str, Any] | None,
1285
- ) -> list[dict[str, str]]:
1286
- selected_skill = str(hero_prompt_state(onboarding_state).get("selected_skill") or "")
1287
- if not selected_skill:
1288
- return candidates
1289
- selected = [candidate for candidate in candidates if candidate["skill"] == selected_skill]
1290
- remaining = [candidate for candidate in candidates if candidate["skill"] != selected_skill]
1291
- return selected + remaining
1292
-
1293
-
1294
- def current_skill_experience(
1295
- workflow: str,
1296
- request_mode: str,
1297
- onboarding_state: dict[str, Any] | None,
1298
- ) -> dict[str, Any]:
1299
- skill_experience = (onboarding_state or {}).get("skill_experience") or {}
1300
- entry = skill_experience.get(workflow) if isinstance(skill_experience, dict) else None
1301
- entry = entry if isinstance(entry, dict) else {}
1302
- introduced = bool(entry.get("introduced_at"))
1303
- tried = bool(entry.get("first_tried_at"))
1304
- dismissed = bool(entry.get("dismissed_at"))
1305
- return {
1306
- "skill": workflow,
1307
- "introduced": introduced,
1308
- "tried": tried,
1309
- "dismissed": dismissed,
1310
- "intro_eligible": workflow in HERO_SKILLS and not introduced and not dismissed,
1311
- "cta_owner": "onboarding" if request_mode == "guided_onboarding_workflow" else "skill",
1312
- }
1313
-
1314
-
1315
- def final_obligations(
1316
- request_mode: str,
1317
- user_context_status: str,
1318
- source_category_config: dict[str, Any],
1319
- onboarding_state: dict[str, Any] | None,
1320
- ) -> list[dict[str, Any]]:
1321
- if request_mode != "ordinary_workflow":
1322
- return []
1323
- status = onboarding_status(onboarding_state)
1324
- if status in {"complete", "quiet"}:
1325
- return []
1326
- if user_context_status in {"missing", "unreadable"}:
1327
- return [
1328
- {
1329
- "id": "offer_data_analytics_onboarding_next_step",
1330
- "timing": "append_after_main_answer",
1331
- "only_when": "missing setup materially affects the requested output and the user has not requested inline-only or quiet delivery",
1332
- "template": markdown_template_from_onboarding_reference(
1333
- "Ordinary Workflow Onboarding CTA"
1334
- ),
1335
- "next_action": {"id": "start_data_analytics_onboarding"},
1336
- "skip_when": "the response requires a clarification or the user asked for quiet behavior",
1337
- }
1338
- ]
1339
- if not core_onboarding_complete(source_category_config, onboarding_state):
1340
- return [
1341
- {
1342
- "id": "complete_data_analytics_core_onboarding",
1343
- "timing": "append_after_main_answer",
1344
- "only_when": "missing setup materially affects the requested output and the user has not requested inline-only or quiet delivery",
1345
- "template": markdown_template_from_onboarding_reference(
1346
- "Active Core Onboarding Reminder"
1347
- ),
1348
- "requirement": "core onboarding is not complete",
1349
- "next_action": next_onboarding_action(source_category_config, onboarding_state),
1350
- "skip_when": "the response requires a clarification or the user asked for quiet behavior",
1351
- }
1352
- ]
1353
- return []
1354
-
1355
-
1356
- def conditional_guidance(request_mode: str, user_context_status: str) -> list[dict[str, Any]]:
1357
- if request_mode != "ordinary_workflow":
1358
- return []
1359
- if user_context_status not in {"missing", "unreadable"}:
1360
- return []
1361
- return [
1362
- {
1363
- "id": "context_gap_note",
1364
- "template": markdown_template_from_onboarding_reference("Context Gap Note"),
1365
- "potential_gaps": [
1366
- "Data Analytics source-routing preferences or semantic-layer registry are missing or unreadable"
1367
- ],
1368
- }
1369
- ]
1370
-
1371
-
1372
- def main() -> int:
1373
- args = parse_args()
1374
- state_dir = state_dir_from_args(args)
1375
- user_context_path = state_dir / "user-context.md"
1376
- onboarding_state_path = state_dir / "onboarding-state.json"
1377
-
1378
- user_context = read_text_payload(
1379
- user_context_path,
1380
- max_context_bytes=args.max_context_bytes,
1381
- sections=args.section,
1382
- )
1383
- onboarding_state = read_json_payload(
1384
- onboarding_state_path,
1385
- max_context_bytes=args.max_context_bytes,
1386
- )
1387
- onboarding_data = (
1388
- onboarding_state.get("data") if onboarding_state["status"] == "present" else None
1389
- )
1390
- source_category_config = load_source_category_config()
1391
- user_context_text = payload_text(user_context)
1392
- saved_source_preferences = extract_saved_source_preferences(
1393
- user_context_text,
1394
- source_category_config,
1395
- )
1396
- connector_confirmation = normalized_connector_confirmation(
1397
- source_category_config, onboarding_data
1398
- )
1399
- connector_setup_summary = build_connector_setup_summary(source_category_config, onboarding_data)
1400
- hero_prompt_candidates = reorder_hero_prompt_candidates(
1401
- build_hero_prompt_candidates(user_context_text, onboarding_data),
1402
- onboarding_data,
1403
- )
1404
- task_list = progress_task_list(source_category_config, onboarding_data)
1405
- payload = {
1406
- "schema": "data_analytics_preflight.v1",
1407
- "read_only": True,
1408
- "workflow": args.workflow,
1409
- "request_mode": args.request_mode,
1410
- "state": {
1411
- "state_dir": str(state_dir),
1412
- "user_context_status": user_context["status"],
1413
- "onboarding_state_status": onboarding_state["status"],
1414
- },
1415
- "files": {
1416
- "user_context": public_file_payload(user_context, include_content=False),
1417
- "onboarding_state": public_file_payload(onboarding_state, include_content=False),
1418
- },
1419
- "current_skill_experience": current_skill_experience(
1420
- args.workflow,
1421
- args.request_mode,
1422
- onboarding_data,
1423
- ),
1424
- "context": {
1425
- "user_context": summarize_user_context(user_context_text, source_category_config),
1426
- "source_preferences": saved_source_preferences,
1427
- "source_category_config": source_category_config,
1428
- "connector_confirmation": connector_confirmation,
1429
- "connector_setup_summary": connector_setup_summary,
1430
- "semantic_layers": semantic_layer_registry(user_context_text),
1431
- "hero_prompt_candidates": hero_prompt_candidates,
1432
- "primary_hero_prompt": hero_prompt_candidates[0] if hero_prompt_candidates else None,
1433
- "extra_hero_prompt_candidates": hero_prompt_candidates[1:3],
1434
- },
1435
- "control": {
1436
- "response_mode": args.request_mode,
1437
- "final_obligations": final_obligations(
1438
- args.request_mode,
1439
- user_context["status"],
1440
- source_category_config,
1441
- onboarding_data,
1442
- ),
1443
- "conditional_guidance": conditional_guidance(args.request_mode, user_context["status"]),
1444
- "onboarding_progress": {
1445
- "status": onboarding_status(onboarding_data),
1446
- "core_onboarding": {
1447
- "complete": core_onboarding_complete(source_category_config, onboarding_data),
1448
- "remaining_step_ids": [
1449
- item["id"] for item in task_list if item["status"] != "completed"
1450
- ],
1451
- "next_action": next_onboarding_action(source_category_config, onboarding_data),
1452
- },
1453
- "task_list": task_list,
1454
- },
1455
- },
1456
- }
1457
- print(json.dumps(payload, indent=2))
1458
- return 0
1459
-
1460
-
1461
- if __name__ == "__main__":
1462
- sys.exit(main())