@tyroneross/build-loop 0.36.0 → 0.43.0

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 (270) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +3 -3
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor/rules/build-loop-surface.mdc +12 -11
  6. package/.cursor/rules/skill-index.mdc +33 -0
  7. package/AGENTS.md +213 -34
  8. package/README.md +99 -31
  9. package/agents/advisor.md +4 -4
  10. package/agents/alignment-checker.md +2 -2
  11. package/agents/architecture-scout.md +4 -4
  12. package/agents/build-orchestrator.md +38 -36
  13. package/agents/database-assessor.md +11 -5
  14. package/agents/design-contract-specialist.md +8 -8
  15. package/agents/fact-checker.md +13 -3
  16. package/agents/fix-critique.md +2 -2
  17. package/agents/independent-auditor.md +60 -7
  18. package/agents/leak-scanner.md +82 -0
  19. package/agents/overfitting-reviewer.md +2 -2
  20. package/agents/plan-critic.md +1 -1
  21. package/agents/promotion-reviewer.md +5 -5
  22. package/agents/retrospective-synthesizer.md +138 -35
  23. package/agents/scope-auditor.md +82 -11
  24. package/agents/security-reviewer.md +56 -2
  25. package/agents/self-improvement-architect.md +17 -3
  26. package/agents/transcript-pattern-miner.md +5 -5
  27. package/agents/ui-validator.md +1 -1
  28. package/bin/build-loop-debugger.js +143 -0
  29. package/bin/build-loop-install.js +1 -4
  30. package/bin/build-loop-load-probe.js +345 -0
  31. package/codex-skills/build-loop/SKILL.md +28 -6
  32. package/commands/feedback.md +37 -0
  33. package/dist/src/interactive-verifier.d.ts +1 -14
  34. package/dist/src/interactive-verifier.d.ts.map +1 -1
  35. package/dist/src/interactive-verifier.js +6 -113
  36. package/dist/src/interactive-verifier.js.map +1 -1
  37. package/dist/src/quality.d.ts +5 -0
  38. package/dist/src/quality.d.ts.map +1 -0
  39. package/dist/src/quality.js +81 -0
  40. package/dist/src/quality.js.map +1 -0
  41. package/dist/src/storage.d.ts.map +1 -1
  42. package/dist/src/storage.js +37 -3
  43. package/dist/src/storage.js.map +1 -1
  44. package/docs/agent-surface-policy.md +35 -31
  45. package/docs/memory-setup.md +19 -0
  46. package/hooks/git/pre-push +65 -4
  47. package/hooks/hooks.json +95 -38
  48. package/hooks/pre-commit +20 -1
  49. package/hooks/pre-edit-rally-point.sh +10 -3
  50. package/hooks/session-start-codex-hook-trust.sh +30 -0
  51. package/hooks/session-start-git-hooks.sh +3 -1
  52. package/hooks/session-start-rally-point.sh +52 -4
  53. package/hooks/session-start-worktree-gc.sh +47 -94
  54. package/hooks/stop-transcript-sweep.sh +173 -0
  55. package/hooks/test_closeout.sh +14 -2
  56. package/package.json +8 -7
  57. package/scripts/README.md +1 -1
  58. package/scripts/_paths.py +65 -0
  59. package/scripts/groundwork_exchange.py +1012 -0
  60. package/scripts/install_memory.py +33 -1
  61. package/scripts/lessons_index/ingest.py +13 -2
  62. package/scripts/lessons_index/query.py +36 -13
  63. package/scripts/memory_context/__init__.py +108 -14
  64. package/scripts/memory_graph/__init__.py +5 -1
  65. package/scripts/project_resolver.py +42 -36
  66. package/scripts/sync_plugin_cache.py +37 -2
  67. package/skills/agent-rally-point/SKILL.md +46 -0
  68. package/skills/api-registry-bridge/SKILL.md +1 -1
  69. package/skills/architecture/dead/SKILL.md +1 -1
  70. package/skills/architecture/impact/SKILL.md +1 -1
  71. package/skills/architecture/review/SKILL.md +1 -1
  72. package/skills/architecture/rules/SKILL.md +3 -3
  73. package/skills/architecture/scan/SKILL.md +1 -1
  74. package/skills/architecture/trace/SKILL.md +1 -1
  75. package/skills/attribution-standard/SKILL.md +6 -6
  76. package/skills/auto-decision-capture/SKILL.md +31 -2
  77. package/skills/auto-finding-capture/SKILL.md +28 -1
  78. package/skills/build-loop/SKILL.md +131 -23
  79. package/skills/build-loop/fallbacks.md +16 -21
  80. package/skills/build-loop/phases/ui-validation.md +2 -2
  81. package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
  82. package/skills/build-loop/references/apple-native-planning.md +1 -1
  83. package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
  84. package/skills/build-loop/references/autonomy-dashboard.md +115 -0
  85. package/skills/build-loop/references/capability-routing.md +24 -2
  86. package/skills/build-loop/references/coordination.md +24 -6
  87. package/skills/build-loop/references/experiment-results-template.md +15 -3
  88. package/skills/build-loop/references/leadership.md +1 -1
  89. package/skills/build-loop/references/memory.md +14 -3
  90. package/skills/build-loop/references/modular-systems-pack.md +8 -0
  91. package/skills/build-loop/references/output-style.md +86 -0
  92. package/skills/build-loop/references/phase-1-assess.md +102 -2
  93. package/skills/build-loop/references/phase-2-plan.md +9 -1
  94. package/skills/build-loop/references/phase-3-execute.md +5 -2
  95. package/skills/build-loop/references/phase-4-review.md +85 -8
  96. package/skills/build-loop/references/phase-5-iterate.md +76 -8
  97. package/skills/build-loop/references/phase-6-learn.md +10 -17
  98. package/skills/build-loop/references/privileged-request-broker.md +254 -0
  99. package/skills/build-loop/references/resource-aware-execution.md +183 -0
  100. package/skills/build-loop/references/self-recursive-dev.md +2 -2
  101. package/skills/build-loop/references/status-output-format.md +207 -0
  102. package/skills/build-loop/references/verify-dispatch.md +56 -2
  103. package/skills/building-with-deepagents/SKILL.md +1 -1
  104. package/skills/claim-scope/SKILL.md +185 -0
  105. package/skills/color-engine/SKILL.md +103 -0
  106. package/skills/color-engine/_core.py +464 -0
  107. package/skills/color-engine/color_engine.py +175 -0
  108. package/skills/cost-rca/SKILL.md +61 -0
  109. package/skills/data-plane-worktrees/SKILL.md +139 -0
  110. package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
  111. package/skills/database-practice/SKILL.md +200 -0
  112. package/skills/database-practice/references/diagnostic-queries.sql +126 -0
  113. package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
  114. package/skills/database-practice/scripts/db_table_map.py +1244 -0
  115. package/skills/database-practice/scripts/test_db_table_map.py +514 -0
  116. package/skills/debug-loop/SKILL.md +36 -6
  117. package/skills/debugging-memory/SKILL.md +32 -430
  118. package/skills/debugging-memory/references/pattern-extraction.md +4 -4
  119. package/skills/debugging-memory/references/search.md +32 -120
  120. package/skills/debugging-memory/references/store.md +32 -126
  121. package/skills/debugging-memory/references/subagent-integration.md +1 -1
  122. package/skills/decision-queue/SKILL.md +251 -0
  123. package/skills/decision-queue/assets/template.html +1242 -0
  124. package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
  125. package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
  126. package/skills/defenseclaw-bridge/SKILL.md +2 -2
  127. package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
  128. package/skills/drain-proposals/SKILL.md +53 -0
  129. package/skills/focused-loop-builder/SKILL.md +31 -0
  130. package/skills/focused-loop-builder/references/spec-format.md +27 -0
  131. package/skills/handoff/SKILL.md +169 -8
  132. package/skills/ibr-bridge/SKILL.md +4 -1
  133. package/skills/knowledge/SKILL.md +26 -14
  134. package/skills/knowledge/references/review-mode.md +2 -3
  135. package/skills/knowledge/templates/madr-minimal.md +1 -1
  136. package/skills/mcp-builder/SKILL.md +1 -1
  137. package/skills/model-bakeoff/SKILL.md +48 -10
  138. package/skills/model-tiering/SKILL.md +92 -31
  139. package/skills/native-ax-driver/SKILL.md +38 -5
  140. package/skills/native-ax-driver/scripts/native_driver.py +278 -22
  141. package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
  142. package/skills/optimize/SKILL.md +1 -1
  143. package/skills/plugin-builder/SKILL.md +48 -1
  144. package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
  145. package/skills/plugin-builder/references/distribution.md +13 -2
  146. package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
  147. package/skills/plugin-tests/SKILL.md +2 -2
  148. package/skills/recursive-retrospective/SKILL.md +1 -1
  149. package/skills/repo-closeout/SKILL.md +17 -0
  150. package/skills/repo-closeout/agents/openai.yaml +4 -0
  151. package/skills/repo-maintenance/SKILL.md +179 -0
  152. package/skills/repo-maintenance/agents/openai.yaml +4 -0
  153. package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
  154. package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
  155. package/skills/repo-maintenance/references/safety-protocol.md +106 -0
  156. package/skills/repo-maintenance/references/stack-profiles.md +138 -0
  157. package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
  158. package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
  159. package/skills/repository-intelligence/SKILL.md +189 -0
  160. package/skills/repository-intelligence/agents/openai.yaml +4 -0
  161. package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
  162. package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
  163. package/skills/research/SKILL.md +12 -2
  164. package/skills/root-cause-analysis/SKILL.md +1 -1
  165. package/skills/runtime-parity-verification/SKILL.md +36 -1
  166. package/skills/security-methodology/SKILL.md +23 -10
  167. package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
  168. package/skills/security-methodology/references/cross-source-matrix.md +1 -1
  169. package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
  170. package/skills/security-scan/SKILL.md +55 -15
  171. package/skills/self-improve/SKILL.md +70 -50
  172. package/skills/silent-assumptions/SKILL.md +341 -0
  173. package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
  174. package/skills/spec-writing/SKILL.md +128 -24
  175. package/skills/spec-writing/scripts/check_checklist.py +114 -15
  176. package/skills/ui-design/SKILL.md +6 -4
  177. package/skills/ui-design/references/color-engine.md +132 -0
  178. package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
  179. package/skills/ui-design/references/ui-guidance-sources.md +1 -1
  180. package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
  181. package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
  182. package/plugin-artifacts/codex/AGENTS.md +0 -560
  183. package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
  184. package/plugin-artifacts/codex/LICENSE +0 -202
  185. package/plugin-artifacts/codex/README.md +0 -313
  186. package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
  187. package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
  188. package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
  189. package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
  190. package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
  191. package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
  192. package/plugin-artifacts/codex/references/backlog-system.md +0 -285
  193. package/plugin-artifacts/codex/references/capability-routing.md +0 -231
  194. package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
  195. package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
  196. package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
  197. package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
  198. package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
  199. package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
  200. package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
  201. package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
  202. package/plugin-artifacts/codex/references/leadership.md +0 -72
  203. package/plugin-artifacts/codex/references/memory-systems.md +0 -261
  204. package/plugin-artifacts/codex/references/memory.md +0 -313
  205. package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
  206. package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
  207. package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
  208. package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
  209. package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
  210. package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
  211. package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
  212. package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
  213. package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
  214. package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
  215. package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
  216. package/plugin-artifacts/codex/references/self-review.md +0 -234
  217. package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
  218. package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
  219. package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
  220. package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
  221. package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
  222. package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
  223. package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
  224. package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
  225. package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
  226. package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
  227. package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
  228. package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
  229. package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
  230. package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
  231. package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
  232. package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
  233. package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
  234. package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
  235. package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
  236. package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
  237. package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
  238. package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
  239. package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
  240. package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
  241. package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
  242. package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
  243. package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
  244. package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
  245. package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
  246. package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
  247. package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
  248. package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
  249. package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
  250. package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
  251. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
  252. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
  253. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
  254. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
  255. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
  256. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
  257. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
  258. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
  259. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
  260. package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
  261. package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
  262. package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
  263. package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
  264. package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
  265. package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
  266. package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
  267. package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
  268. package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
  269. package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
  270. package/scripts/build_codex_plugin_artifact.py +0 -321
