@xulthekl/team-flow 0.22.4

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 (405) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.agents/skills +1 -0
  3. package/.claude/always/phase-guard.md +3 -0
  4. package/.claude-plugin/marketplace.json +20 -0
  5. package/.claude-plugin/plugin.json +31 -0
  6. package/.codex-plugin/plugin.json +45 -0
  7. package/.codexignore +6 -0
  8. package/.cursor-plugin/marketplace.json +17 -0
  9. package/.cursor-plugin/plugin.json +31 -0
  10. package/.github/copilot-instructions.md +15 -0
  11. package/.github/dependabot.yml +10 -0
  12. package/.github/plugin/marketplace.json +42 -0
  13. package/.github/workflows/ci.yml +98 -0
  14. package/.github/workflows/hol-plugin-scanner.yml +17 -0
  15. package/.opencode/INSTALL.md +61 -0
  16. package/.opencode/plugins/team-flow.js +70 -0
  17. package/AGENTS.md +280 -0
  18. package/CHANGELOG.md +635 -0
  19. package/CONTRIBUTING.md +115 -0
  20. package/GEMINI.md +14 -0
  21. package/HANDOFF.md +219 -0
  22. package/INSTALL.md +810 -0
  23. package/LICENSE +21 -0
  24. package/README.md +185 -0
  25. package/SECURITY.md +37 -0
  26. package/agents/bug-investigator.md +180 -0
  27. package/agents/change-split-auditor.md +257 -0
  28. package/agents/code-reviewer.md +171 -0
  29. package/agents/cross-change-consistency-checker.md +215 -0
  30. package/agents/prd-completeness-reviewer.md +197 -0
  31. package/agents/prototype-builder.md +230 -0
  32. package/agents/prototype-env-scout.md +156 -0
  33. package/agents/prototype-reviewer.md +226 -0
  34. package/assets/icon.svg +6 -0
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.js +5 -0
  37. package/dist/parsing/change-parser.d.ts +12 -0
  38. package/dist/parsing/change-parser.js +54 -0
  39. package/dist/parsing/requirement-blocks.d.ts +31 -0
  40. package/dist/parsing/requirement-blocks.js +192 -0
  41. package/dist/schema/base.d.ts +7 -0
  42. package/dist/schema/base.js +1 -0
  43. package/dist/schema/change.d.ts +25 -0
  44. package/dist/schema/change.js +1 -0
  45. package/dist/schema/index.d.ts +3 -0
  46. package/dist/schema/index.js +1 -0
  47. package/dist/schema/spec.d.ts +11 -0
  48. package/dist/schema/spec.js +1 -0
  49. package/dist/validation/constants.d.ts +42 -0
  50. package/dist/validation/constants.js +42 -0
  51. package/dist/validation/tokenizer.d.ts +17 -0
  52. package/dist/validation/tokenizer.js +173 -0
  53. package/dist/validation/types.d.ts +40 -0
  54. package/dist/validation/types.js +1 -0
  55. package/dist/validation/validator.d.ts +21 -0
  56. package/dist/validation/validator.js +489 -0
  57. package/docs/README_en.md +358 -0
  58. package/docs/artifact-contract.md +96 -0
  59. package/docs/decision-points.md +88 -0
  60. package/docs/e2e-integration-design.md +207 -0
  61. package/docs/examples/README.md +25 -0
  62. package/docs/examples/add-dark-mode/README.md +13 -0
  63. package/docs/examples/add-dark-mode/design.md +49 -0
  64. package/docs/examples/add-dark-mode/execution-contract.md +56 -0
  65. package/docs/examples/add-dark-mode/proposal.md +46 -0
  66. package/docs/examples/add-dark-mode/specs/ui-theme/spec.md +35 -0
  67. package/docs/examples/add-dark-mode/tasks.md +26 -0
  68. package/docs/examples/refactor-auth-boundary/README.md +15 -0
  69. package/docs/examples/refactor-auth-boundary/design.md +41 -0
  70. package/docs/examples/refactor-auth-boundary/execution-contract.md +61 -0
  71. package/docs/examples/refactor-auth-boundary/proposal.md +47 -0
  72. package/docs/examples/refactor-auth-boundary/specs/auth-boundary/spec.md +45 -0
  73. package/docs/examples/refactor-auth-boundary/tasks.md +25 -0
  74. package/docs/plans/2026-07-07-fix-batch-design.md +68 -0
  75. package/docs/plans/2026-07-20-001-refactor-skill-collaboration-protocol-plan.md +128 -0
  76. package/docs/platform-matrix.md +45 -0
  77. package/docs/prototype-design-research.md +206 -0
  78. package/docs/release-checklist.md +96 -0
  79. package/docs/showcase.html +699 -0
  80. package/docs/skill-rename-v0.8.0.md +49 -0
  81. package/docs/state-machine.md +162 -0
  82. package/gemini-extension.json +6 -0
  83. package/hooks/hooks-cursor.json +8 -0
  84. package/hooks/hooks.json +26 -0
  85. package/hooks/pre-tool-use-guard +116 -0
  86. package/hooks/session-start +14 -0
  87. package/llms.txt +51 -0
  88. package/package.json +48 -0
  89. package/plugin.json +27 -0
  90. package/prd/v1/plan.md +443 -0
  91. package/prd/v1/prd.md +580 -0
  92. package/scripts/check-update.mjs +91 -0
  93. package/scripts/check-version-consistency.mjs +345 -0
  94. package/scripts/ensure-branch.mjs +71 -0
  95. package/scripts/get-config +31 -0
  96. package/scripts/guard/checks/artifacts-exist.mjs +36 -0
  97. package/scripts/guard/checks/contract-current.mjs +33 -0
  98. package/scripts/guard/checks/contract-fresh.mjs +17 -0
  99. package/scripts/guard/checks/dp-gate-passed.mjs +35 -0
  100. package/scripts/guard/checks/dp3-approved.mjs +22 -0
  101. package/scripts/guard/checks/execution-plan-ready.mjs +40 -0
  102. package/scripts/guard/checks/execution-reviews-passed.mjs +36 -0
  103. package/scripts/guard/checks/schema-valid.mjs +63 -0
  104. package/scripts/guard/checks/specs-merged.mjs +51 -0
  105. package/scripts/guard/checks/tasks-complete.mjs +31 -0
  106. package/scripts/guard/checks/tests-passing.mjs +31 -0
  107. package/scripts/guard/design-token-guard.mjs +237 -0
  108. package/scripts/guard/guard.mjs +205 -0
  109. package/scripts/infer-workflow.mjs +136 -0
  110. package/scripts/install-amazon-q.mjs +9 -0
  111. package/scripts/install-cline.mjs +9 -0
  112. package/scripts/install-continue.mjs +9 -0
  113. package/scripts/install-cursor.mjs +265 -0
  114. package/scripts/install-git-hooks.mjs +82 -0
  115. package/scripts/install-kiro.mjs +9 -0
  116. package/scripts/install-pi.mjs +9 -0
  117. package/scripts/install-qoder.mjs +9 -0
  118. package/scripts/install-qwen.mjs +9 -0
  119. package/scripts/install-roocode.mjs +9 -0
  120. package/scripts/install-windsurf.mjs +9 -0
  121. package/scripts/install-zcode.mjs +265 -0
  122. package/scripts/lib/cmd-audit.mjs +127 -0
  123. package/scripts/lib/cmd-checkpoint.mjs +118 -0
  124. package/scripts/lib/cmd-config.mjs +88 -0
  125. package/scripts/lib/cmd-doctor.mjs +267 -0
  126. package/scripts/lib/cmd-execution.mjs +206 -0
  127. package/scripts/lib/cmd-handoff.mjs +94 -0
  128. package/scripts/lib/cmd-inject.mjs +310 -0
  129. package/scripts/lib/cmd-install-amazon-q.mjs +11 -0
  130. package/scripts/lib/cmd-install-cline.mjs +11 -0
  131. package/scripts/lib/cmd-install-continue.mjs +11 -0
  132. package/scripts/lib/cmd-install-cursor.mjs +14 -0
  133. package/scripts/lib/cmd-install-kiro.mjs +11 -0
  134. package/scripts/lib/cmd-install-pi.mjs +11 -0
  135. package/scripts/lib/cmd-install-qoder.mjs +11 -0
  136. package/scripts/lib/cmd-install-qwen.mjs +11 -0
  137. package/scripts/lib/cmd-install-roocode.mjs +11 -0
  138. package/scripts/lib/cmd-install-windsurf.mjs +11 -0
  139. package/scripts/lib/cmd-install-workbuddy.mjs +359 -0
  140. package/scripts/lib/cmd-install-zcode.mjs +14 -0
  141. package/scripts/lib/cmd-isolate.mjs +37 -0
  142. package/scripts/lib/cmd-list.mjs +71 -0
  143. package/scripts/lib/cmd-runtime.mjs +85 -0
  144. package/scripts/lib/cmd-solutions.mjs +71 -0
  145. package/scripts/lib/cmd-state.mjs +231 -0
  146. package/scripts/lib/cmd-sync.mjs +102 -0
  147. package/scripts/lib/cmd-validate.mjs +105 -0
  148. package/scripts/lib/cmd-version.mjs +148 -0
  149. package/scripts/lib/config-loader.mjs +107 -0
  150. package/scripts/lib/execution-plan.mjs +492 -0
  151. package/scripts/lib/execution-recommendation.mjs +221 -0
  152. package/scripts/lib/hash.mjs +74 -0
  153. package/scripts/lib/install.mjs +267 -0
  154. package/scripts/lib/platform-runtime-inventory.mjs +27 -0
  155. package/scripts/lib/platforms.mjs +165 -0
  156. package/scripts/lib/prototype-sync.mjs +192 -0
  157. package/scripts/lib/sdd-overlay.mjs +262 -0
  158. package/scripts/lib/shell-quote.mjs +4 -0
  159. package/scripts/lib/solutions-capture.mjs +102 -0
  160. package/scripts/lib/solutions-index-gen.mjs +112 -0
  161. package/scripts/lib/solutions-inject.mjs +77 -0
  162. package/scripts/lib/solutions-promote.mjs +145 -0
  163. package/scripts/lib/spec-paths.mjs +85 -0
  164. package/scripts/lib/state-loader.mjs +154 -0
  165. package/scripts/lint/lint-skills.mjs +149 -0
  166. package/scripts/lint/rules/behavior-consistency.mjs +56 -0
  167. package/scripts/lint/rules/dp-trigger-points.mjs +60 -0
  168. package/scripts/lint/rules/exception-handling.mjs +59 -0
  169. package/scripts/lint/rules/no-contradictory-instructions.mjs +67 -0
  170. package/scripts/lint/rules/no-redundant-checks.mjs +50 -0
  171. package/scripts/lint/rules/token-rules.mjs +122 -0
  172. package/scripts/review-package +44 -0
  173. package/scripts/task-brief +40 -0
  174. package/scripts/team-flow.mjs +164 -0
  175. package/scripts/token-baseline.mjs +158 -0
  176. package/scripts/validate-artifacts +96 -0
  177. package/scripts/verify-marketplace-release.mjs +59 -0
  178. package/skills/architecture-design/SKILL.md +140 -0
  179. package/skills/architecture-design/chapters/ch01-4a-domains.md +27 -0
  180. package/skills/architecture-design/chapters/ch02-change-cascade.md +27 -0
  181. package/skills/architecture-design/chapters/ch03-architecture-outputs.md +25 -0
  182. package/skills/architecture-design/chapters/ch04-entity-to-aggregate.md +27 -0
  183. package/skills/architecture-design/chapters/ch05-cqrs.md +32 -0
  184. package/skills/architecture-design/chapters/ch06-integration.md +54 -0
  185. package/skills/architecture-design/cheatsheet.md +51 -0
  186. package/skills/architecture-design/glossary.md +23 -0
  187. package/skills/architecture-design/patterns.md +32 -0
  188. package/skills/bug-investigator/SKILL.md +77 -0
  189. package/skills/build-executor/SKILL.md +163 -0
  190. package/skills/build-executor/implementer-prompt.md +162 -0
  191. package/skills/build-executor/references/execution-modes.md +86 -0
  192. package/skills/build-executor/task-reviewer-prompt.md +195 -0
  193. package/skills/ce-brainstorm/SKILL.md +415 -0
  194. package/skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
  195. package/skills/ce-brainstorm/references/blindspot-pass.md +70 -0
  196. package/skills/ce-brainstorm/references/brainstorm-sections.md +285 -0
  197. package/skills/ce-brainstorm/references/handoff.md +168 -0
  198. package/skills/ce-brainstorm/references/html-rendering.md +634 -0
  199. package/skills/ce-brainstorm/references/markdown-rendering.md +241 -0
  200. package/skills/ce-brainstorm/references/model-tiers.md +9 -0
  201. package/skills/ce-brainstorm/references/prd-mapping.md +71 -0
  202. package/skills/ce-brainstorm/references/product-pressure-test.md +42 -0
  203. package/skills/ce-brainstorm/references/reasoning-elevation.md +63 -0
  204. package/skills/ce-brainstorm/references/settled-decisions.md +45 -0
  205. package/skills/ce-brainstorm/references/synthesis-summary.md +282 -0
  206. package/skills/ce-brainstorm/references/universal-brainstorming.md +73 -0
  207. package/skills/ce-brainstorm/references/verdict-routing.md +26 -0
  208. package/skills/ce-brainstorm/references/visual-probes.md +158 -0
  209. package/skills/ce-brainstorm/scripts/visual-probe-server.js +418 -0
  210. package/skills/ce-compound/SKILL.md +114 -0
  211. package/skills/ce-compound/assets/resolution-template.md +94 -0
  212. package/skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
  213. package/skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
  214. package/skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
  215. package/skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
  216. package/skills/ce-compound/references/agents/performance-oracle.md +108 -0
  217. package/skills/ce-compound/references/agents/security-sentinel.md +91 -0
  218. package/skills/ce-compound/references/agents/session-historian.md +83 -0
  219. package/skills/ce-compound/references/concepts-vocabulary.md +78 -0
  220. package/skills/ce-compound/references/full-mode-workflow.md +413 -0
  221. package/skills/ce-compound/references/grounding-validation.md +84 -0
  222. package/skills/ce-compound/references/lightweight-mode.md +53 -0
  223. package/skills/ce-compound/references/output-standards.md +182 -0
  224. package/skills/ce-compound/references/promotion-rules.md +38 -0
  225. package/skills/ce-compound/references/schema.yaml +231 -0
  226. package/skills/ce-compound/references/three-tier-index.md +55 -0
  227. package/skills/ce-compound/references/v0.5-upgrade.md +32 -0
  228. package/skills/ce-compound/references/write-flow.md +36 -0
  229. package/skills/ce-compound/references/yaml-schema.md +118 -0
  230. package/skills/ce-compound/scripts/session-history/discover-sessions.sh +130 -0
  231. package/skills/ce-compound/scripts/session-history/extract-errors.py +254 -0
  232. package/skills/ce-compound/scripts/session-history/extract-metadata.py +456 -0
  233. package/skills/ce-compound/scripts/session-history/extract-skeleton.py +575 -0
  234. package/skills/ce-compound/scripts/validate-doc-claims.py +346 -0
  235. package/skills/ce-compound/scripts/validate-frontmatter.py +137 -0
  236. package/skills/ce-ideate/SKILL.md +402 -0
  237. package/skills/ce-ideate/references/agents/issue-intelligence-analyst.md +200 -0
  238. package/skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
  239. package/skills/ce-ideate/references/agents/slack-researcher.md +127 -0
  240. package/skills/ce-ideate/references/agents/web-researcher.md +121 -0
  241. package/skills/ce-ideate/references/divergent-ideation.md +89 -0
  242. package/skills/ce-ideate/references/html-rendering.md +634 -0
  243. package/skills/ce-ideate/references/ideation-sections.md +191 -0
  244. package/skills/ce-ideate/references/markdown-rendering.md +238 -0
  245. package/skills/ce-ideate/references/post-ideation-workflow.md +167 -0
  246. package/skills/ce-ideate/references/universal-ideation.md +107 -0
  247. package/skills/ce-ideate/references/web-research-cache.md +56 -0
  248. package/skills/ce-plan/SKILL.md +137 -0
  249. package/skills/ce-plan/references/agents/agent-native-planning-strategist.md +62 -0
  250. package/skills/ce-plan/references/agents/architecture-strategist.md +46 -0
  251. package/skills/ce-plan/references/agents/best-practices-researcher.md +114 -0
  252. package/skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
  253. package/skills/ce-plan/references/agents/data-migration-reviewer.md +103 -0
  254. package/skills/ce-plan/references/agents/deployment-verification-agent.md +157 -0
  255. package/skills/ce-plan/references/agents/framework-docs-researcher.md +93 -0
  256. package/skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
  257. package/skills/ce-plan/references/agents/learnings-researcher.md +247 -0
  258. package/skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
  259. package/skills/ce-plan/references/agents/performance-oracle.md +108 -0
  260. package/skills/ce-plan/references/agents/repo-research-analyst.md +258 -0
  261. package/skills/ce-plan/references/agents/security-sentinel.md +91 -0
  262. package/skills/ce-plan/references/agents/slack-researcher.md +127 -0
  263. package/skills/ce-plan/references/agents/spec-flow-analyzer.md +80 -0
  264. package/skills/ce-plan/references/agents/web-researcher.md +121 -0
  265. package/skills/ce-plan/references/approach-altitude.md +55 -0
  266. package/skills/ce-plan/references/change-splitting.md +65 -0
  267. package/skills/ce-plan/references/completion-contract.md +33 -0
  268. package/skills/ce-plan/references/core-principles.md +40 -0
  269. package/skills/ce-plan/references/deepening-workflow.md +263 -0
  270. package/skills/ce-plan/references/dependency-graph.md +36 -0
  271. package/skills/ce-plan/references/html-rendering.md +634 -0
  272. package/skills/ce-plan/references/intake-routing.md +189 -0
  273. package/skills/ce-plan/references/markdown-rendering.md +238 -0
  274. package/skills/ce-plan/references/plan-handoff.md +150 -0
  275. package/skills/ce-plan/references/plan-sections.md +427 -0
  276. package/skills/ce-plan/references/plan-structure.md +120 -0
  277. package/skills/ce-plan/references/planning-modes.md +69 -0
  278. package/skills/ce-plan/references/reasoning-elevation.md +63 -0
  279. package/skills/ce-plan/references/research-workflow.md +165 -0
  280. package/skills/ce-plan/references/review-and-write.md +127 -0
  281. package/skills/ce-plan/references/settled-decisions.md +45 -0
  282. package/skills/ce-plan/references/synthesis-summary.md +418 -0
  283. package/skills/ce-plan/references/universal-planning.md +168 -0
  284. package/skills/ce-proof/SKILL.md +346 -0
  285. package/skills/ce-strategy/SKILL.md +97 -0
  286. package/skills/ce-strategy/references/interview.md +143 -0
  287. package/skills/ce-strategy/references/strategy-template.md +89 -0
  288. package/skills/code-reviewer/SKILL.md +84 -0
  289. package/skills/code-reviewer/code-reviewer-prompt.md +195 -0
  290. package/skills/contract-builder/SKILL.md +72 -0
  291. package/skills/design-system/SKILL.md +75 -0
  292. package/skills/design-system/references/agents/design-system-architect.md +138 -0
  293. package/skills/design-system/references/creation-flow.md +170 -0
  294. package/skills/design-system/references/preview-template.html +319 -0
  295. package/skills/design-system/references/token-derivation.md +115 -0
  296. package/skills/design-system/references/variant-schema.md +60 -0
  297. package/skills/e2e/SKILL.md +56 -0
  298. package/skills/e2e/references/test-verifier.md +40 -0
  299. package/skills/need-explorer/SKILL.md +79 -0
  300. package/skills/prototype/SKILL.md +98 -0
  301. package/skills/prototype/references/agents/design-system-architect.md +122 -0
  302. package/skills/prototype/references/checklist.md +82 -0
  303. package/skills/prototype/references/craft/accessibility-baseline.md +71 -0
  304. package/skills/prototype/references/craft/anti-ai-slop.md +87 -0
  305. package/skills/prototype/references/craft/laws-of-ux.md +60 -0
  306. package/skills/prototype/references/craft/state-coverage.md +81 -0
  307. package/skills/prototype/references/craft/typography-hierarchy.md +50 -0
  308. package/skills/prototype/references/layouts.md +223 -0
  309. package/skills/prototype/references/orchestration-flow.md +101 -0
  310. package/skills/prototype/references/prototype-scaffold/assets/design-tokens.css +19 -0
  311. package/skills/prototype/references/prototype-scaffold/components/button.html +3 -0
  312. package/skills/prototype/references/prototype-scaffold/design-system.md +7 -0
  313. package/skills/prototype/references/prototype-scaffold/flow.md +11 -0
  314. package/skills/prototype/references/prototype-scaffold/index.html +20 -0
  315. package/skills/prototype/references/prototype-scaffold/pages/index.html +11 -0
  316. package/skills/prototype/references/template.html +396 -0
  317. package/skills/release-archivist/SKILL.md +166 -0
  318. package/skills/release-archivist/references/closing-procedures.md +81 -0
  319. package/skills/session-handoff/SKILL.md +110 -0
  320. package/skills/session-handoff/references/context-extraction.md +70 -0
  321. package/skills/session-handoff/references/handoff-template.md +90 -0
  322. package/skills/session-handoff/references/skill-recommendation.md +43 -0
  323. package/skills/spec-merger/SKILL.md +66 -0
  324. package/skills/spec-writer/SKILL.md +149 -0
  325. package/skills/workflow-bootstrap/SKILL.md +148 -0
  326. package/skills/workflow-bootstrap/references/agents/codebase-recon-analyst.md +121 -0
  327. package/skills/workflow-bootstrap/references/b1-reconnaissance.md +80 -0
  328. package/skills/workflow-bootstrap/scripts/recon-probe.sh +328 -0
  329. package/skills/workflow-feedback/SKILL.md +120 -0
  330. package/skills/workflow-feedback/references/category-guide.md +121 -0
  331. package/skills/workflow-feedback/references/feedback-template.md +73 -0
  332. package/skills/workflow-feedback/references/review-mode.md +92 -0
  333. package/skills/workflow-orchestrator/SKILL.md +94 -0
  334. package/skills/workflow-orchestrator/references/feedback-loops.md +56 -0
  335. package/skills/workflow-orchestrator/references/s1-path-router.md +81 -0
  336. package/skills/workflow-orchestrator/references/s2-prd-prototype-loop.md +96 -0
  337. package/skills/workflow-orchestrator/references/s3-plan-pipeline.md +50 -0
  338. package/skills/workflow-orchestrator/references/s4-split-validate.md +108 -0
  339. package/skills/workflow-orchestrator/references/s5-monitoring.md +61 -0
  340. package/skills/workflow-orchestrator/references/state-model.md +185 -0
  341. package/skills/workflow-start/SKILL.md +147 -0
  342. package/skills/workflow-start/references/routing-rules.md +155 -0
  343. package/src/index.ts +16 -0
  344. package/src/parsing/change-parser.ts +79 -0
  345. package/src/parsing/requirement-blocks.ts +244 -0
  346. package/src/schema/base.ts +8 -0
  347. package/src/schema/change.ts +29 -0
  348. package/src/schema/index.ts +3 -0
  349. package/src/schema/spec.ts +12 -0
  350. package/src/validation/constants.ts +53 -0
  351. package/src/validation/tokenizer.ts +180 -0
  352. package/src/validation/types.ts +47 -0
  353. package/src/validation/validator.ts +552 -0
  354. package/templates/abandonment-summary.md +29 -0
  355. package/templates/design.md +37 -0
  356. package/templates/execution-contract.md +99 -0
  357. package/templates/plan.md +86 -0
  358. package/templates/prd.md +468 -0
  359. package/templates/proposal.md +37 -0
  360. package/templates/spec.md +31 -0
  361. package/templates/tasks.md +47 -0
  362. package/tests/e2e.test.mjs +266 -0
  363. package/tests/lib/cmd-audit.test.mjs +202 -0
  364. package/tests/lib/cmd-checkpoint.test.mjs +98 -0
  365. package/tests/lib/cmd-config.test.mjs +101 -0
  366. package/tests/lib/cmd-doctor.test.mjs +450 -0
  367. package/tests/lib/cmd-execution.test.mjs +647 -0
  368. package/tests/lib/cmd-handoff.test.mjs +137 -0
  369. package/tests/lib/cmd-inject.test.mjs +218 -0
  370. package/tests/lib/cmd-install-workbuddy.test.mjs +113 -0
  371. package/tests/lib/cmd-install-zcode.test.mjs +42 -0
  372. package/tests/lib/cmd-isolate.test.mjs +68 -0
  373. package/tests/lib/cmd-list.test.mjs +127 -0
  374. package/tests/lib/cmd-runtime.test.mjs +83 -0
  375. package/tests/lib/cmd-state-missing.test.mjs +65 -0
  376. package/tests/lib/cmd-state.test.mjs +365 -0
  377. package/tests/lib/cmd-sync-paths.test.mjs +84 -0
  378. package/tests/lib/cmd-validate-paths.test.mjs +90 -0
  379. package/tests/lib/config-loader.test.mjs +175 -0
  380. package/tests/lib/ensure-branch.test.mjs +59 -0
  381. package/tests/lib/execution-control-plane.test.mjs +168 -0
  382. package/tests/lib/execution-plan.test.mjs +474 -0
  383. package/tests/lib/guard-specs-merged.test.mjs +108 -0
  384. package/tests/lib/guard-tests-passing.test.mjs +112 -0
  385. package/tests/lib/guard-transitions.test.mjs +262 -0
  386. package/tests/lib/guard.test.mjs +611 -0
  387. package/tests/lib/hash.test.mjs +138 -0
  388. package/tests/lib/infer-workflow.test.mjs +161 -0
  389. package/tests/lib/install-git-hooks.test.mjs +20 -0
  390. package/tests/lib/marketplace-release-docs.test.mjs +31 -0
  391. package/tests/lib/minimality-discipline.test.mjs +37 -0
  392. package/tests/lib/model-profiles-docs.test.mjs +33 -0
  393. package/tests/lib/node20-compatibility.test.mjs +73 -0
  394. package/tests/lib/node20-test-entry.test.mjs +17 -0
  395. package/tests/lib/platform-runtime-distribution.test.mjs +150 -0
  396. package/tests/lib/raw-mode-smoke.test.mjs +42 -0
  397. package/tests/lib/sdd-overlay.test.mjs +118 -0
  398. package/tests/lib/spec-paths.test.mjs +80 -0
  399. package/tests/lib/state-loader.test.mjs +251 -0
  400. package/tests/lib/token-baseline.test.mjs +72 -0
  401. package/tests/lib/token-rules.test.mjs +94 -0
  402. package/tests/lib/verify-marketplace-release.test.mjs +128 -0
  403. package/tests/tsconfig.json +12 -0
  404. package/token-baseline.json +95 -0
  405. package/tsconfig.json +14 -0
