@tyroneross/build-loop 0.30.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.
- package/.agents/plugins/marketplace.json +10 -0
- package/.claude-plugin/marketplace.json +38 -0
- package/.claude-plugin/plugin.json +30 -0
- package/.codex-plugin/plugin.json +41 -0
- package/.cursor/rules/build-loop-surface.mdc +22 -0
- package/AGENTS.md +498 -0
- package/LICENSE +202 -0
- package/README.md +403 -0
- package/agents/alignment-checker.md +124 -0
- package/agents/api-assessor.md +136 -0
- package/agents/architecture-scout.md +185 -0
- package/agents/assessment-orchestrator.md +163 -0
- package/agents/build-orchestrator.md +198 -0
- package/agents/database-assessor.md +133 -0
- package/agents/design-contract-specialist.md +239 -0
- package/agents/fact-checker.md +69 -0
- package/agents/fix-critique.md +161 -0
- package/agents/frontend-assessor.md +136 -0
- package/agents/implementer.md +185 -0
- package/agents/independent-auditor.md +143 -0
- package/agents/mock-scanner.md +78 -0
- package/agents/optimize-runner.md +112 -0
- package/agents/overfitting-reviewer.md +96 -0
- package/agents/performance-assessor.md +159 -0
- package/agents/plan-critic.md +85 -0
- package/agents/promotion-reviewer.md +121 -0
- package/agents/recurring-pattern-detector.md +248 -0
- package/agents/retrospective-synthesizer.md +109 -0
- package/agents/root-cause-investigator.md +285 -0
- package/agents/scope-auditor.md +121 -0
- package/agents/security-reviewer.md +151 -0
- package/agents/self-improvement-architect.md +125 -0
- package/agents/synthesis-critic.md +99 -0
- package/agents/transcript-pattern-miner.md +165 -0
- package/agents/ui-validator.md +193 -0
- package/codex-skills/build-loop/SKILL.md +20 -0
- package/codex-skills/debug-loop/SKILL.md +18 -0
- package/codex-skills/handoff/SKILL.md +22 -0
- package/codex-skills/knowledge/SKILL.md +21 -0
- package/codex-skills/optimize/SKILL.md +18 -0
- package/codex-skills/research/SKILL.md +18 -0
- package/commands/agent-rally-point.md +301 -0
- package/commands/assess.md +41 -0
- package/commands/debug.md +20 -0
- package/commands/debugger-detail.md +34 -0
- package/commands/debugger-scan.md +15 -0
- package/commands/debugger-status.md +20 -0
- package/commands/debugger.md +32 -0
- package/commands/handoff.md +113 -0
- package/commands/knowledge-review.md +16 -0
- package/commands/optimize.md +31 -0
- package/commands/plan-verify.md +39 -0
- package/commands/promote-experiment.md +129 -0
- package/commands/research.md +22 -0
- package/commands/run.md +12 -0
- package/commands/self-review.md +51 -0
- package/commands/start-prd.md +57 -0
- package/commands/test.md +34 -0
- package/dist/src/assessment-orchestrator.d.ts +78 -0
- package/dist/src/assessment-orchestrator.d.ts.map +1 -0
- package/dist/src/assessment-orchestrator.js +304 -0
- package/dist/src/assessment-orchestrator.js.map +1 -0
- package/dist/src/audit-miner.d.ts +21 -0
- package/dist/src/audit-miner.d.ts.map +1 -0
- package/dist/src/audit-miner.js +421 -0
- package/dist/src/audit-miner.js.map +1 -0
- package/dist/src/batch-operations.d.ts +30 -0
- package/dist/src/batch-operations.d.ts.map +1 -0
- package/dist/src/batch-operations.js +339 -0
- package/dist/src/batch-operations.js.map +1 -0
- package/dist/src/config.d.ts +83 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +176 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context-engine.d.ts +45 -0
- package/dist/src/context-engine.d.ts.map +1 -0
- package/dist/src/context-engine.js +135 -0
- package/dist/src/context-engine.js.map +1 -0
- package/dist/src/debug-wrapper.d.ts +58 -0
- package/dist/src/debug-wrapper.d.ts.map +1 -0
- package/dist/src/debug-wrapper.js +285 -0
- package/dist/src/debug-wrapper.js.map +1 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +149 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interactive-verifier.d.ts +26 -0
- package/dist/src/interactive-verifier.d.ts.map +1 -0
- package/dist/src/interactive-verifier.js +435 -0
- package/dist/src/interactive-verifier.js.map +1 -0
- package/dist/src/lessons.d.ts +59 -0
- package/dist/src/lessons.d.ts.map +1 -0
- package/dist/src/lessons.js +172 -0
- package/dist/src/lessons.js.map +1 -0
- package/dist/src/log-reader.d.ts +39 -0
- package/dist/src/log-reader.d.ts.map +1 -0
- package/dist/src/log-reader.js +291 -0
- package/dist/src/log-reader.js.map +1 -0
- package/dist/src/logger.d.ts +59 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +328 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/parallel-retrieval.d.ts +52 -0
- package/dist/src/parallel-retrieval.d.ts.map +1 -0
- package/dist/src/parallel-retrieval.js +309 -0
- package/dist/src/parallel-retrieval.js.map +1 -0
- package/dist/src/pattern-extractor.d.ts +30 -0
- package/dist/src/pattern-extractor.d.ts.map +1 -0
- package/dist/src/pattern-extractor.js +386 -0
- package/dist/src/pattern-extractor.js.map +1 -0
- package/dist/src/result-aggregator.d.ts +44 -0
- package/dist/src/result-aggregator.d.ts.map +1 -0
- package/dist/src/result-aggregator.js +315 -0
- package/dist/src/result-aggregator.js.map +1 -0
- package/dist/src/retrieval.d.ts +139 -0
- package/dist/src/retrieval.d.ts.map +1 -0
- package/dist/src/retrieval.js +724 -0
- package/dist/src/retrieval.js.map +1 -0
- package/dist/src/setup/auto-setup.d.ts +15 -0
- package/dist/src/setup/auto-setup.d.ts.map +1 -0
- package/dist/src/setup/auto-setup.js +157 -0
- package/dist/src/setup/auto-setup.js.map +1 -0
- package/dist/src/setup/configure-hooks.d.ts +8 -0
- package/dist/src/setup/configure-hooks.d.ts.map +1 -0
- package/dist/src/setup/configure-hooks.js +16 -0
- package/dist/src/setup/configure-hooks.js.map +1 -0
- package/dist/src/setup/create-slash-commands.d.ts +8 -0
- package/dist/src/setup/create-slash-commands.d.ts.map +1 -0
- package/dist/src/setup/create-slash-commands.js +101 -0
- package/dist/src/setup/create-slash-commands.js.map +1 -0
- package/dist/src/setup/index.d.ts +8 -0
- package/dist/src/setup/index.d.ts.map +1 -0
- package/dist/src/setup/index.js +17 -0
- package/dist/src/setup/index.js.map +1 -0
- package/dist/src/setup/inject-claude-md.d.ts +10 -0
- package/dist/src/setup/inject-claude-md.d.ts.map +1 -0
- package/dist/src/setup/inject-claude-md.js +150 -0
- package/dist/src/setup/inject-claude-md.js.map +1 -0
- package/dist/src/setup/uninstall.d.ts +22 -0
- package/dist/src/setup/uninstall.d.ts.map +1 -0
- package/dist/src/setup/uninstall.js +235 -0
- package/dist/src/setup/uninstall.js.map +1 -0
- package/dist/src/storage.d.ts +192 -0
- package/dist/src/storage.d.ts.map +1 -0
- package/dist/src/storage.js +1037 -0
- package/dist/src/storage.js.map +1 -0
- package/dist/src/string-similarity.d.ts +8 -0
- package/dist/src/string-similarity.d.ts.map +1 -0
- package/dist/src/string-similarity.js +57 -0
- package/dist/src/string-similarity.js.map +1 -0
- package/dist/src/traces/adapters/browser.d.ts +69 -0
- package/dist/src/traces/adapters/browser.d.ts.map +1 -0
- package/dist/src/traces/adapters/browser.js +280 -0
- package/dist/src/traces/adapters/browser.js.map +1 -0
- package/dist/src/traces/adapters/index.d.ts +23 -0
- package/dist/src/traces/adapters/index.d.ts.map +1 -0
- package/dist/src/traces/adapters/index.js +67 -0
- package/dist/src/traces/adapters/index.js.map +1 -0
- package/dist/src/traces/adapters/langchain.d.ts +42 -0
- package/dist/src/traces/adapters/langchain.d.ts.map +1 -0
- package/dist/src/traces/adapters/langchain.js +151 -0
- package/dist/src/traces/adapters/langchain.js.map +1 -0
- package/dist/src/traces/adapters/opentelemetry.d.ts +46 -0
- package/dist/src/traces/adapters/opentelemetry.d.ts.map +1 -0
- package/dist/src/traces/adapters/opentelemetry.js +164 -0
- package/dist/src/traces/adapters/opentelemetry.js.map +1 -0
- package/dist/src/traces/adapters/sentry.d.ts +58 -0
- package/dist/src/traces/adapters/sentry.d.ts.map +1 -0
- package/dist/src/traces/adapters/sentry.js +212 -0
- package/dist/src/traces/adapters/sentry.js.map +1 -0
- package/dist/src/traces/index.d.ts +10 -0
- package/dist/src/traces/index.d.ts.map +1 -0
- package/dist/src/traces/index.js +45 -0
- package/dist/src/traces/index.js.map +1 -0
- package/dist/src/traces/storage.d.ts +78 -0
- package/dist/src/traces/storage.d.ts.map +1 -0
- package/dist/src/traces/storage.js +399 -0
- package/dist/src/traces/storage.js.map +1 -0
- package/dist/src/traces/summarizer.d.ts +83 -0
- package/dist/src/traces/summarizer.d.ts.map +1 -0
- package/dist/src/traces/summarizer.js +247 -0
- package/dist/src/traces/summarizer.js.map +1 -0
- package/dist/src/traces/types.d.ts +365 -0
- package/dist/src/traces/types.d.ts.map +1 -0
- package/dist/src/traces/types.js +14 -0
- package/dist/src/traces/types.js.map +1 -0
- package/dist/src/types.d.ts +495 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +27 -0
- package/dist/src/types.js.map +1 -0
- package/docs/agent-surface-policy.md +45 -0
- package/docs/memory-setup.md +226 -0
- package/hooks/_arch_scan_bg.py +88 -0
- package/hooks/_plugin_drift_check_bg.py +85 -0
- package/hooks/_session_start_lib.sh +42 -0
- package/hooks/git/pre-push +141 -0
- package/hooks/hooks.json +126 -0
- package/hooks/post-commit +30 -0
- package/hooks/pre-commit +29 -0
- package/hooks/pre-edit-apppulse.sh +6 -0
- package/hooks/pre-edit-architecture.sh +106 -0
- package/hooks/pre-edit-rally-point.sh +92 -0
- package/hooks/session-start-apppulse.sh +6 -0
- package/hooks/session-start-architecture.sh +10 -0
- package/hooks/session-start-git-hooks.sh +12 -0
- package/hooks/session-start-plugin-drift.sh +27 -0
- package/hooks/session-start-rally-point.sh +44 -0
- package/hooks/session-start-retrieval.sh +24 -0
- package/hooks/session-start-worktree-gc.sh +105 -0
- package/hooks/test_apppulse_hooks.sh +6 -0
- package/hooks/test_rally_point_hooks.sh +388 -0
- package/hooks/test_sec008_hooks.sh +66 -0
- package/package.json +111 -0
- package/scripts/README.md +301 -0
- package/scripts/_db_url.py +61 -0
- package/scripts/_paths.py +445 -0
- package/scripts/blm.py +162 -0
- package/scripts/blm_api.py +263 -0
- package/scripts/check_cache_sync.py +490 -0
- package/scripts/embed_backend.py +475 -0
- package/scripts/install_memory.py +556 -0
- package/scripts/lessons_index/__init__.py +77 -0
- package/scripts/lessons_index/__main__.py +135 -0
- package/scripts/lessons_index/ingest.py +288 -0
- package/scripts/lessons_index/query.py +285 -0
- package/scripts/lessons_index/schema.py +114 -0
- package/scripts/memory_context/__init__.py +610 -0
- package/scripts/memory_graph/__init__.py +393 -0
- package/scripts/project_resolver.py +172 -0
- package/scripts/prune_codex_plugin_cache.py +23 -0
- package/scripts/prune_plugin_cache.py +359 -0
- package/scripts/semantic_index/__init__.py +482 -0
- package/scripts/semantic_index/_bench_hybrid.py +175 -0
- package/scripts/semantic_index/backfill.py +263 -0
- package/scripts/semantic_index/hybrid.py +174 -0
- package/scripts/semantic_index/test_backfill.py +292 -0
- package/scripts/semantic_index/test_hybrid.py +541 -0
- package/scripts/sync_navgator_lessons.py +666 -0
- package/scripts/sync_plugin_cache.py +388 -0
- package/skills/agent-rally-point/SKILL.md +165 -0
- package/skills/agent-rally-watcher/SKILL.md +83 -0
- package/skills/api-registry-bridge/SKILL.md +59 -0
- package/skills/architecture/dead/SKILL.md +56 -0
- package/skills/architecture/impact/SKILL.md +88 -0
- package/skills/architecture/review/SKILL.md +227 -0
- package/skills/architecture/rules/SKILL.md +72 -0
- package/skills/architecture/scan/SKILL.md +79 -0
- package/skills/architecture/trace/SKILL.md +65 -0
- package/skills/attribution-standard/SKILL.md +122 -0
- package/skills/authentication/SKILL.md +81 -0
- package/skills/authentication/references/better-auth-magic-link.md +135 -0
- package/skills/authentication/references/better-auth-setup.md +224 -0
- package/skills/authentication/references/google-calendar-sync.md +278 -0
- package/skills/authentication/references/google-cloud-console.md +159 -0
- package/skills/authentication/references/google-geocoding-directions.md +126 -0
- package/skills/authentication/references/google-lessons-example-web-app.md +177 -0
- package/skills/authentication/references/google-maps.md +162 -0
- package/skills/authentication/references/google-oauth-setup.md +343 -0
- package/skills/authentication/references/google-places.md +173 -0
- package/skills/authentication/references/lessons-example-web-app-better-auth.md +126 -0
- package/skills/authentication/references/resend-email.md +227 -0
- package/skills/authentication/references/resend-otp-magic-link.md +153 -0
- package/skills/authentication/references/supabase-auth.md +172 -0
- package/skills/auto-decision-capture/SKILL.md +419 -0
- package/skills/build-loop/SKILL.md +516 -0
- package/skills/build-loop/detect-plugins.mjs +82 -0
- package/skills/build-loop/eval-guide.md +65 -0
- package/skills/build-loop/fallbacks.md +549 -0
- package/skills/build-loop/phases/fact-check.md +42 -0
- package/skills/build-loop/phases/ui-validation.md +267 -0
- package/skills/build-loop/references/apple-native-planning.md +439 -0
- package/skills/build-loop/references/capability-routing.md +181 -0
- package/skills/build-loop/references/codex-subagents.md +98 -0
- package/skills/build-loop/references/coordination.md +161 -0
- package/skills/build-loop/references/correction-aware-capture.md +177 -0
- package/skills/build-loop/references/independent-auditor.md +72 -0
- package/skills/build-loop/references/intent-capability-pack.md +170 -0
- package/skills/build-loop/references/intent-exploration-prompts.md +96 -0
- package/skills/build-loop/references/leadership.md +72 -0
- package/skills/build-loop/references/memory.md +284 -0
- package/skills/build-loop/references/modular-systems-pack.md +96 -0
- package/skills/build-loop/references/output-style.md +129 -0
- package/skills/build-loop/references/pay-it-forward-arch.md +98 -0
- package/skills/build-loop/references/phase-1-assess.md +218 -0
- package/skills/build-loop/references/phase-2-plan.md +77 -0
- package/skills/build-loop/references/phase-3-execute.md +47 -0
- package/skills/build-loop/references/phase-4-review.md +310 -0
- package/skills/build-loop/references/phase-5-iterate.md +71 -0
- package/skills/build-loop/references/phase-6-learn.md +56 -0
- package/skills/build-loop/references/recent-design-structures.md +274 -0
- package/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
- package/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
- package/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
- package/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
- package/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
- package/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
- package/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
- package/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
- package/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
- package/skills/build-loop/references/self-recursive-dev.md +77 -0
- package/skills/build-loop/references/self-review.md +232 -0
- package/skills/build-loop/references/ui-io-contract.md +116 -0
- package/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
- package/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
- package/skills/build-loop/templates/backlog-item.md +35 -0
- package/skills/build-loop/templates/codex-worker-prompt.md +89 -0
- package/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
- package/skills/build-loop/templates/ux-fix-plan.md +40 -0
- package/skills/building-with-deepagents/SKILL.md +195 -0
- package/skills/building-with-deepagents/references/anti-patterns.md +141 -0
- package/skills/building-with-deepagents/references/api-quick-reference.md +184 -0
- package/skills/capabilities/SKILL.md +91 -0
- package/skills/debug-loop/SKILL.md +278 -0
- package/skills/debug-loop/references/convergence-rules.md +145 -0
- package/skills/debug-loop/references/swiftui-macos-clunky-ui-debugger.html +823 -0
- package/skills/debugging/assess/SKILL.md +111 -0
- package/skills/debugging/debug-loop/SKILL.md +231 -0
- package/skills/debugging/memory/SKILL.md +147 -0
- package/skills/debugging/store/SKILL.md +153 -0
- package/skills/debugging-memory/SKILL.md +440 -0
- package/skills/debugging-memory/examples/incident-example.json +67 -0
- package/skills/debugging-memory/references/incident-documentation.md +280 -0
- package/skills/debugging-memory/references/ios-notification-alarm-playbook.md +300 -0
- package/skills/debugging-memory/references/pattern-extraction.md +163 -0
- package/skills/debugging-memory/references/subagent-integration.md +312 -0
- package/skills/defenseclaw-bridge/SKILL.md +156 -0
- package/skills/defenseclaw-bridge/references/dc-config-mapping.md +162 -0
- package/skills/defenseclaw-bridge/references/output-format.md +108 -0
- package/skills/handoff/SKILL.md +94 -0
- package/skills/ibr-bridge/SKILL.md +68 -0
- package/skills/knowledge/SKILL.md +127 -0
- package/skills/knowledge/references/recall-integration.md +83 -0
- package/skills/knowledge/templates/madr-minimal.md +56 -0
- package/skills/knowledge-review/SKILL.md +112 -0
- package/skills/logging-tracer/SKILL.md +202 -0
- package/skills/logging-tracer/references/log-analysis.md +128 -0
- package/skills/logging-tracer/references/stack-templates.md +274 -0
- package/skills/logging-tracer-bridge/SKILL.md +70 -0
- package/skills/mcp-builder/SKILL.md +278 -0
- package/skills/mcp-builder/references/mcp-security.md +106 -0
- package/skills/model-tiering/SKILL.md +216 -0
- package/skills/native-ax-driver/SKILL.md +220 -0
- package/skills/native-ax-driver/scripts/layout_fill.py +222 -0
- package/skills/native-ax-driver/scripts/native_driver.py +495 -0
- package/skills/native-ax-driver/swift/bl-ax-driver/Package.swift +20 -0
- package/skills/native-ax-driver/swift/bl-ax-driver/Sources/main.swift +542 -0
- package/skills/optimize/SKILL.md +202 -0
- package/skills/optimize/profiles.md +61 -0
- package/skills/plan-verify/SKILL.md +115 -0
- package/skills/plan-verify/test-fixtures/example-app-v20-findings.json +27 -0
- package/skills/plan-verify/test-fixtures/example-app-v20.md +42 -0
- package/skills/plan-verify/test-fixtures/example-app-v22-findings.json +15 -0
- package/skills/plan-verify/test-fixtures/example-app-v22.md +1608 -0
- package/skills/plan-verify/test-fixtures/unrelated-good-plan-findings.json +15 -0
- package/skills/plan-verify/test-fixtures/unrelated-good-plan.md +55 -0
- package/skills/plugin-builder/SKILL.md +329 -0
- package/skills/plugin-builder/references/authoritative-sources.md +104 -0
- package/skills/plugin-builder/references/build-loop-phase-guidance.md +94 -0
- package/skills/plugin-builder/references/components-guide.md +221 -0
- package/skills/plugin-builder/references/distribution.md +317 -0
- package/skills/plugin-builder/references/dual-host-claude-codex.md +220 -0
- package/skills/plugin-builder/references/hooks-reference.md +210 -0
- package/skills/plugin-builder/references/manifest-schema.md +111 -0
- package/skills/plugin-builder/references/plugin-hygiene-lessons.md +307 -0
- package/skills/plugin-tests/SKILL.md +94 -0
- package/skills/prd-bridge/SKILL.md +135 -0
- package/skills/research/SKILL.md +80 -0
- package/skills/security-methodology/SKILL.md +105 -0
- package/skills/security-methodology/references/cross-source-matrix.md +77 -0
- package/skills/security-methodology/references/mitre-atlas-starter.md +83 -0
- package/skills/security-methodology/references/nist-600-1-mapping.md +119 -0
- package/skills/security-methodology/references/owasp-agentic-top-10.md +157 -0
- package/skills/security-methodology/references/owasp-llm-top-10.md +144 -0
- package/skills/security-methodology/references/owasp-web-top-10.md +65 -0
- package/skills/self-improve/SKILL.md +298 -0
- package/skills/spec-writing/SKILL.md +548 -0
- package/skills/spec-writing/scripts/check_checklist.py +478 -0
- package/skills/sync-skills/SKILL.md +132 -0
- package/skills/telemetry/SKILL.md +66 -0
- package/skills/ui-design/SKILL.md +75 -0
- package/skills/ui-design/references/design-patterns-multi.md +165 -0
- package/skills/ui-design/references/design-preferences-from-owned-apps.md +150 -0
- package/skills/ui-design/references/evidence-capture-policy.md +55 -0
- package/skills/ui-design/references/ui-guidance-sources.md +330 -0
- package/skills/ui-design/references/universal-design-principles.alt.md +182 -0
- package/skills/ui-design/references/universal-design-principles.md +419 -0
- package/templates/memory/MEMORY.md.template +55 -0
- package/templates/memory/constitution.md.template +64 -0
- package/templates/memory/manifest.json +47 -0
|
@@ -0,0 +1,490 @@
|
|
|
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
|
+
"""Check source repo ↔ plugin cache sync for plugin work.
|
|
5
|
+
|
|
6
|
+
For Claude Code, greps the source repo for ``${CLAUDE_PLUGIN_ROOT}/`` references
|
|
7
|
+
in docs/manifests/scripts, resolves each path in both the source repo and the
|
|
8
|
+
cache, and reports files that diverge.
|
|
9
|
+
|
|
10
|
+
For Codex, checks the installed Codex plugin cache against Codex-visible source
|
|
11
|
+
surfaces: .codex-plugin/plugin.json, AGENTS.md, README.md, commands/*.md, the
|
|
12
|
+
manifest-declared skill root, and the manifest-declared MCP config.
|
|
13
|
+
|
|
14
|
+
For Rally Point coordination work, ``--coordination-cache-parity``
|
|
15
|
+
compares the installed Claude and Codex plugin caches against each other for
|
|
16
|
+
coordination runtime surfaces. CI should fail if one host has a stale
|
|
17
|
+
coordination script while the other host has the new one.
|
|
18
|
+
|
|
19
|
+
Run from a plugin source repo (or with --source).
|
|
20
|
+
|
|
21
|
+
Exit codes:
|
|
22
|
+
0 — all referenced files in sync (or cache not installed — nothing to check)
|
|
23
|
+
1 — at least one referenced file diverges, or Codex has only stale versions installed
|
|
24
|
+
2 — usage / filesystem error
|
|
25
|
+
|
|
26
|
+
Zero deps, Python 3.11+.
|
|
27
|
+
"""
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import argparse
|
|
31
|
+
import hashlib
|
|
32
|
+
import json
|
|
33
|
+
import os
|
|
34
|
+
import re
|
|
35
|
+
import subprocess
|
|
36
|
+
import sys
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
REF_RE = re.compile(r"\$\{CLAUDE_PLUGIN_ROOT\}/([A-Za-z0-9_][A-Za-z0-9_./\-]*[A-Za-z0-9_])")
|
|
40
|
+
SEARCH_EXTS = {".md", ".json", ".py", ".sh", ".mjs", ".js", ".ts"}
|
|
41
|
+
IGNORE_DIRS = {".git", "node_modules", "__pycache__", ".venv", ".build-loop"}
|
|
42
|
+
CODEX_DEFAULT_MARKETPLACE = os.environ.get(
|
|
43
|
+
"BUILD_LOOP_CODEX_DEFAULT_MARKETPLACE",
|
|
44
|
+
"local-marketplace",
|
|
45
|
+
)
|
|
46
|
+
COORDINATION_EXACT_REFS = (
|
|
47
|
+
"commands/agent-rally-point.md",
|
|
48
|
+
"references/rally-point-protocol.md",
|
|
49
|
+
"references/coordination-rules.md",
|
|
50
|
+
"references/multi-session-coordination.md",
|
|
51
|
+
"scripts/check_cache_sync.py",
|
|
52
|
+
)
|
|
53
|
+
COORDINATION_PREFIXES = (
|
|
54
|
+
"scripts/rally_point",
|
|
55
|
+
)
|
|
56
|
+
COORDINATION_GLOBS = (
|
|
57
|
+
"scripts/coordination_*.py",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def sha256(path: Path) -> str:
|
|
62
|
+
h = hashlib.sha256()
|
|
63
|
+
with open(path, "rb") as f:
|
|
64
|
+
for chunk in iter(lambda: f.read(65536), b""):
|
|
65
|
+
h.update(chunk)
|
|
66
|
+
return h.hexdigest()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_manifest(source: Path, host: str) -> dict:
|
|
70
|
+
manifest_dir = ".codex-plugin" if host == "codex" else ".claude-plugin"
|
|
71
|
+
m = source / manifest_dir / "plugin.json"
|
|
72
|
+
if not m.exists():
|
|
73
|
+
print(f"error: no {manifest_dir}/plugin.json under {source}", file=sys.stderr)
|
|
74
|
+
sys.exit(2)
|
|
75
|
+
return json.loads(m.read_text())
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def default_marketplace(source: Path) -> str:
|
|
79
|
+
# Heuristic: walk up until we find a .claude-plugin/marketplace.json with this plugin listed
|
|
80
|
+
for parent in [source.parent, source.parent.parent, source.parent.parent.parent]:
|
|
81
|
+
mf = parent / ".claude-plugin" / "marketplace.json"
|
|
82
|
+
if mf.exists():
|
|
83
|
+
try:
|
|
84
|
+
data = json.loads(mf.read_text())
|
|
85
|
+
return data.get("name", "unknown-marketplace")
|
|
86
|
+
except json.JSONDecodeError:
|
|
87
|
+
pass
|
|
88
|
+
return "rosslabs-ai-toolkit"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def find_references(source: Path) -> set[str]:
|
|
92
|
+
refs: set[str] = set()
|
|
93
|
+
for root, dirs, files in os.walk(source):
|
|
94
|
+
dirs[:] = [d for d in dirs if d not in IGNORE_DIRS and not d.startswith(".")]
|
|
95
|
+
for name in files:
|
|
96
|
+
p = Path(root) / name
|
|
97
|
+
if p.suffix not in SEARCH_EXTS:
|
|
98
|
+
continue
|
|
99
|
+
try:
|
|
100
|
+
text = p.read_text(encoding="utf-8", errors="ignore")
|
|
101
|
+
except OSError:
|
|
102
|
+
continue
|
|
103
|
+
for m in REF_RE.finditer(text):
|
|
104
|
+
refs.add(m.group(1))
|
|
105
|
+
return refs
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _manifest_path_ref(value: object) -> str | None:
|
|
109
|
+
if not isinstance(value, str) or not value.strip():
|
|
110
|
+
return None
|
|
111
|
+
ref = value.strip()
|
|
112
|
+
if ref.startswith("./"):
|
|
113
|
+
return ref[2:]
|
|
114
|
+
return ref.lstrip("/")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def find_codex_surfaces(source: Path, manifest: dict | None = None) -> set[str]:
|
|
118
|
+
refs: set[str] = set()
|
|
119
|
+
for extra in (".codex-plugin/plugin.json", "AGENTS.md", "README.md"):
|
|
120
|
+
if (source / extra).exists():
|
|
121
|
+
refs.add(extra)
|
|
122
|
+
|
|
123
|
+
skill_root = _manifest_path_ref((manifest or {}).get("skills")) or "skills"
|
|
124
|
+
root_names = [skill_root, "commands"]
|
|
125
|
+
mcp_ref = _manifest_path_ref((manifest or {}).get("mcpServers"))
|
|
126
|
+
if mcp_ref:
|
|
127
|
+
refs.add(mcp_ref)
|
|
128
|
+
|
|
129
|
+
for root_name in root_names:
|
|
130
|
+
root_path = source / root_name
|
|
131
|
+
if not root_path.exists():
|
|
132
|
+
continue
|
|
133
|
+
for root, dirs, files in os.walk(root_path):
|
|
134
|
+
dirs[:] = [d for d in dirs if d not in IGNORE_DIRS and not d.startswith(".")]
|
|
135
|
+
for name in files:
|
|
136
|
+
p = Path(root) / name
|
|
137
|
+
if p.suffix in SEARCH_EXTS:
|
|
138
|
+
refs.add(str(p.relative_to(source)))
|
|
139
|
+
return refs
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def find_coordination_surfaces(source: Path) -> set[str]:
|
|
143
|
+
"""Return host-shared coordination surfaces that must stay cache-aligned."""
|
|
144
|
+
refs: set[str] = set()
|
|
145
|
+
for ref in COORDINATION_EXACT_REFS:
|
|
146
|
+
if (source / ref).is_file():
|
|
147
|
+
refs.add(ref)
|
|
148
|
+
|
|
149
|
+
for prefix in COORDINATION_PREFIXES:
|
|
150
|
+
root_path = source / prefix
|
|
151
|
+
if not root_path.exists():
|
|
152
|
+
continue
|
|
153
|
+
for root, dirs, files in os.walk(root_path):
|
|
154
|
+
dirs[:] = [
|
|
155
|
+
d for d in dirs
|
|
156
|
+
if d not in IGNORE_DIRS and not d.startswith(".")
|
|
157
|
+
]
|
|
158
|
+
for name in files:
|
|
159
|
+
p = Path(root) / name
|
|
160
|
+
if p.suffix in SEARCH_EXTS:
|
|
161
|
+
refs.add(str(p.relative_to(source)))
|
|
162
|
+
|
|
163
|
+
for pattern in COORDINATION_GLOBS:
|
|
164
|
+
refs.update(
|
|
165
|
+
str(p.relative_to(source))
|
|
166
|
+
for p in source.glob(pattern)
|
|
167
|
+
if p.is_file() and p.suffix in SEARCH_EXTS
|
|
168
|
+
)
|
|
169
|
+
return refs
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def find_installed_versions(cache_root: Path, name: str) -> list[Path]:
|
|
173
|
+
if not cache_root.exists():
|
|
174
|
+
return []
|
|
175
|
+
versions: list[Path] = []
|
|
176
|
+
for marketplace in cache_root.iterdir():
|
|
177
|
+
plugin_dir = marketplace / name
|
|
178
|
+
if not plugin_dir.is_dir():
|
|
179
|
+
continue
|
|
180
|
+
versions.extend([p for p in plugin_dir.iterdir() if p.is_dir()])
|
|
181
|
+
return sorted(versions, key=lambda p: p.name, reverse=True)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def default_cache(source: Path, host: str, name: str, version: str, marketplace: str | None) -> tuple[Path, list[Path]]:
|
|
185
|
+
if host == "claude":
|
|
186
|
+
chosen_marketplace = marketplace or default_marketplace(source)
|
|
187
|
+
return Path.home() / ".claude" / "plugins" / "cache" / chosen_marketplace / name / version, []
|
|
188
|
+
|
|
189
|
+
cache_root = Path.home() / ".codex" / "plugins" / "cache"
|
|
190
|
+
if marketplace:
|
|
191
|
+
plugin_root = cache_root / marketplace / name
|
|
192
|
+
stale = []
|
|
193
|
+
if plugin_root.is_dir():
|
|
194
|
+
stale = [p for p in plugin_root.iterdir() if p.is_dir() and p.name != version]
|
|
195
|
+
return plugin_root / version, sorted(stale, key=lambda p: p.name, reverse=True)
|
|
196
|
+
|
|
197
|
+
installed_versions = find_installed_versions(cache_root, name)
|
|
198
|
+
stale = [p for p in installed_versions if p.name != version]
|
|
199
|
+
exact_matches = [p for p in installed_versions if p.name == version]
|
|
200
|
+
if exact_matches:
|
|
201
|
+
return exact_matches[0], sorted(stale, key=lambda p: p.name, reverse=True)
|
|
202
|
+
|
|
203
|
+
return cache_root / CODEX_DEFAULT_MARKETPLACE / name / version, sorted(stale, key=lambda p: p.name, reverse=True)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def check_sync(source: Path, cache: Path, refs: set[str]) -> list[dict]:
|
|
207
|
+
"""Only flag problems where source has the file and cache doesn't match.
|
|
208
|
+
|
|
209
|
+
Docs often reference illustrative paths (e.g. ``scripts/my-script.sh``) that
|
|
210
|
+
don't exist in the real source tree — those are not sync problems, they're
|
|
211
|
+
just examples. We ignore them. Cache-only files (leftovers from older
|
|
212
|
+
versions) are also not actionable for the current sync check.
|
|
213
|
+
"""
|
|
214
|
+
diffs: list[dict] = []
|
|
215
|
+
for ref in sorted(refs):
|
|
216
|
+
src = source / ref
|
|
217
|
+
if not src.exists() or src.is_dir():
|
|
218
|
+
continue # example ref, non-file, or path that never existed in source
|
|
219
|
+
dst = cache / ref
|
|
220
|
+
if not dst.exists():
|
|
221
|
+
diffs.append({"path": ref, "status": "missing_in_cache", "src": str(src), "dst": str(dst)})
|
|
222
|
+
continue
|
|
223
|
+
if dst.is_dir():
|
|
224
|
+
continue
|
|
225
|
+
if sha256(src) != sha256(dst):
|
|
226
|
+
diffs.append({"path": ref, "status": "diverged", "src": str(src), "dst": str(dst)})
|
|
227
|
+
return diffs
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def check_cache_parity(
|
|
231
|
+
*,
|
|
232
|
+
source: Path,
|
|
233
|
+
claude_cache: Path,
|
|
234
|
+
codex_cache: Path,
|
|
235
|
+
refs: set[str],
|
|
236
|
+
) -> list[dict]:
|
|
237
|
+
"""Compare installed Claude and Codex caches for ``refs``.
|
|
238
|
+
|
|
239
|
+
The source repo defines the authoritative ref set. The comparison itself is
|
|
240
|
+
cache-to-cache so CI catches the specific failure where one installed host
|
|
241
|
+
has newer coordination code than the other.
|
|
242
|
+
"""
|
|
243
|
+
diffs: list[dict] = []
|
|
244
|
+
for ref in sorted(refs):
|
|
245
|
+
src = source / ref
|
|
246
|
+
if not src.exists() or src.is_dir():
|
|
247
|
+
continue
|
|
248
|
+
claude = claude_cache / ref
|
|
249
|
+
codex = codex_cache / ref
|
|
250
|
+
if not claude.exists():
|
|
251
|
+
diffs.append({
|
|
252
|
+
"path": ref,
|
|
253
|
+
"status": "missing_in_claude_cache",
|
|
254
|
+
"claude": str(claude),
|
|
255
|
+
"codex": str(codex),
|
|
256
|
+
})
|
|
257
|
+
continue
|
|
258
|
+
if not codex.exists():
|
|
259
|
+
diffs.append({
|
|
260
|
+
"path": ref,
|
|
261
|
+
"status": "missing_in_codex_cache",
|
|
262
|
+
"claude": str(claude),
|
|
263
|
+
"codex": str(codex),
|
|
264
|
+
})
|
|
265
|
+
continue
|
|
266
|
+
if claude.is_dir() or codex.is_dir():
|
|
267
|
+
continue
|
|
268
|
+
if sha256(claude) != sha256(codex):
|
|
269
|
+
diffs.append({
|
|
270
|
+
"path": ref,
|
|
271
|
+
"status": "host_cache_diverged",
|
|
272
|
+
"claude": str(claude),
|
|
273
|
+
"codex": str(codex),
|
|
274
|
+
})
|
|
275
|
+
return diffs
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def suggest_fix(source: Path, cache: Path) -> str:
|
|
279
|
+
return (
|
|
280
|
+
f" rsync -av --delete --exclude=.git --exclude=node_modules --exclude=__pycache__ "
|
|
281
|
+
f"{source}/ {cache}/"
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def parse_args() -> argparse.Namespace:
|
|
286
|
+
p = argparse.ArgumentParser(description="Check plugin source ↔ cache sync for plugin work.")
|
|
287
|
+
p.add_argument("--host", choices=["claude", "codex"], default="claude", help="Plugin host cache to inspect (default: claude)")
|
|
288
|
+
p.add_argument("--source", default=".", help="Plugin source repo root (default: cwd)")
|
|
289
|
+
p.add_argument("--cache", default=None, help="Plugin cache dir (default: resolve from plugin.json version + marketplace)")
|
|
290
|
+
p.add_argument("--marketplace", default=None, help="Marketplace name (default: autodetect from parent marketplace.json)")
|
|
291
|
+
p.add_argument("--json", action="store_true", help="Emit JSON report instead of human-readable")
|
|
292
|
+
p.add_argument("--fail-on-missing-cache", action="store_true", help="Treat a missing cache dir as exit 1 (default: exit 0)")
|
|
293
|
+
p.add_argument(
|
|
294
|
+
"--coordination-cache-parity",
|
|
295
|
+
action="store_true",
|
|
296
|
+
help="Compare installed Claude and Codex caches for coordination surfaces.",
|
|
297
|
+
)
|
|
298
|
+
p.add_argument(
|
|
299
|
+
"--claude-cache",
|
|
300
|
+
default=None,
|
|
301
|
+
help="Claude cache dir for --coordination-cache-parity.",
|
|
302
|
+
)
|
|
303
|
+
p.add_argument(
|
|
304
|
+
"--codex-cache",
|
|
305
|
+
default=None,
|
|
306
|
+
help="Codex cache dir for --coordination-cache-parity.",
|
|
307
|
+
)
|
|
308
|
+
return p.parse_args()
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def main() -> int:
|
|
312
|
+
args = parse_args()
|
|
313
|
+
source = Path(args.source).resolve()
|
|
314
|
+
if args.coordination_cache_parity:
|
|
315
|
+
claude_manifest = load_manifest(source, "claude")
|
|
316
|
+
codex_manifest = load_manifest(source, "codex")
|
|
317
|
+
name = claude_manifest.get("name")
|
|
318
|
+
version = claude_manifest.get("version")
|
|
319
|
+
if not name or not version:
|
|
320
|
+
print("error: .claude-plugin/plugin.json missing name or version", file=sys.stderr)
|
|
321
|
+
return 2
|
|
322
|
+
if codex_manifest.get("name") != name or codex_manifest.get("version") != version:
|
|
323
|
+
print("error: Claude and Codex manifests disagree on name/version", file=sys.stderr)
|
|
324
|
+
return 2
|
|
325
|
+
|
|
326
|
+
if args.claude_cache:
|
|
327
|
+
claude_cache = Path(args.claude_cache).resolve()
|
|
328
|
+
else:
|
|
329
|
+
claude_cache, _ = default_cache(source, "claude", name, version, args.marketplace)
|
|
330
|
+
if args.codex_cache:
|
|
331
|
+
codex_cache = Path(args.codex_cache).resolve()
|
|
332
|
+
stale_versions: list[Path] = []
|
|
333
|
+
else:
|
|
334
|
+
codex_cache, stale_versions = default_cache(source, "codex", name, version, args.marketplace)
|
|
335
|
+
|
|
336
|
+
missing: list[dict] = []
|
|
337
|
+
if not claude_cache.exists():
|
|
338
|
+
missing.append({"host": "claude", "cache": str(claude_cache)})
|
|
339
|
+
if not codex_cache.exists():
|
|
340
|
+
missing.append({"host": "codex", "cache": str(codex_cache)})
|
|
341
|
+
if missing:
|
|
342
|
+
if args.json:
|
|
343
|
+
print(json.dumps({
|
|
344
|
+
"mode": "coordination-cache-parity",
|
|
345
|
+
"plugin": name,
|
|
346
|
+
"version": version,
|
|
347
|
+
"source": str(source),
|
|
348
|
+
"claude_cache": str(claude_cache),
|
|
349
|
+
"codex_cache": str(codex_cache),
|
|
350
|
+
"missing_caches": missing,
|
|
351
|
+
"stale_codex_versions": [str(p) for p in stale_versions],
|
|
352
|
+
"diffs": [],
|
|
353
|
+
}, indent=2))
|
|
354
|
+
else:
|
|
355
|
+
for item in missing:
|
|
356
|
+
print(
|
|
357
|
+
f"cache for {item['host']} {name}@{version} not installed "
|
|
358
|
+
f"at {item['cache']}",
|
|
359
|
+
file=sys.stderr,
|
|
360
|
+
)
|
|
361
|
+
if stale_versions:
|
|
362
|
+
print("found other installed Codex version(s):", file=sys.stderr)
|
|
363
|
+
for stale in stale_versions:
|
|
364
|
+
print(f" {stale}", file=sys.stderr)
|
|
365
|
+
return 1
|
|
366
|
+
|
|
367
|
+
refs = find_coordination_surfaces(source)
|
|
368
|
+
diffs = check_cache_parity(
|
|
369
|
+
source=source,
|
|
370
|
+
claude_cache=claude_cache,
|
|
371
|
+
codex_cache=codex_cache,
|
|
372
|
+
refs=refs,
|
|
373
|
+
)
|
|
374
|
+
if args.json:
|
|
375
|
+
print(json.dumps({
|
|
376
|
+
"mode": "coordination-cache-parity",
|
|
377
|
+
"plugin": name,
|
|
378
|
+
"version": version,
|
|
379
|
+
"source": str(source),
|
|
380
|
+
"claude_cache": str(claude_cache),
|
|
381
|
+
"codex_cache": str(codex_cache),
|
|
382
|
+
"refs_checked": sorted(refs),
|
|
383
|
+
"diffs": diffs,
|
|
384
|
+
}, indent=2))
|
|
385
|
+
return 1 if diffs else 0
|
|
386
|
+
else:
|
|
387
|
+
if not diffs:
|
|
388
|
+
print(
|
|
389
|
+
f"✅ coordination cache parity: {name}@{version} "
|
|
390
|
+
f"all {len(refs)} coordination surfaces match"
|
|
391
|
+
)
|
|
392
|
+
print(f" claude: {claude_cache}")
|
|
393
|
+
print(f" codex: {codex_cache}")
|
|
394
|
+
else:
|
|
395
|
+
print(
|
|
396
|
+
f"❌ coordination cache parity: {name}@{version} "
|
|
397
|
+
f"{len(diffs)} file(s) diverged between host caches"
|
|
398
|
+
)
|
|
399
|
+
print(f" claude: {claude_cache}")
|
|
400
|
+
print(f" codex: {codex_cache}")
|
|
401
|
+
print()
|
|
402
|
+
for d in diffs:
|
|
403
|
+
status = d["status"]
|
|
404
|
+
path = d["path"]
|
|
405
|
+
if status == "missing_in_claude_cache":
|
|
406
|
+
print(f" [MISSING IN CLAUDE CACHE] {path}")
|
|
407
|
+
elif status == "missing_in_codex_cache":
|
|
408
|
+
print(f" [MISSING IN CODEX CACHE] {path}")
|
|
409
|
+
elif status == "host_cache_diverged":
|
|
410
|
+
print(f" [HOST CACHE DIVERGED] {path}")
|
|
411
|
+
return 1 if diffs else 0
|
|
412
|
+
|
|
413
|
+
manifest = load_manifest(source, args.host)
|
|
414
|
+
name = manifest.get("name")
|
|
415
|
+
version = manifest.get("version")
|
|
416
|
+
if not name or not version:
|
|
417
|
+
print("error: plugin.json missing name or version", file=sys.stderr)
|
|
418
|
+
return 2
|
|
419
|
+
|
|
420
|
+
if args.cache:
|
|
421
|
+
cache = Path(args.cache).resolve()
|
|
422
|
+
stale_versions: list[Path] = []
|
|
423
|
+
else:
|
|
424
|
+
cache, stale_versions = default_cache(source, args.host, name, version, args.marketplace)
|
|
425
|
+
|
|
426
|
+
if not cache.exists():
|
|
427
|
+
if args.host == "codex" and stale_versions:
|
|
428
|
+
print(f"cache for {name}@{version} not installed at {cache}", file=sys.stderr)
|
|
429
|
+
print("found other installed Codex version(s):", file=sys.stderr)
|
|
430
|
+
for stale in stale_versions:
|
|
431
|
+
print(f" {stale}", file=sys.stderr)
|
|
432
|
+
return 1
|
|
433
|
+
msg = f"cache not installed at {cache} — skipping (use --fail-on-missing-cache to enforce)"
|
|
434
|
+
print(msg, file=sys.stderr)
|
|
435
|
+
return 1 if args.fail_on_missing_cache else 0
|
|
436
|
+
|
|
437
|
+
if args.host == "codex":
|
|
438
|
+
refs = find_codex_surfaces(source, manifest)
|
|
439
|
+
else:
|
|
440
|
+
refs = find_references(source)
|
|
441
|
+
# Always also check the manifest + hooks even if not referenced via ${CLAUDE_PLUGIN_ROOT}
|
|
442
|
+
for extra in (".claude-plugin/plugin.json", "hooks/hooks.json"):
|
|
443
|
+
if (source / extra).exists():
|
|
444
|
+
refs.add(extra)
|
|
445
|
+
|
|
446
|
+
diffs = check_sync(source, cache, refs)
|
|
447
|
+
|
|
448
|
+
if args.json:
|
|
449
|
+
print(json.dumps({
|
|
450
|
+
"host": args.host,
|
|
451
|
+
"plugin": name,
|
|
452
|
+
"version": version,
|
|
453
|
+
"source": str(source),
|
|
454
|
+
"cache": str(cache),
|
|
455
|
+
"stale_codex_versions": [str(p) for p in stale_versions] if args.host == "codex" else [],
|
|
456
|
+
"diffs": diffs,
|
|
457
|
+
}, indent=2))
|
|
458
|
+
else:
|
|
459
|
+
if not diffs:
|
|
460
|
+
print(f"✅ {args.host} {name}@{version}: all {len(refs)} referenced files in sync")
|
|
461
|
+
print(f" source: {source}")
|
|
462
|
+
print(f" cache: {cache}")
|
|
463
|
+
else:
|
|
464
|
+
print(f"❌ {args.host} {name}@{version}: {len(diffs)} file(s) out of sync between source and cache")
|
|
465
|
+
print(f" source: {source}")
|
|
466
|
+
print(f" cache: {cache}")
|
|
467
|
+
print()
|
|
468
|
+
for d in diffs:
|
|
469
|
+
status = d["status"]
|
|
470
|
+
path = d["path"]
|
|
471
|
+
if status == "missing_in_cache":
|
|
472
|
+
print(f" [MISSING IN CACHE] {path}")
|
|
473
|
+
elif status == "diverged":
|
|
474
|
+
print(f" [DIVERGED] {path}")
|
|
475
|
+
print()
|
|
476
|
+
print("to resync:")
|
|
477
|
+
print(suggest_fix(source, cache))
|
|
478
|
+
if args.host == "codex" and stale_versions:
|
|
479
|
+
print()
|
|
480
|
+
print("stale Codex cache version(s) still installed:")
|
|
481
|
+
for stale in stale_versions:
|
|
482
|
+
print(f" {stale}")
|
|
483
|
+
print("to prune:")
|
|
484
|
+
print(" python3 scripts/prune_codex_plugin_cache.py --source . --apply")
|
|
485
|
+
|
|
486
|
+
return 1 if diffs else 0
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
if __name__ == "__main__":
|
|
490
|
+
sys.exit(main())
|