@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,495 @@
|
|
|
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
|
+
"""
|
|
5
|
+
Build-loop native AX driver — Python launcher.
|
|
6
|
+
|
|
7
|
+
Wraps the vendored Swift extractor (`swift/bl-ax-driver/`). Compiles on first
|
|
8
|
+
use, caches the binary at `.build-loop/bin/bl-ax-driver`, rebuilds when the
|
|
9
|
+
Swift source is newer than the binary.
|
|
10
|
+
|
|
11
|
+
All actions go through macOS Accessibility APIs. The driver does NOT inject
|
|
12
|
+
synthetic mouse or keyboard events — the user's hardware cursor is never moved.
|
|
13
|
+
|
|
14
|
+
Usage (from a build-loop run, project cwd):
|
|
15
|
+
|
|
16
|
+
# Resolve a running app to its pid (no AX permission needed for this)
|
|
17
|
+
python3 native_driver.py resolve --app "Secrets Vault"
|
|
18
|
+
|
|
19
|
+
# Scan AX tree of running app
|
|
20
|
+
python3 native_driver.py scan --app "Secrets Vault" --json
|
|
21
|
+
python3 native_driver.py scan --pid 12345 --json
|
|
22
|
+
|
|
23
|
+
# Perform an AX action on a specific element
|
|
24
|
+
python3 native_driver.py action --pid 12345 \\
|
|
25
|
+
--element-path 0,2,1 --action press
|
|
26
|
+
|
|
27
|
+
# Set a text-field value
|
|
28
|
+
python3 native_driver.py action --pid 12345 \\
|
|
29
|
+
--element-path 0,4,0 --action setValue --value "secret"
|
|
30
|
+
|
|
31
|
+
# Pre-flight permission check (returns 0 if AX granted, 2 if not)
|
|
32
|
+
python3 native_driver.py preflight
|
|
33
|
+
|
|
34
|
+
# List running regular GUI apps (no AX permission needed)
|
|
35
|
+
python3 native_driver.py apps
|
|
36
|
+
|
|
37
|
+
# Analyze a captured AX tree for centered-narrow layout gaps
|
|
38
|
+
python3 native_driver.py analyze-layout --stdin < ax-tree.json
|
|
39
|
+
|
|
40
|
+
The launcher is intentionally stdlib-only (no pip deps). Calling code can shell
|
|
41
|
+
out from any orchestrator phase or skill.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
from __future__ import annotations
|
|
45
|
+
|
|
46
|
+
import argparse
|
|
47
|
+
import json
|
|
48
|
+
import os
|
|
49
|
+
import shutil
|
|
50
|
+
import subprocess
|
|
51
|
+
import sys
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
|
|
54
|
+
# ─── Paths ────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
# This file lives at:
|
|
57
|
+
# <plugin-root>/skills/native-ax-driver/scripts/native_driver.py
|
|
58
|
+
# Swift source:
|
|
59
|
+
# <plugin-root>/skills/native-ax-driver/swift/bl-ax-driver/
|
|
60
|
+
# Cached binary (in the *consumer* project, NOT the plugin):
|
|
61
|
+
# <consumer-cwd>/.build-loop/bin/bl-ax-driver
|
|
62
|
+
|
|
63
|
+
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
64
|
+
sys.path.insert(0, str(SCRIPT_DIR))
|
|
65
|
+
|
|
66
|
+
from layout_fill import analyze_layout_fill
|
|
67
|
+
|
|
68
|
+
SKILL_DIR = SCRIPT_DIR.parent # skills/native-ax-driver
|
|
69
|
+
SWIFT_SOURCE_DIR = SKILL_DIR / "swift" / "bl-ax-driver"
|
|
70
|
+
SWIFT_MAIN = SWIFT_SOURCE_DIR / "Sources" / "main.swift"
|
|
71
|
+
SWIFT_PACKAGE = SWIFT_SOURCE_DIR / "Package.swift"
|
|
72
|
+
SWIFT_BUILT_BINARY = SWIFT_SOURCE_DIR / ".build" / "release" / "bl-ax-driver"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def consumer_bin_dir() -> Path:
|
|
76
|
+
"""Directory the compiled binary is cached in, in the consumer project."""
|
|
77
|
+
cwd_bl = Path.cwd() / ".build-loop" / "bin"
|
|
78
|
+
return cwd_bl
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def cached_binary_path() -> Path:
|
|
82
|
+
return consumer_bin_dir() / "bl-ax-driver"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ─── Build the Swift extractor ────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _is_fresh(binary: Path) -> bool:
|
|
89
|
+
"""Binary is fresh iff it's newer than both Swift sources."""
|
|
90
|
+
if not binary.exists():
|
|
91
|
+
return False
|
|
92
|
+
try:
|
|
93
|
+
bin_mtime = binary.stat().st_mtime
|
|
94
|
+
src_mtime = max(SWIFT_MAIN.stat().st_mtime, SWIFT_PACKAGE.stat().st_mtime)
|
|
95
|
+
return bin_mtime >= src_mtime
|
|
96
|
+
except FileNotFoundError:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _build_swift() -> None:
|
|
101
|
+
if not SWIFT_PACKAGE.exists() or not SWIFT_MAIN.exists():
|
|
102
|
+
raise RuntimeError(
|
|
103
|
+
f"Swift sources missing under {SWIFT_SOURCE_DIR}. "
|
|
104
|
+
"The native-ax-driver skill is not vendored correctly."
|
|
105
|
+
)
|
|
106
|
+
if shutil.which("swift") is None:
|
|
107
|
+
raise RuntimeError(
|
|
108
|
+
"`swift` not found on PATH. Install Xcode Command Line Tools: "
|
|
109
|
+
"`xcode-select --install`"
|
|
110
|
+
)
|
|
111
|
+
try:
|
|
112
|
+
subprocess.run(
|
|
113
|
+
["swift", "build", "-c", "release"],
|
|
114
|
+
cwd=SWIFT_SOURCE_DIR,
|
|
115
|
+
check=True,
|
|
116
|
+
timeout=120,
|
|
117
|
+
)
|
|
118
|
+
except subprocess.CalledProcessError:
|
|
119
|
+
# Some sandboxed shells need --disable-sandbox
|
|
120
|
+
subprocess.run(
|
|
121
|
+
["swift", "build", "-c", "release", "--disable-sandbox"],
|
|
122
|
+
cwd=SWIFT_SOURCE_DIR,
|
|
123
|
+
check=True,
|
|
124
|
+
timeout=120,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def ensure_binary() -> Path:
|
|
129
|
+
"""Compile-on-first-use, cache in consumer's .build-loop/bin/. Idempotent."""
|
|
130
|
+
cached = cached_binary_path()
|
|
131
|
+
if _is_fresh(cached):
|
|
132
|
+
return cached
|
|
133
|
+
|
|
134
|
+
if not _is_fresh(SWIFT_BUILT_BINARY):
|
|
135
|
+
_build_swift()
|
|
136
|
+
|
|
137
|
+
if not SWIFT_BUILT_BINARY.exists():
|
|
138
|
+
raise RuntimeError(
|
|
139
|
+
f"Swift build reported success but binary missing at {SWIFT_BUILT_BINARY}"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
consumer_bin_dir().mkdir(parents=True, exist_ok=True)
|
|
143
|
+
shutil.copy2(SWIFT_BUILT_BINARY, cached)
|
|
144
|
+
cached.chmod(0o755)
|
|
145
|
+
return cached
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ─── Subcommand implementations ───────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def cmd_preflight(_args: argparse.Namespace) -> int:
|
|
152
|
+
"""Quickest possible AX-permission probe."""
|
|
153
|
+
if shutil.which("osascript") is None:
|
|
154
|
+
print(json.dumps({"granted": False, "error": "osascript not found"}))
|
|
155
|
+
return 2
|
|
156
|
+
try:
|
|
157
|
+
# The least-surprising AX op: read frontmost process name.
|
|
158
|
+
result = subprocess.run(
|
|
159
|
+
[
|
|
160
|
+
"osascript",
|
|
161
|
+
"-e",
|
|
162
|
+
'tell application "System Events" to get the name of '
|
|
163
|
+
"(first process whose frontmost is true)",
|
|
164
|
+
],
|
|
165
|
+
capture_output=True,
|
|
166
|
+
text=True,
|
|
167
|
+
timeout=5,
|
|
168
|
+
)
|
|
169
|
+
granted = result.returncode == 0 and bool(result.stdout.strip())
|
|
170
|
+
payload = {"granted": granted}
|
|
171
|
+
if not granted:
|
|
172
|
+
payload["error"] = (
|
|
173
|
+
result.stderr.strip()
|
|
174
|
+
or "Grant Accessibility permission in System Settings > Privacy & Security."
|
|
175
|
+
)
|
|
176
|
+
print(json.dumps(payload))
|
|
177
|
+
return 0 if granted else 2
|
|
178
|
+
except subprocess.TimeoutExpired:
|
|
179
|
+
print(json.dumps({"granted": False, "error": "AX preflight timed out"}))
|
|
180
|
+
return 2
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def cmd_apps(_args: argparse.Namespace) -> int:
|
|
184
|
+
"""List regular GUI apps with their pid and bundle identifier (no AX needed)."""
|
|
185
|
+
script = (
|
|
186
|
+
'tell application "System Events" to '
|
|
187
|
+
'get {name, unix id, bundle identifier} of every process '
|
|
188
|
+
"whose background only is false"
|
|
189
|
+
)
|
|
190
|
+
try:
|
|
191
|
+
result = subprocess.run(
|
|
192
|
+
["osascript", "-e", script],
|
|
193
|
+
capture_output=True,
|
|
194
|
+
text=True,
|
|
195
|
+
timeout=10,
|
|
196
|
+
check=True,
|
|
197
|
+
)
|
|
198
|
+
except FileNotFoundError:
|
|
199
|
+
print(json.dumps({"error": "osascript missing"}), file=sys.stderr)
|
|
200
|
+
return 1
|
|
201
|
+
except subprocess.CalledProcessError as e:
|
|
202
|
+
print(json.dumps({"error": e.stderr.strip() or "osascript failed"}), file=sys.stderr)
|
|
203
|
+
return 1
|
|
204
|
+
|
|
205
|
+
raw = result.stdout.strip()
|
|
206
|
+
# AppleScript returns a flat list: name1, name2, ..., pid1, pid2, ..., bundle1, ...
|
|
207
|
+
parts = [p.strip() for p in raw.split(",")]
|
|
208
|
+
n = len(parts) // 3 if len(parts) % 3 == 0 else 0
|
|
209
|
+
apps = []
|
|
210
|
+
for i in range(n):
|
|
211
|
+
apps.append(
|
|
212
|
+
{
|
|
213
|
+
"name": parts[i],
|
|
214
|
+
"pid": int(parts[n + i]) if parts[n + i].isdigit() else None,
|
|
215
|
+
"bundleIdentifier": parts[2 * n + i] if parts[2 * n + i] != "missing value" else None,
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
print(json.dumps(apps, indent=2))
|
|
219
|
+
return 0
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def cmd_resolve(args: argparse.Namespace) -> int:
|
|
223
|
+
binary = ensure_binary()
|
|
224
|
+
proc = subprocess.run(
|
|
225
|
+
[str(binary), "--resolve-app", args.app],
|
|
226
|
+
capture_output=True,
|
|
227
|
+
text=True,
|
|
228
|
+
timeout=10,
|
|
229
|
+
)
|
|
230
|
+
if proc.returncode != 0:
|
|
231
|
+
sys.stderr.write(proc.stderr)
|
|
232
|
+
return proc.returncode
|
|
233
|
+
sys.stdout.write(proc.stdout)
|
|
234
|
+
return 0
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def cmd_scan(args: argparse.Namespace) -> int:
|
|
238
|
+
binary = ensure_binary()
|
|
239
|
+
cmd: list[str] = [str(binary)]
|
|
240
|
+
if args.pid is not None:
|
|
241
|
+
cmd += ["--pid", str(args.pid)]
|
|
242
|
+
elif args.app:
|
|
243
|
+
cmd += ["--app", args.app]
|
|
244
|
+
elif args.device_name:
|
|
245
|
+
cmd += ["--device-name", args.device_name]
|
|
246
|
+
else:
|
|
247
|
+
print(
|
|
248
|
+
json.dumps({"error": "scan requires --pid, --app, or --device-name"}),
|
|
249
|
+
file=sys.stderr,
|
|
250
|
+
)
|
|
251
|
+
return 2
|
|
252
|
+
|
|
253
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
254
|
+
sys.stdout.write(proc.stdout)
|
|
255
|
+
sys.stderr.write(proc.stderr)
|
|
256
|
+
return proc.returncode
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _strip_window_header(text: str) -> str:
|
|
260
|
+
lines = text.splitlines()
|
|
261
|
+
if lines and lines[0].startswith("WINDOW:"):
|
|
262
|
+
return "\n".join(lines[1:]).strip()
|
|
263
|
+
return text.strip()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _load_ax_roots(text: str) -> list[dict] | dict:
|
|
267
|
+
return json.loads(_strip_window_header(text))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _scan_for_layout(args: argparse.Namespace) -> tuple[str | None, str | None]:
|
|
271
|
+
binary = ensure_binary()
|
|
272
|
+
cmd: list[str] = [str(binary)]
|
|
273
|
+
if args.pid is not None:
|
|
274
|
+
cmd += ["--pid", str(args.pid)]
|
|
275
|
+
elif args.app:
|
|
276
|
+
cmd += ["--app", args.app]
|
|
277
|
+
else:
|
|
278
|
+
return None, "analyze-layout requires --from-file, --stdin, --pid, or --app"
|
|
279
|
+
|
|
280
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
281
|
+
if proc.returncode != 0:
|
|
282
|
+
return None, proc.stderr.strip() or f"scan failed with exit {proc.returncode}"
|
|
283
|
+
return proc.stdout, None
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _emit_layout_envelope(
|
|
287
|
+
*,
|
|
288
|
+
status: str,
|
|
289
|
+
artifacts: list[str],
|
|
290
|
+
verification: str,
|
|
291
|
+
findings: list[dict],
|
|
292
|
+
error: str | None = None,
|
|
293
|
+
) -> None:
|
|
294
|
+
payload = {
|
|
295
|
+
"status": status,
|
|
296
|
+
"route": "native",
|
|
297
|
+
"verifier": "native-ax-driver",
|
|
298
|
+
"artifacts": artifacts,
|
|
299
|
+
"verification": verification,
|
|
300
|
+
"findings": findings,
|
|
301
|
+
}
|
|
302
|
+
if error:
|
|
303
|
+
payload["error"] = error
|
|
304
|
+
print(json.dumps(payload, indent=2))
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def cmd_analyze_layout(args: argparse.Namespace) -> int:
|
|
308
|
+
artifacts: list[str]
|
|
309
|
+
try:
|
|
310
|
+
if args.from_file:
|
|
311
|
+
artifacts = [str(args.from_file)]
|
|
312
|
+
source = Path(args.from_file).read_text()
|
|
313
|
+
elif args.stdin:
|
|
314
|
+
artifacts = ["stdin"]
|
|
315
|
+
source = sys.stdin.read()
|
|
316
|
+
else:
|
|
317
|
+
artifacts = [f"pid:{args.pid}" if args.pid is not None else f"app:{args.app}"]
|
|
318
|
+
source, error = _scan_for_layout(args)
|
|
319
|
+
if error:
|
|
320
|
+
_emit_layout_envelope(
|
|
321
|
+
status="failed",
|
|
322
|
+
artifacts=artifacts,
|
|
323
|
+
verification=f"native-ax-driver analyze-layout failed: {error}",
|
|
324
|
+
findings=[],
|
|
325
|
+
error=error,
|
|
326
|
+
)
|
|
327
|
+
return 0
|
|
328
|
+
|
|
329
|
+
roots = _load_ax_roots(source)
|
|
330
|
+
raw_findings = analyze_layout_fill(
|
|
331
|
+
roots,
|
|
332
|
+
threshold=args.threshold,
|
|
333
|
+
min_container_px=args.min_container_px,
|
|
334
|
+
)
|
|
335
|
+
findings = [
|
|
336
|
+
{
|
|
337
|
+
"severity": "warning",
|
|
338
|
+
"category": "structure",
|
|
339
|
+
"message": f"layout-fill: {finding.get('detail', '')}",
|
|
340
|
+
"finding": finding,
|
|
341
|
+
}
|
|
342
|
+
for finding in raw_findings
|
|
343
|
+
]
|
|
344
|
+
count = len(findings)
|
|
345
|
+
plural = "" if count == 1 else "s"
|
|
346
|
+
_emit_layout_envelope(
|
|
347
|
+
status="ran",
|
|
348
|
+
artifacts=artifacts,
|
|
349
|
+
verification=(
|
|
350
|
+
f"native-ax-driver analyze-layout ran; found {count} "
|
|
351
|
+
f"layout-fill finding{plural}."
|
|
352
|
+
),
|
|
353
|
+
findings=findings,
|
|
354
|
+
)
|
|
355
|
+
return 0
|
|
356
|
+
except Exception as exc: # Keep analyzer failures data-shaped for bridge callers.
|
|
357
|
+
error = str(exc)
|
|
358
|
+
_emit_layout_envelope(
|
|
359
|
+
status="failed",
|
|
360
|
+
artifacts=artifacts if "artifacts" in locals() else [],
|
|
361
|
+
verification=f"native-ax-driver analyze-layout failed: {error}",
|
|
362
|
+
findings=[],
|
|
363
|
+
error=error,
|
|
364
|
+
)
|
|
365
|
+
return 0
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
VALID_ACTIONS = {
|
|
369
|
+
"press",
|
|
370
|
+
"setValue",
|
|
371
|
+
"increment",
|
|
372
|
+
"decrement",
|
|
373
|
+
"showMenu",
|
|
374
|
+
"confirm",
|
|
375
|
+
"cancel",
|
|
376
|
+
"focus",
|
|
377
|
+
"scrollToVisible",
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def cmd_action(args: argparse.Namespace) -> int:
|
|
382
|
+
if args.action not in VALID_ACTIONS:
|
|
383
|
+
print(
|
|
384
|
+
json.dumps(
|
|
385
|
+
{
|
|
386
|
+
"success": False,
|
|
387
|
+
"error": f"invalid --action {args.action!r}; one of: {sorted(VALID_ACTIONS)}",
|
|
388
|
+
}
|
|
389
|
+
),
|
|
390
|
+
file=sys.stderr,
|
|
391
|
+
)
|
|
392
|
+
return 2
|
|
393
|
+
if args.pid is None:
|
|
394
|
+
print(
|
|
395
|
+
json.dumps({"success": False, "error": "--pid required"}),
|
|
396
|
+
file=sys.stderr,
|
|
397
|
+
)
|
|
398
|
+
return 2
|
|
399
|
+
if not args.element_path:
|
|
400
|
+
print(
|
|
401
|
+
json.dumps({"success": False, "error": "--element-path required (e.g. '0,2,1')"}),
|
|
402
|
+
file=sys.stderr,
|
|
403
|
+
)
|
|
404
|
+
return 2
|
|
405
|
+
|
|
406
|
+
binary = ensure_binary()
|
|
407
|
+
cmd = [
|
|
408
|
+
str(binary),
|
|
409
|
+
"--pid",
|
|
410
|
+
str(args.pid),
|
|
411
|
+
"--action",
|
|
412
|
+
args.action,
|
|
413
|
+
"--element-path",
|
|
414
|
+
args.element_path,
|
|
415
|
+
]
|
|
416
|
+
if args.value is not None:
|
|
417
|
+
cmd += ["--value", args.value]
|
|
418
|
+
if args.device_name:
|
|
419
|
+
cmd += ["--device-name", args.device_name]
|
|
420
|
+
|
|
421
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
|
|
422
|
+
sys.stdout.write(proc.stdout)
|
|
423
|
+
sys.stderr.write(proc.stderr)
|
|
424
|
+
return proc.returncode
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
# ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
431
|
+
p = argparse.ArgumentParser(
|
|
432
|
+
prog="native_driver.py",
|
|
433
|
+
description="Build-loop native macOS AX driver (cursor-free).",
|
|
434
|
+
)
|
|
435
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
436
|
+
|
|
437
|
+
sub.add_parser("preflight", help="Check AX permission")
|
|
438
|
+
sub.add_parser("apps", help="List running regular GUI apps")
|
|
439
|
+
|
|
440
|
+
p_resolve = sub.add_parser("resolve", help="Resolve an app name to its pid")
|
|
441
|
+
p_resolve.add_argument("--app", required=True)
|
|
442
|
+
|
|
443
|
+
p_scan = sub.add_parser("scan", help="Scan AX tree of running app")
|
|
444
|
+
p_scan.add_argument("--pid", type=int)
|
|
445
|
+
p_scan.add_argument("--app")
|
|
446
|
+
p_scan.add_argument("--device-name", help="Pin to a specific iOS sim device window")
|
|
447
|
+
|
|
448
|
+
p_analyze = sub.add_parser(
|
|
449
|
+
"analyze-layout",
|
|
450
|
+
help="Analyze AX tree for centered-narrow layout-fill gaps",
|
|
451
|
+
)
|
|
452
|
+
source = p_analyze.add_mutually_exclusive_group(required=True)
|
|
453
|
+
source.add_argument("--from-file", type=Path, help="Read Swift scan JSON from a file")
|
|
454
|
+
source.add_argument("--stdin", action="store_true", help="Read Swift scan JSON from stdin")
|
|
455
|
+
source.add_argument("--pid", type=int, help="Scan this pid and analyze the result")
|
|
456
|
+
source.add_argument("--app", help="Scan this app name and analyze the result")
|
|
457
|
+
p_analyze.add_argument("--threshold", type=float, default=0.12)
|
|
458
|
+
p_analyze.add_argument("--min-container-px", type=float, default=50.0)
|
|
459
|
+
|
|
460
|
+
p_action = sub.add_parser("action", help="Perform AX action on element by index path")
|
|
461
|
+
p_action.add_argument("--pid", type=int, required=True)
|
|
462
|
+
p_action.add_argument(
|
|
463
|
+
"--element-path",
|
|
464
|
+
required=True,
|
|
465
|
+
help="Comma-separated indices, e.g. '0,2,1' from window root",
|
|
466
|
+
)
|
|
467
|
+
p_action.add_argument("--action", required=True, choices=sorted(VALID_ACTIONS))
|
|
468
|
+
p_action.add_argument("--value", help="Required for setValue")
|
|
469
|
+
p_action.add_argument("--device-name", help="iOS sim variant")
|
|
470
|
+
|
|
471
|
+
return p
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def main(argv: list[str] | None = None) -> int:
|
|
475
|
+
parser = build_parser()
|
|
476
|
+
args = parser.parse_args(argv)
|
|
477
|
+
|
|
478
|
+
handlers = {
|
|
479
|
+
"preflight": cmd_preflight,
|
|
480
|
+
"apps": cmd_apps,
|
|
481
|
+
"resolve": cmd_resolve,
|
|
482
|
+
"scan": cmd_scan,
|
|
483
|
+
"analyze-layout": cmd_analyze_layout,
|
|
484
|
+
"action": cmd_action,
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
try:
|
|
488
|
+
return handlers[args.cmd](args)
|
|
489
|
+
except RuntimeError as e:
|
|
490
|
+
print(json.dumps({"error": str(e)}), file=sys.stderr)
|
|
491
|
+
return 1
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
if __name__ == "__main__":
|
|
495
|
+
sys.exit(main())
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
// SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
//
|
|
5
|
+
// Build-loop native AX driver — drives running macOS apps through the
|
|
6
|
+
// Accessibility API. Vendored from the same source IBR uses; both projects
|
|
7
|
+
// can keep their own copy without depending on each other.
|
|
8
|
+
|
|
9
|
+
import PackageDescription
|
|
10
|
+
|
|
11
|
+
let package = Package(
|
|
12
|
+
name: "bl-ax-driver",
|
|
13
|
+
platforms: [.macOS(.v13)],
|
|
14
|
+
targets: [
|
|
15
|
+
.executableTarget(
|
|
16
|
+
name: "bl-ax-driver",
|
|
17
|
+
path: "Sources"
|
|
18
|
+
),
|
|
19
|
+
]
|
|
20
|
+
)
|