@@ -0,0 +1,118 @@
1
+ # YAML Frontmatter Schema
2
+
3
+ `schema.yaml` in this directory is the canonical contract for `docs/solutions/` frontmatter written by `ce-compound`.
4
+
5
+ Use this file as the quick reference for:
6
+ - required fields
7
+ - enum values
8
+ - validation expectations
9
+ - category mapping
10
+ - track classification (bug vs knowledge)
11
+
12
+ ## Tracks
13
+
14
+ The `problem_type` determines which **track** applies. Each track has different required and optional fields.
15
+
16
+ | Track | problem_types | Description |
17
+ |-------|--------------|-------------|
18
+ | **Bug** | `build_error`, `test_failure`, `runtime_error`, `performance_issue`, `database_issue`, `security_issue`, `ui_bug`, `integration_issue`, `logic_error` | Defects and failures that were diagnosed and fixed |
19
+ | **Knowledge** | `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention` | Practices, patterns, conventions, decisions, workflow improvements, and documentation. Prefer the narrowest applicable value; `best_practice` is the fallback. |
20
+
21
+ ## Required Fields (both tracks)
22
+
23
+ - **module**: Module or area affected
24
+ - **date**: ISO date in `YYYY-MM-DD`
25
+ - **problem_type**: One of the values listed in the Tracks table above
26
+ - **component**: One of `rails_model`, `rails_controller`, `rails_view`, `service_object`, `background_job`, `database`, `frontend_stimulus`, `hotwire_turbo`, `email_processing`, `brief_system`, `assistant`, `authentication`, `payments`, `development_workflow`, `testing_framework`, `documentation`, `tooling`
27
+ - **severity**: One of `critical`, `high`, `medium`, `low`
28
+
29
+ ## Bug Track Fields
30
+
31
+ Required:
32
+ - **symptoms**: YAML array with 1-5 observable symptoms (errors, broken behavior)
33
+ - **root_cause**: One of `missing_association`, `missing_include`, `missing_index`, `wrong_api`, `scope_issue`, `thread_violation`, `async_timing`, `memory_leak`, `config_error`, `logic_error`, `test_isolation`, `missing_validation`, `missing_permission`, `missing_workflow_step`, `inadequate_documentation`, `missing_tooling`, `incomplete_setup`
34
+ - **resolution_type**: One of `code_fix`, `migration`, `config_change`, `test_fix`, `dependency_update`, `environment_setup`, `workflow_improvement`, `documentation_update`, `tooling_addition`, `seed_data_update`
35
+
36
+ ## Knowledge Track Fields
37
+
38
+ No additional required fields beyond the shared ones. All fields below are optional:
39
+
40
+ - **applies_when**: Conditions or situations where this guidance applies
41
+ - **symptoms**: Observable gaps or friction that prompted this guidance
42
+ - **root_cause**: Underlying cause, if there is a specific one
43
+ - **resolution_type**: Type of change, if applicable
44
+
45
+ ## Optional Fields (both tracks)
46
+
47
+ - **related_components**: Other components involved
48
+ - **tags**: Search keywords, lowercase and hyphen-separated
49
+
50
+ ## Optional Fields (bug track only)
51
+
52
+ - **rails_version**: Rails version in `X.Y.Z` format
53
+
54
+ ## Backward Compatibility
55
+
56
+ Docs created before the track system may have `symptoms`/`root_cause`/`resolution_type` on knowledge-type problem_types. These are valid legacy docs:
57
+
58
+ - Bug-track fields present on a knowledge-track doc are harmless. Do not strip them during refresh unless the doc is being rewritten for other reasons.
59
+ - When creating **new** docs, follow the track rules above.
60
+
61
+ ## Category Mapping
62
+
63
+ - `build_error` -> `docs/solutions/build-errors/`
64
+ - `test_failure` -> `docs/solutions/test-failures/`
65
+ - `runtime_error` -> `docs/solutions/runtime-errors/`
66
+ - `performance_issue` -> `docs/solutions/performance-issues/`
67
+ - `database_issue` -> `docs/solutions/database-issues/`
68
+ - `security_issue` -> `docs/solutions/security-issues/`
69
+ - `ui_bug` -> `docs/solutions/ui-bugs/`
70
+ - `integration_issue` -> `docs/solutions/integration-issues/`
71
+ - `logic_error` -> `docs/solutions/logic-errors/`
72
+ - `developer_experience` -> `docs/solutions/developer-experience/`
73
+ - `workflow_issue` -> `docs/solutions/workflow-issues/`
74
+ - `best_practice` -> `docs/solutions/best-practices/`
75
+ - `documentation_gap` -> `docs/solutions/documentation-gaps/`
76
+ - `architecture_pattern` -> `docs/solutions/architecture-patterns/`
77
+ - `design_pattern` -> `docs/solutions/design-patterns/`
78
+ - `tooling_decision` -> `docs/solutions/tooling-decisions/`
79
+ - `convention` -> `docs/solutions/conventions/`
80
+
81
+ ## Validation Rules
82
+
83
+ 1. Determine the track from `problem_type` using the Tracks table.
84
+ 2. All shared required fields must be present.
85
+ 3. Bug-track required fields (`symptoms`, `root_cause`, `resolution_type`) must be present on bug-track docs.
86
+ 4. Knowledge-track docs have no additional required fields beyond the shared ones.
87
+ 5. Bug-track fields on existing knowledge-track docs are harmless (see Backward Compatibility).
88
+ 6. Enum fields must match the allowed values exactly.
89
+ 7. Array fields must respect min/max item counts.
90
+ 8. `date` must match `YYYY-MM-DD`.
91
+ 9. `rails_version`, if present, must match `X.Y.Z` and only applies to bug-track docs.
92
+
93
+ ## YAML Safety Rules
94
+
95
+ Strict YAML 1.2 parsers (`yq`, `js-yaml` strict, PyYAML) reject array items
96
+ that start with a reserved indicator character as unquoted scalars. When
97
+ writing items for any array-of-strings field (`symptoms`, `applies_when`,
98
+ `tags`, `related_components`, or any future array field), wrap the value in
99
+ double quotes if it starts with any of:
100
+
101
+ `` ` ``, `[`, `*`, `&`, `!`, `|`, `>`, `%`, `@`, `?`
102
+
103
+ Also quote if the value contains the substring `": "` — that punctuation
104
+ confuses flow-style parsers.
105
+
106
+ Example — before (breaks strict YAML):
107
+
108
+ symptoms:
109
+ - `sudo dscacheutil -flushcache` does not restore in-container mDNS
110
+
111
+ Example — after (parses cleanly):
112
+
113
+ symptoms:
114
+ - "`sudo dscacheutil -flushcache` does not restore in-container mDNS"
115
+
116
+ This rule applies to all array-of-strings frontmatter fields. Scalar string
117
+ fields like `description:` have their own quoting rules (see plugin
118
+ `AGENTS.md` under "YAML Frontmatter").
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bash
2
+ # Discover session files across Claude Code, Codex, Cursor, and Pi.
3
+ #
4
+ # Usage: discover-sessions.sh <repo-name> <days> [--cwd /abs/repo/root] [--platform claude|codex|cursor|pi]
5
+ #
6
+ # Outputs one file path per line. Safe in both bash and zsh (all globs guarded).
7
+ # Pass output to extract-metadata.py:
8
+ # python3 extract-metadata.py --cwd-filter <repo-name> $(bash discover-sessions.sh <repo-name> 7)
9
+ #
10
+ # Arguments:
11
+ # repo-name Folder name of the repo (e.g., "my-repo"). Used for directory matching.
12
+ # days Scan window in days (e.g., 7). Files older than this are skipped.
13
+ # --cwd Absolute repo root. Used for exact Pi encoded-CWD discovery.
14
+ # --platform Restrict to a single platform. Omit to search all.
15
+
16
+ set -euo pipefail
17
+
18
+ REPO_NAME="${1:?Usage: discover-sessions.sh <repo-name> <days> [--cwd /abs/repo/root] [--platform claude|codex|cursor|pi]}"
19
+ DAYS="${2:?Usage: discover-sessions.sh <repo-name> <days> [--cwd /abs/repo/root] [--platform claude|codex|cursor|pi]}"
20
+ PLATFORM="all"
21
+ REPO_CWD=""
22
+
23
+ # Parse optional --platform flag
24
+ shift 2
25
+ while [ $# -gt 0 ]; do
26
+ case "$1" in
27
+ --cwd) REPO_CWD="$2"; shift 2 ;;
28
+ --platform) PLATFORM="$2"; shift 2 ;;
29
+ *) shift ;;
30
+ esac
31
+ done
32
+
33
+ encode_pi_cwd() {
34
+ local cwd="${1%/}"
35
+ local encoded="${cwd//\//-}"
36
+ encoded="${encoded#-}"
37
+ printf -- "--%s--" "$encoded"
38
+ }
39
+
40
+ # --- Claude Code ---
41
+ discover_claude() {
42
+ local base="$HOME/.claude/projects"
43
+ [ -d "$base" ] || return 0
44
+
45
+ # Find all project dirs matching repo name
46
+ for dir in "$base"/*"$REPO_NAME"*/; do
47
+ [ -d "$dir" ] || continue
48
+ find "$dir" -maxdepth 1 -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
49
+ done
50
+ }
51
+
52
+ # --- Codex ---
53
+ discover_codex() {
54
+ for base in "$HOME/.codex/sessions" "$HOME/.agents/sessions"; do
55
+ [ -d "$base" ] || continue
56
+
57
+ # Use mtime-based discovery (consistent with Claude/Cursor) so that
58
+ # sessions started before the scan window but still active within it
59
+ # are not missed.
60
+ find "$base" -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
61
+ done
62
+ }
63
+
64
+ # --- Cursor ---
65
+ discover_cursor() {
66
+ local base="$HOME/.cursor/projects"
67
+ [ -d "$base" ] || return 0
68
+
69
+ for dir in "$base"/*"$REPO_NAME"*/; do
70
+ [ -d "$dir" ] || continue
71
+ local transcripts="$dir/agent-transcripts"
72
+ [ -d "$transcripts" ] || continue
73
+ find "$transcripts" -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
74
+ done
75
+ }
76
+
77
+ # --- Pi ---
78
+ discover_pi() {
79
+ local agent_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
80
+ local base="${PI_CODING_AGENT_SESSION_DIR:-$agent_dir/sessions}"
81
+ [ -d "$base" ] || return 0
82
+
83
+ # Pi's explicit session-dir override stores session files directly in the
84
+ # supplied directory. The cwd filter later reads each header and keeps only
85
+ # sessions for the active repo.
86
+ if [ -n "${PI_CODING_AGENT_SESSION_DIR:-}" ]; then
87
+ find "$base" -maxdepth 1 -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
88
+ if [ -z "$REPO_CWD" ]; then
89
+ for dir in "$base"/*"$REPO_NAME"*/; do
90
+ [ -d "$dir" ] || continue
91
+ find "$dir" -maxdepth 1 -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
92
+ done
93
+ fi
94
+ return 0
95
+ fi
96
+
97
+ # Pi stores sessions under --<absolute-cwd-with-slashes-as-hyphens>--.
98
+ # When the caller supplies an exact repo root, probe only that encoded
99
+ # directory so sibling repos like my-repo-old never enter the pipeline.
100
+ if [ -n "$REPO_CWD" ]; then
101
+ local dir="$base/$(encode_pi_cwd "$REPO_CWD")"
102
+ [ -d "$dir" ] || return 0
103
+ find "$dir" -maxdepth 1 -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
104
+ return 0
105
+ fi
106
+
107
+ # Fallback for direct script use without --cwd.
108
+ for dir in "$base"/*"$REPO_NAME"*/; do
109
+ [ -d "$dir" ] || continue
110
+ find "$dir" -maxdepth 1 -name "*.jsonl" -mtime "-${DAYS}" 2>/dev/null
111
+ done
112
+ }
113
+
114
+ # --- Dispatch ---
115
+ case "$PLATFORM" in
116
+ claude) discover_claude ;;
117
+ codex) discover_codex ;;
118
+ cursor) discover_cursor ;;
119
+ pi) discover_pi ;;
120
+ all)
121
+ discover_claude
122
+ discover_codex
123
+ discover_cursor
124
+ discover_pi
125
+ ;;
126
+ *)
127
+ echo "Unknown platform: $PLATFORM" >&2
128
+ exit 1
129
+ ;;
130
+ esac
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env python3
2
+ """Extract error signals from a Claude Code, Codex, Cursor, or Pi JSONL session file.
3
+
4
+ Usage:
5
+ cat <session.jsonl> | python3 extract-errors.py
6
+ cat <session.jsonl> | python3 extract-errors.py --output PATH
7
+
8
+ Auto-detects platform from the JSONL structure.
9
+ Note: Cursor agent transcripts do not log tool results, so no errors can be extracted.
10
+ Finds failed tool calls / commands and outputs them with timestamps.
11
+
12
+ When --output PATH is given, the extracted error log is written to PATH and
13
+ stdout receives only a one-line JSON status (_meta with wrote/bytes/stats).
14
+ This lets callers route bulk content to a scratch file without round-tripping
15
+ extraction bytes through orchestrator tool results.
16
+
17
+ Without --output, extracted content goes to stdout and ends with a _meta line.
18
+ """
19
+ import argparse
20
+ import io
21
+ import os
22
+ import sys
23
+ import json
24
+
25
+ parser = argparse.ArgumentParser(add_help=True)
26
+ parser.add_argument(
27
+ "--output",
28
+ metavar="PATH",
29
+ help="Write extracted errors to PATH instead of stdout. Stdout receives a one-line _meta status.",
30
+ )
31
+ args = parser.parse_args()
32
+
33
+ _original_stdout = sys.stdout
34
+ if args.output:
35
+ sys.stdout = io.StringIO()
36
+
37
+ stats = {"lines": 0, "parse_errors": 0, "errors_found": 0}
38
+
39
+
40
+ def summarize_error(raw):
41
+ """Extract a short error summary instead of dumping the full payload."""
42
+ text = str(raw).strip()
43
+ # Take the first non-empty line as the error message
44
+ for line in text.split("\n"):
45
+ line = line.strip()
46
+ if line:
47
+ return line[:200]
48
+ return text[:200]
49
+
50
+
51
+ def handle_claude(obj):
52
+ if obj.get("type") == "user":
53
+ content = obj.get("message", {}).get("content", [])
54
+ if isinstance(content, list):
55
+ for block in content:
56
+ if block.get("type") == "tool_result" and block.get("is_error"):
57
+ ts = obj.get("timestamp", "")[:19]
58
+ summary = summarize_error(block.get("content", ""))
59
+ print(f"[{ts}] [error] {summary}")
60
+ print("---")
61
+ stats["errors_found"] += 1
62
+
63
+
64
+ def handle_codex(obj):
65
+ if obj.get("type") == "event_msg":
66
+ p = obj.get("payload", {})
67
+ if p.get("type") == "exec_command_end":
68
+ output = p.get("aggregated_output", "")
69
+ stderr = p.get("stderr", "")
70
+ command = p.get("command", [])
71
+ cmd_str = command[-1] if command else ""
72
+
73
+ exit_match = None
74
+ if "Process exited with code " in output:
75
+ try:
76
+ code_str = output.split("Process exited with code ")[1].split("\n")[0]
77
+ exit_code = int(code_str)
78
+ if exit_code != 0:
79
+ exit_match = exit_code
80
+ except (IndexError, ValueError):
81
+ pass
82
+
83
+ if exit_match is not None or stderr:
84
+ ts = obj.get("timestamp", "")[:19]
85
+ error_summary = summarize_error(stderr if stderr else output)
86
+ print(f"[{ts}] [error] exit={exit_match} cmd={cmd_str[:120]}: {error_summary}")
87
+ print("---")
88
+ stats["errors_found"] += 1
89
+
90
+
91
+ def _pi_content_summary(content):
92
+ if isinstance(content, str):
93
+ return summarize_error(content)
94
+ if isinstance(content, list):
95
+ text = "\n".join(
96
+ block.get("text", "")
97
+ for block in content
98
+ if isinstance(block, dict) and block.get("type") in ("text", "toolError")
99
+ )
100
+ return summarize_error(text)
101
+ return summarize_error(content)
102
+
103
+
104
+ def _pi_active_path_objects(objects):
105
+ """Return only entries on Pi's active leaf-to-root path."""
106
+ by_id = {
107
+ obj.get("id"): obj
108
+ for obj in objects
109
+ if isinstance(obj.get("id"), str) and obj.get("type") != "session"
110
+ }
111
+ leaf_id = None
112
+ for obj in objects:
113
+ if obj.get("type") != "session" and isinstance(obj.get("id"), str):
114
+ leaf_id = obj["id"]
115
+ if not leaf_id:
116
+ return objects
117
+
118
+ active_ids = set()
119
+ current = leaf_id
120
+ while isinstance(current, str) and current and current not in active_ids:
121
+ active_ids.add(current)
122
+ parent = by_id.get(current, {}).get("parentId")
123
+ current = parent if isinstance(parent, str) else None
124
+ return [
125
+ obj
126
+ for obj in objects
127
+ if obj.get("type") == "session" or obj.get("id") in active_ids
128
+ ]
129
+
130
+
131
+ def _pi_context_objects(objects):
132
+ """Return Pi entries that participate in active LLM context."""
133
+ active = _pi_active_path_objects(objects)
134
+ compactions = [obj for obj in active if obj.get("type") == "compaction"]
135
+ if not compactions:
136
+ return active
137
+
138
+ first_kept = compactions[-1].get("firstKeptEntryId")
139
+ if not isinstance(first_kept, str):
140
+ return active
141
+
142
+ latest_compaction_id = compactions[-1].get("id")
143
+ started = False
144
+ found_first_kept = False
145
+ context = [obj for obj in active if obj.get("type") == "session"]
146
+ context.append(compactions[-1])
147
+ for obj in active:
148
+ if obj.get("type") == "session":
149
+ continue
150
+ if obj.get("id") == first_kept:
151
+ started = True
152
+ found_first_kept = True
153
+ if obj.get("id") == latest_compaction_id:
154
+ continue
155
+ if started:
156
+ context.append(obj)
157
+ return context if found_first_kept and len(context) > 1 else active
158
+
159
+
160
+ def handle_pi(obj):
161
+ if obj.get("type") != "message":
162
+ return
163
+ msg = obj.get("message", {})
164
+ if msg.get("role") == "bashExecution":
165
+ exit_code = msg.get("exitCode")
166
+ if exit_code in (None, 0) and not msg.get("cancelled"):
167
+ return
168
+ ts = obj.get("timestamp", "")[:19]
169
+ command = msg.get("command", "")
170
+ output = msg.get("output", "")
171
+ summary = summarize_error(output)
172
+ status = "cancelled" if msg.get("cancelled") else f"exit={exit_code}"
173
+ print(f"[{ts}] [error] {status} cmd={command[:120]}: {summary}")
174
+ print("---")
175
+ stats["errors_found"] += 1
176
+ return
177
+
178
+ if msg.get("role") != "toolResult":
179
+ return
180
+ content = msg.get("content", [])
181
+ is_error = bool(msg.get("isError"))
182
+ if isinstance(content, list):
183
+ is_error = is_error or any(
184
+ isinstance(block, dict) and block.get("type") == "toolError"
185
+ for block in content
186
+ )
187
+ if not is_error:
188
+ return
189
+
190
+ ts = obj.get("timestamp", "")[:19]
191
+ tool = msg.get("toolName", "unknown")
192
+ summary = _pi_content_summary(content)
193
+ print(f"[{ts}] [error] tool={tool}: {summary}")
194
+ print("---")
195
+ stats["errors_found"] += 1
196
+
197
+
198
+ # Auto-detect platform from first few lines, then process all
199
+ detected = None
200
+ buffer = []
201
+
202
+ for line in sys.stdin:
203
+ line = line.strip()
204
+ if not line:
205
+ continue
206
+ buffer.append(line)
207
+ stats["lines"] += 1
208
+
209
+ if not detected and len(buffer) <= 10:
210
+ try:
211
+ obj = json.loads(line)
212
+ if obj.get("type") == "session" and "cwd" in obj:
213
+ detected = "pi"
214
+ elif obj.get("type") in ("user", "assistant"):
215
+ detected = "claude"
216
+ elif obj.get("type") in ("session_meta", "turn_context", "response_item", "event_msg"):
217
+ detected = "codex"
218
+ elif obj.get("role") in ("user", "assistant") and "type" not in obj:
219
+ detected = "cursor"
220
+ except (json.JSONDecodeError, KeyError):
221
+ pass
222
+
223
+ # Cursor transcripts don't log tool results — no errors to extract
224
+ def handle_noop(obj):
225
+ pass
226
+
227
+ handlers = {"claude": handle_claude, "codex": handle_codex, "cursor": handle_noop, "pi": handle_pi}
228
+ handler = handlers.get(detected, handle_noop)
229
+
230
+ objects = []
231
+ for line in buffer:
232
+ try:
233
+ objects.append(json.loads(line))
234
+ except (json.JSONDecodeError, KeyError):
235
+ stats["parse_errors"] += 1
236
+
237
+ if detected == "pi":
238
+ objects = _pi_context_objects(objects)
239
+
240
+ for obj in objects:
241
+ try:
242
+ handler(obj)
243
+ except KeyError:
244
+ stats["parse_errors"] += 1
245
+
246
+ print(json.dumps({"_meta": True, **stats}))
247
+
248
+ if args.output:
249
+ body = sys.stdout.getvalue()
250
+ sys.stdout = _original_stdout
251
+ with open(args.output, "w") as f:
252
+ f.write(body)
253
+ bytes_written = os.path.getsize(args.output)
254
+ print(json.dumps({"_meta": True, "wrote": args.output, "bytes": bytes_written, **stats}))