@@ -1,321 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
3
- # SPDX-License-Identifier: Apache-2.0
4
- """Build the slim Codex plugin artifact.
5
-
6
- The source repo keeps Claude's full internal skill tree at ``skills/``. Codex
7
- auto-discovers root ``skills/*/SKILL.md`` entries, so the Codex marketplace must
8
- install from an artifact that exposes exactly one public skill.
9
- """
10
- from __future__ import annotations
11
-
12
- import argparse
13
- import filecmp
14
- import json
15
- import os
16
- import re
17
- import shutil
18
- import tempfile
19
- from pathlib import Path
20
- from typing import Iterable
21
-
22
-
23
- DEFAULT_TARGET = Path("plugin-artifacts/codex")
24
- IGNORED_NAMES = {".DS_Store", "__pycache__", ".pytest_cache"}
25
- IGNORED_SUFFIXES = {".pyc"}
26
- TOP_LEVEL_FILES = ("AGENTS.md", "README.md", "LICENSE")
27
- ASSET_FILES = (Path("assets") / "build-loop-plugin-icon.png",)
28
-
29
- # Bundle markdown points readers at ``references/<file>.md`` (root-relative).
30
- # The Claude source resolves that logical namespace across the repo's top-level
31
- # ``references/`` plus each skill's own ``references/``. The slim Codex bundle
32
- # ships only the ``build-loop`` skill, so those pointers dangle unless we mirror
33
- # every cited reference into ONE top-level ``references/`` dir at the bundle
34
- # root — the natural resolution point for both AGENTS.md (at root) and any
35
- # deeper file an LLM reads. Search order resolves drift deterministically: the
36
- # skill's own copy wins (it's the one already shipped in the skill tree), then
37
- # the repo root, then the ui-design skill.
38
- REFERENCE_SOURCE_DIRS = (
39
- Path("skills") / "build-loop" / "references",
40
- Path("references"),
41
- Path("skills") / "ui-design" / "references",
42
- )
43
- # A bare ``references/X.md`` pointer. Anchored to a path boundary so we don't
44
- # match foreign-skill prose like ``build-loop:deepagents`` references — those
45
- # are always written with the skill name in front (``The skill's
46
- # `references/anti-patterns.md```) and resolve inside that other skill, which
47
- # the slim bundle does not ship.
48
- _REFERENCE_POINTER_RE = re.compile(r"(?:^|[\s`(\[])references/([A-Za-z0-9_.-]+\.md)")
49
- # Pointers that name another skill's references dir in prose, not a build-loop
50
- # bundle file. They have no build-loop source and must not fail the check.
51
- FOREIGN_SKILL_REFERENCES = frozenset(
52
- {
53
- "anti-patterns.md", # build-loop:building-with-deepagents
54
- "stack-templates.md", # build-loop:logging-tracer
55
- "ios-notification-alarm-playbook.md", # build-loop:debugging-memory
56
- }
57
- )
58
- # Pre-existing, deliberate forward-reference placeholders in the source tree
59
- # (marked TBD in prose). They have no file anywhere — in the Claude tree either.
60
- # Not codex-introduced; fixing them is out of scope for the artifact builder, so
61
- # they are tolerated rather than blocking every bundle build. Keep this list
62
- # tight: a NEW unresolvable pointer on the primary surface must still fail.
63
- KNOWN_TBD_REFERENCES = frozenset(
64
- {
65
- "brief-filters.md", # references/implementer-envelope-schema.md: "(TBD)"
66
- }
67
- )
68
-
69
-
70
- def cited_reference_basenames(*roots: Path) -> set[str]:
71
- """Every bare ``references/<file>.md`` pointer across the given markdown roots."""
72
- cited: set[str] = set()
73
- for root in roots:
74
- for md in root.rglob("*.md"):
75
- cited.update(
76
- _REFERENCE_POINTER_RE.findall(
77
- md.read_text(encoding="utf-8", errors="ignore")
78
- )
79
- )
80
- return cited
81
-
82
-
83
- def resolve_reference_source(source: Path, basename: str) -> Path | None:
84
- """Locate a cited reference file in the build-loop source search paths."""
85
- for rel_dir in REFERENCE_SOURCE_DIRS:
86
- candidate = source / rel_dir / basename
87
- if candidate.is_file():
88
- return candidate
89
- return None
90
-
91
-
92
- def mirror_references(source: Path, bundle_root: Path) -> None:
93
- """Copy the transitive closure of cited references into ``<bundle>/references/``.
94
-
95
- Iterates to a fixpoint: a mirrored reference file may itself cite further
96
- ``references/X.md``, so re-scan after each copy until no new resolvable
97
- pointer appears. Makes every root-relative ``references/X.md`` pointer in the
98
- bundle resolve at the bundle root. Foreign-skill and known-TBD pointers are
99
- skipped (no build-loop source); a genuinely unexpected unresolvable pointer
100
- is left for ``check_reference_pointers`` to adjudicate by surface.
101
- """
102
- out_dir = bundle_root / "references"
103
- copied: set[str] = set()
104
- while True:
105
- cited = cited_reference_basenames(bundle_root)
106
- new_resolvable = False
107
- for basename in sorted(cited - copied):
108
- copied.add(basename)
109
- if basename in FOREIGN_SKILL_REFERENCES or basename in KNOWN_TBD_REFERENCES:
110
- continue
111
- src_file = resolve_reference_source(source, basename)
112
- if src_file is not None:
113
- copy_file(src_file, out_dir / basename)
114
- new_resolvable = True
115
- if not new_resolvable:
116
- break
117
-
118
-
119
- def check_reference_pointers(bundle_root: Path) -> None:
120
- """Assert every ``references/X.md`` pointer on the bundle's PRIMARY surface resolves.
121
-
122
- Primary surface = the files a Codex user actually lands on: top-level
123
- AGENTS.md / README.md and the whole ``skills/build-loop`` tree. Resolution
124
- target is the mirrored top-level ``<bundle>/references/``. Foreign-skill and
125
- known-TBD pointers are allowlisted. A dangling primary-surface pointer is a
126
- real regression and fails the build. Pointers that appear ONLY inside
127
- transitively-mirrored reference files (often forward TBDs) are tolerated —
128
- fixing unrelated source dead-links is not the artifact builder's job.
129
- """
130
- refs_dir = bundle_root / "references"
131
- surface_roots = [bundle_root / "skills" / "build-loop"]
132
- surface_roots += [
133
- bundle_root / name for name in ("AGENTS.md", "README.md") if (bundle_root / name).is_file()
134
- ]
135
- # rglob on a file path yields nothing; scan top-level files explicitly.
136
- cited: set[str] = set()
137
- for root in surface_roots:
138
- if root.is_dir():
139
- cited |= cited_reference_basenames(root)
140
- elif root.is_file():
141
- cited |= set(
142
- _REFERENCE_POINTER_RE.findall(root.read_text(encoding="utf-8", errors="ignore"))
143
- )
144
- dangling = sorted(
145
- b
146
- for b in cited
147
- if b not in FOREIGN_SKILL_REFERENCES
148
- and b not in KNOWN_TBD_REFERENCES
149
- and not (refs_dir / b).is_file()
150
- )
151
- if dangling:
152
- raise ArtifactError(
153
- "dangling reference pointers on the primary surface (no file at "
154
- "bundle references/): " + ", ".join(dangling)
155
- )
156
-
157
-
158
- class ArtifactError(RuntimeError):
159
- pass
160
-
161
-
162
- def ignore_generated(_dir: str, names: list[str]) -> set[str]:
163
- ignored = set()
164
- for name in names:
165
- if name in IGNORED_NAMES:
166
- ignored.add(name)
167
- continue
168
- if any(name.endswith(suffix) for suffix in IGNORED_SUFFIXES):
169
- ignored.add(name)
170
- return ignored
171
-
172
-
173
- def copy_file(source: Path, target: Path) -> None:
174
- if not source.is_file():
175
- raise ArtifactError(f"missing required file: {source}")
176
- target.parent.mkdir(parents=True, exist_ok=True)
177
- shutil.copy2(source, target)
178
-
179
-
180
- def copy_tree(source: Path, target: Path) -> None:
181
- if not source.is_dir():
182
- raise ArtifactError(f"missing required directory: {source}")
183
- shutil.copytree(source, target, ignore=ignore_generated)
184
-
185
-
186
- def write_codex_manifest(source: Path, target: Path) -> None:
187
- manifest_path = source / ".codex-plugin" / "plugin.json"
188
- if not manifest_path.is_file():
189
- raise ArtifactError(f"missing required file: {manifest_path}")
190
- manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
191
- manifest["skills"] = "./skills"
192
- target.parent.mkdir(parents=True, exist_ok=True)
193
- target.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
194
-
195
-
196
- def write_notice(target: Path) -> None:
197
- target.write_text(
198
- "\n".join(
199
- [
200
- "# Codex Build Loop Artifact",
201
- "",
202
- "Generated by `python3 scripts/build_codex_plugin_artifact.py`.",
203
- "This artifact is the Codex marketplace install surface.",
204
- "It exposes exactly one public skill: `build-loop`.",
205
- "",
206
- ]
207
- ),
208
- encoding="utf-8",
209
- )
210
-
211
-
212
- def skill_files(root: Path) -> list[Path]:
213
- return sorted(root.rglob("SKILL.md"))
214
-
215
-
216
- def validate_artifact(target: Path) -> None:
217
- manifest_path = target / ".codex-plugin" / "plugin.json"
218
- skills_root = target / "skills"
219
- if not manifest_path.is_file():
220
- raise ArtifactError(f"artifact missing {manifest_path}")
221
- manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
222
- if manifest.get("skills") != "./skills":
223
- raise ArtifactError("artifact Codex manifest must use skills=./skills")
224
-
225
- files = skill_files(skills_root)
226
- rel_files = [str(path.relative_to(target)) for path in files]
227
- if rel_files != ["skills/build-loop/SKILL.md"]:
228
- raise ArtifactError(f"artifact must expose exactly one SKILL.md, got {rel_files}")
229
-
230
- for rel_path in ASSET_FILES:
231
- if not (target / rel_path).is_file():
232
- raise ArtifactError(f"artifact missing asset: {rel_path}")
233
-
234
- check_reference_pointers(target)
235
-
236
-
237
- def build_artifact(source: Path, target: Path) -> None:
238
- source = source.resolve()
239
- target = target.resolve()
240
- if source == target or target in source.parents:
241
- raise ArtifactError(f"refusing to write artifact above source: {target}")
242
-
243
- parent = target.parent
244
- parent.mkdir(parents=True, exist_ok=True)
245
- with tempfile.TemporaryDirectory(prefix=".codex-artifact-", dir=str(parent)) as tmp_raw:
246
- tmp = Path(tmp_raw)
247
- write_codex_manifest(source, tmp / ".codex-plugin" / "plugin.json")
248
- for name in TOP_LEVEL_FILES:
249
- copy_file(source / name, tmp / name)
250
- for rel_path in ASSET_FILES:
251
- copy_file(source / rel_path, tmp / rel_path)
252
- copy_tree(source / "skills" / "build-loop", tmp / "skills" / "build-loop")
253
- copy_file(source / "docs" / "agent-surface-policy.md", tmp / "docs" / "agent-surface-policy.md")
254
- write_notice(tmp / "BUILD-ARTIFACT.md")
255
- # Mirror cited references AFTER the skill tree + top-level files exist so
256
- # the pointer scan sees every citing file.
257
- mirror_references(source, tmp)
258
- validate_artifact(tmp)
259
-
260
- if target.exists():
261
- shutil.rmtree(target)
262
- os.replace(tmp, target)
263
-
264
-
265
- def iter_files(root: Path) -> Iterable[Path]:
266
- for path in sorted(root.rglob("*")):
267
- if path.is_file():
268
- yield path
269
-
270
-
271
- def assert_same_tree(expected: Path, actual: Path) -> None:
272
- expected_files = {path.relative_to(expected) for path in iter_files(expected)}
273
- actual_files = {path.relative_to(actual) for path in iter_files(actual)}
274
- if expected_files != actual_files:
275
- missing = sorted(str(path) for path in expected_files - actual_files)
276
- extra = sorted(str(path) for path in actual_files - expected_files)
277
- raise ArtifactError(f"artifact file set differs; missing={missing}, extra={extra}")
278
- for rel in sorted(expected_files):
279
- if not filecmp.cmp(expected / rel, actual / rel, shallow=False):
280
- raise ArtifactError(f"artifact file differs: {rel}")
281
-
282
-
283
- def check_artifact(source: Path, target: Path) -> None:
284
- parent = target.resolve().parent
285
- parent.mkdir(parents=True, exist_ok=True)
286
- with tempfile.TemporaryDirectory(prefix=".codex-artifact-check-", dir=str(parent)) as tmp_raw:
287
- tmp = Path(tmp_raw) / "codex"
288
- build_artifact(source, tmp)
289
- assert_same_tree(tmp, target.resolve())
290
- validate_artifact(target.resolve())
291
-
292
-
293
- def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
294
- parser = argparse.ArgumentParser(description=__doc__)
295
- parser.add_argument("--source", default=".", help="Build Loop source repo root.")
296
- parser.add_argument("--target", default=str(DEFAULT_TARGET), help="Codex artifact output directory.")
297
- parser.add_argument("--check", action="store_true", help="Fail if the artifact is missing or stale.")
298
- return parser.parse_args(argv)
299
-
300
-
301
- def main(argv: list[str] | None = None) -> int:
302
- args = parse_args(argv)
303
- source = Path(args.source).expanduser().resolve()
304
- target = Path(args.target).expanduser()
305
- if not target.is_absolute():
306
- target = source / target
307
- try:
308
- if args.check:
309
- check_artifact(source, target)
310
- print(f"codex artifact up to date: {target}")
311
- else:
312
- build_artifact(source, target)
313
- print(f"codex artifact written: {target}")
314
- return 0
315
- except ArtifactError as exc:
316
- print(f"error: {exc}")
317
- return 1
318
-
319
-
320
- if __name__ == "__main__":
321
- raise SystemExit(main())