arckit-cli 6.1.1__py3-none-any.whl
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.
- arckit_cli/__init__.py +1120 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/memory/sessions.md +293 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/_partials/RENDERING.md +22 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/_partials/document-control-uae.md +20 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/_partials/document-control-uk.md +16 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/adm-preliminary-template.md +135 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/adr-template.md +588 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-design-template.md +390 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-governance-template.md +90 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-integration-template.md +159 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-inventory-template.md +108 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-maturity-template.md +388 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/agent-security-template.md +213 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/analysis-report-template.md +323 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/application-inventory-template.md +221 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-board-template.md +194 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-change-template.md +205 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-diagram-template.md +610 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-principles-template.md +632 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-repository-template.md +107 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/architecture-strategy-template.md +666 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/at-bvergg-template.md +252 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/at-dsgvo-template.md +354 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/at-nisg-template.md +236 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-aescsf-template.md +189 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-ai-assurance-template.md +243 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-disp-attestation-template.md +297 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-dss-template.md +302 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-e8-posture-template.md +377 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-energy-compliance-template.md +189 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-ism-controls-template.md +462 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-ndb-playbook-template.md +288 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-ot-security-template.md +204 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-pia-template.md +394 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-pspf-template.md +380 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/au-soci-cirmp-template.md +206 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/aws-research-template.md +605 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/azure-research-template.md +559 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/backlog-template.md +465 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-aia-template.md +206 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-atip-template.md +192 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-charter-template.md +190 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-cloud-residency-template.md +173 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-fitaa-template.md +156 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-gc-digital-standards-template.md +208 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-itsg-33-template.md +228 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-ocap-template.md +205 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-ola-template.md +171 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-pia-template.md +193 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-pspc-template.md +214 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ca-soia-template.md +219 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/capability-map-template.md +125 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/competitors-template.md +113 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/conformance-assessment-template.md +507 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/data-mesh-contract-template.md +851 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/data-model-template.md +1043 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/data-source-profile-template.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/datascout-template.md +546 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/devops-template.md +961 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/dfd-template.md +161 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/dld-review-template.md +427 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/dos-requirements-template.md +506 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/dpia-template.md +1200 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-ai-act-template.md +227 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-cra-template.md +176 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-data-act-template.md +175 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-dora-template.md +197 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-dsa-template.md +183 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-nis2-template.md +196 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/eu-rgpd-template.md +198 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/evaluation-criteria-template.md +719 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/finops-template.md +662 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-algorithme-public-template.md +162 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-anssi-carto-template.md +196 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-anssi-template.md +190 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-code-reuse-template.md +190 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-dinum-template.md +195 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-dr-template.md +187 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-ebios-template.md +209 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-irn-template.md +311 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-marche-public-template.md +178 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-pssi-template.md +270 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-rgpd-template.md +195 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/fr-secnumcloud-template.md +188 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/framework-overview-template.md +247 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gap-analysis-template.md +198 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gcloud-clarify-template.md +340 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gcloud-requirements-template.md +370 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gcp-research-template.md +585 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/glossary-template.md +117 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gov-code-search-template.md +213 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gov-landscape-template.md +271 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/gov-reuse-template.md +214 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/grants-template.md +131 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/hld-review-template.md +760 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/jsp-936-template.md +1394 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/maturity-model-template.md +297 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/mlops-template.md +720 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/mod-secure-by-design-template.md +784 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/operationalize-template.md +1016 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/pages-template.html +5121 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/platform-design-template.md +1610 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/presentation-template.md +270 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/principles-compliance-assessment-template.md +389 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/project-plan-template.md +421 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/rationalization-template.md +208 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/requirements-template.md +1026 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/research-findings-template.md +939 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/risk-register-template.md +883 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/roadmap-template.md +787 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/service-assessment-prep-template.md +448 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/servicenow-design-template.md +273 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/sobc-template.md +1127 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/sow-template.md +785 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/stakeholder-drivers-template.md +493 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/story-template.md +889 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/tcop-review-template.md +593 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/tech-note-template.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/tenders-template.md +124 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/traceability-matrix-template.md +360 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/transition-architecture-template.md +286 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-ai-autonomy-tier-template.md +97 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-ai-charter-template.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-classification-template.md +86 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-cloud-residency-template.md +136 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-data-sharing-template.md +105 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-digital-records-template.md +97 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-ias-template.md +109 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-pdpl-template.md +105 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-priorities-alignment-template.md +99 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-procurement-template.md +115 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-uaepass-template.md +129 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uae-zero-bureaucracy-template.md +85 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-consumer-duty-board-report-template.md +49 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-consumer-duty-template.md +362 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-ctp-dependency-register-template.md +24 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-ctp-dependency-template.md +321 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-safeguarding-reconciliation-template.md +77 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-safeguarding-template.md +348 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-sca-rts-exemption-matrix-template.md +47 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-fs-sca-rts-template.md +273 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-gov-ai-playbook-template.md +942 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-gov-atrs-template.md +1087 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-mdr-classification-template.md +307 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0129-case-template.md +214 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0129-hazard-template.md +217 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0129-safety-template.md +78 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0129-template.md +13 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0160-deployment-case-template.md +207 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0160-deployment-hazard-template.md +290 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0160-deployment-safety-template.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dcb0160-template.md +13 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/uk-nhs-dtac-template.md +341 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/ukgov-secure-by-design-template.md +1031 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-ai-impact-template.md +212 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-ai-rmf-template.md +232 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-fedramp-readiness-template.md +209 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-fedramp-ssp-template.md +352 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-fisma-categorization-template.md +145 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-icam-template.md +216 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-nist-800-53-template.md +222 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-privacy-pia-template.md +191 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-sbom-eo-14028-template.md +253 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/us-zero-trust-template.md +234 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/vendor-profile-template.md +88 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/vendor-scoring-template.md +332 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/wardley-climate-template.md +269 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/wardley-doctrine-template.md +299 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/wardley-gameplay-template.md +346 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/wardley-map-template.md +587 -0
- arckit_cli-6.1.1.data/data/share/arckit/.arckit/templates/wardley-value-chain-template.md +256 -0
- arckit_cli-6.1.1.data/data/share/arckit/CHANGELOG.md +3554 -0
- arckit_cli-6.1.1.data/data/share/arckit/VERSION +1 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/DEPENDENCY-MATRIX.md +929 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/README.md +322 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/WORKFLOW-DIAGRAMS.md +1088 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/adm-preliminary.md +72 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/adr.md +60 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-design.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-governance.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-integration.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-inventory.md +60 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-maturity.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/agent-security.md +63 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ai-playbook.md +103 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/analyze.md +57 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/application-inventory.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/application-rationalization.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/architecture-board.md +60 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/architecture-change.md +73 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/architecture-repository.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/artifact-health.md +228 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/at-bvergg.md +86 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/at-dsgvo.md +75 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/at-nisg.md +94 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/atrs.md +98 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-aescsf.md +45 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-ai-assurance.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-disp-attestation.md +90 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-dss.md +76 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-e8-posture.md +73 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-energy-compliance.md +47 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-federal-overlay.md +199 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-ism-controls.md +78 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-ndb-playbook.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-ot-security.md +39 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-pia.md +72 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-pspf.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/au-soci-cirmp.md +40 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/autoresearch.md +334 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/aws-research.md +160 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/azure-research.md +157 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/backlog.md +58 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/build.md +132 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/business-capability-map.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/business-case.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/c4-layout-science.md +280 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-aia.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-atip.md +79 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-charter.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-cloud-residency.md +91 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-fitaa.md +81 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-gc-digital-standards.md +93 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-itsg-33.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-ocap.md +91 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-ola.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-pia.md +83 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-pspc.md +96 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/ca-soia.md +87 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/codes-of-practice.md +154 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/competitors.md +202 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/conformance.md +153 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/create.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/custom-commands.md +236 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/customize.md +108 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/data-mesh-contract.md +239 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/data-model.md +69 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/data-quality-framework.md +118 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/datascout.md +162 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/declaration.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/design-review.md +66 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/devops.md +96 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/dfd.md +187 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/diagram.md +118 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/dld-review.md +102 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/dos.md +109 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/dpia.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/enterprise-scale.md +260 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-ai-act.md +82 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-cra.md +90 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-data-act.md +85 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-dora.md +83 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-dsa.md +85 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-nis2.md +82 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/eu-rgpd.md +76 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/evaluate.md +115 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/export-okf.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/finops.md +117 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-algorithme-public.md +86 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-anssi-carto.md +69 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-anssi.md +79 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-code-reuse.md +86 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-dinum.md +83 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-dr.md +88 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-ebios.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-irn.md +103 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-marche-public.md +94 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-pssi.md +87 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-rgpd.md +75 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/fr-secnumcloud.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/framework.md +234 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gap-analysis.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gcloud-clarify.md +108 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gcloud-competitors.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gcloud-search.md +106 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gcp-research.md +169 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/glossary.md +190 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gov-code-search.md +119 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gov-landscape.md +114 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/gov-reuse.md +112 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/govs-007-security.md +93 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/grants.md +106 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/graph-report.md +77 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/health.md +234 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/hld-review.md +110 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/hooks.md +121 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/impact.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/import-okf.md +67 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/init.md +159 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/jsp-936.md +60 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/knowledge-compounding.md +140 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/maturity-model.md +186 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/mcp-servers.md +329 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/migration.md +333 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/mlops.md +126 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/mod-secure.md +124 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/national-data-strategy.md +115 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/navigator.md +86 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/operationalize.md +143 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/pages.md +227 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/pinecone-mcp.md +128 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/plan.md +66 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/platform-design.md +600 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/presentation.md +137 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/pricing.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/principles-compliance.md +63 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/principles.md +55 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/procurement.md +57 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/productivity.md +217 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/remote-control.md +151 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/requirements.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/research.md +65 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/review.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/risk-management.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/risk.md +132 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roadmap.md +58 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/README.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/business-analyst.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/business-architect.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/cdo.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/ciso.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/cto-cdio.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/data-architect.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/data-governance-manager.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/delivery-manager.md +63 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/devops-engineer.md +55 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/enterprise-architect.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/it-service-manager.md +55 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/network-architect.md +58 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/performance-analyst.md +67 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/product-manager.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/security-architect.md +78 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/service-owner.md +58 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/solution-architect.md +75 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/roles/technical-architect.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/score.md +91 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/sdd-lot1.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/sdd-lot2.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/sdd-lot3.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/search.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/secure.md +181 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/security-hooks.md +200 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/security.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/service-assessment.md +47 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/service-design.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/servicenow.md +152 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/session-memory.md +100 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/sobc.md +129 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/sow.md +125 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/stakeholder-analysis.md +51 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/stakeholders.md +138 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/start.md +276 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/story.md +61 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/strategy.md +211 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/submission-pack.md +72 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/supplier-profile.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/tcop.md +124 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/template-builder.md +125 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/tenders.md +193 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/testing-plugin-branches.md +79 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/traceability.md +58 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/transition-architecture.md +69 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/trello.md +139 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-ai-autonomy-tier.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-ai-charter.md +89 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-classification.md +73 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-cloud-residency.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-data-sharing.md +84 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-digital-records.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-ias.md +93 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-overlay-maintenance.md +154 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-overlay.md +208 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-pdpl.md +73 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-priorities-alignment.md +82 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-procurement.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-uaepass.md +83 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uae-zero-bureaucracy.md +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-fs-consumer-duty.md +178 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-fs-ctp-dependency.md +181 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-fs-payments-overlay.md +216 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-fs-safeguarding.md +176 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-fs-sca-rts.md +164 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/ai-playbook.md +56 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/algorithmic-transparency.md +44 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/digital-marketplace.md +55 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/secure-by-design.md +51 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/standards-map.md +108 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-government/technology-code-of-practice.md +63 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-mdr-classification.md +59 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-mod/secure-by-design.md +54 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-nhs-clinical-safety-overlay.md +214 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-nhs-dcb0129.md +64 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-nhs-dcb0160.md +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/uk-nhs-dtac.md +55 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/upgrading.md +130 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-ai-impact.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-ai-rmf.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-federal-overlay.md +111 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-fedramp-readiness.md +69 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-fedramp-ssp.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-fisma-categorization.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-icam.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-nist-800-53.md +70 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-privacy-pia.md +74 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-sbom-eo-14028.md +71 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/us-zero-trust.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/wardley-climate.md +122 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/wardley-doctrine.md +120 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/wardley-gameplay.md +123 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/wardley-value-chain.md +130 -0
- arckit_cli-6.1.1.data/data/share/arckit/docs/guides/wardley.md +173 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/.agents/plugins/marketplace.json +20 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/README.md +325 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/VERSION +1 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/docs/DEPENDENCY-MATRIX.md +616 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/arckit-codex-hook.mjs +1270 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/graph-inject.mjs +1497 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/graph-rollups.mjs +247 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/graph-utils.mjs +363 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/hook-utils.mjs +383 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/hooks.json +80 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/okf-frontmatter.mjs +279 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/project-context-builder.mjs +168 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-codex/hooks/sync-guides.mjs +1120 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-copilot/README.md +68 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-copilot/VERSION +1 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-copilot/docs/DEPENDENCY-MATRIX.md +616 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-opencode/LICENSE +21 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-opencode/README.md +65 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-opencode/VERSION +1 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-opencode/docs/DEPENDENCY-MATRIX.md +616 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-opencode/opencode.json +25 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-vibe/.mcp.json +63 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-vibe/LICENSE +26 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-vibe/README.md +407 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-vibe/VERSION +1 -0
- arckit_cli-6.1.1.data/data/share/arckit/extensions/arckit-vibe/vibe-config.toml +62 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/README.md +680 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/autoresearch/fixtures/000-global/ARC-000-PRIN-v1.0.md +120 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/autoresearch/fixtures/001-test-project/ARC-001-STKE-v1.0.md +100 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/autoresearch/fixtures/001-test-project/README.md +15 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/autoresearch/program-selfharness.md +748 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/autoresearch/program.md +269 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/check-prerequisites.sh +250 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/common.sh +359 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/create-project.sh +408 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/generate-document-id.sh +146 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/list-projects.sh +359 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bash/migrate-filenames.sh +553 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/bump-version.sh +293 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/check_doctype_collisions.py +30 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/check_recipes.py +94 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/check_references.py +144 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/convert_vibe_agents.py +198 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/convert_vibe_skills.py +499 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/converter.py +2002 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/create-sdg-repo.py +820 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/generate-arckit-architecture-hero.py +317 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/generate-arckit-hero.py +278 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/generate-release-notes.sh +112 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/managed-agents/README.md +105 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/managed-agents/arckit-agent.py +418 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/push-extensions.sh +424 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/apply_doc_control_marker.py +50 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/common.py +288 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/create-project.py +373 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/generate-document-id.py +96 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/list-projects.py +238 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/python/migrate_classification.py +94 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/render-brand-pngs.py +72 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/standardise-colon.py +128 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/sync-claude-plugin-layout.py +159 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/sync-shared-assets.py +132 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/tag-plugins.sh +65 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/tests/test-doc-types-dual-registration.mjs +57 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/tests/test-fde-templates.mjs +100 -0
- arckit_cli-6.1.1.data/data/share/arckit/scripts/tests/test-regime-registration.mjs +65 -0
- arckit_cli-6.1.1.dist-info/METADATA +1966 -0
- arckit_cli-6.1.1.dist-info/RECORD +482 -0
- arckit_cli-6.1.1.dist-info/WHEEL +4 -0
- arckit_cli-6.1.1.dist-info/entry_points.txt +2 -0
- arckit_cli-6.1.1.dist-info/licenses/LICENSE +26 -0
|
@@ -0,0 +1,2002 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CLAUDE_ONLY_COMMAND_FIELDS = (
|
|
10
|
+
"effort",
|
|
11
|
+
"keep-coding-instructions",
|
|
12
|
+
"paths",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
CLAUDE_ONLY_AGENT_FIELDS = (
|
|
16
|
+
"effort",
|
|
17
|
+
"initialPrompt",
|
|
18
|
+
"maxTurns",
|
|
19
|
+
"disallowedTools",
|
|
20
|
+
"tools",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
USER_CONFIG_PLACEHOLDER_RE = re.compile(r"\$\{user_config\.([A-Za-z_][A-Za-z0-9_]*)\}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def rewrite_user_config_placeholders(value):
|
|
28
|
+
"""Rewrite Claude Code `${user_config.KEY}` placeholders to plain `${KEY}`.
|
|
29
|
+
|
|
30
|
+
Non-Claude extensions (Codex, Gemini, OpenCode, Copilot) don't support
|
|
31
|
+
plugin user config and fall back to shell environment variables.
|
|
32
|
+
"""
|
|
33
|
+
if not isinstance(value, str):
|
|
34
|
+
return value
|
|
35
|
+
return USER_CONFIG_PLACEHOLDER_RE.sub(r"${\1}", value)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def rewrite_copilot_command_invocations(prompt):
|
|
39
|
+
"""Rewrite Claude-style ArcKit slash commands to Copilot prompt names."""
|
|
40
|
+
return prompt.replace("/arckit:", "/arckit-")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def build_agent_map(agents_dir):
|
|
44
|
+
"""Build a map from command name to agent file path and content.
|
|
45
|
+
|
|
46
|
+
Agent files are named arckit-{name}.md. The corresponding plugin command
|
|
47
|
+
is {name}.md. Returns {command_filename: (agent_path, agent_prompt)}.
|
|
48
|
+
"""
|
|
49
|
+
agent_map = {}
|
|
50
|
+
if not os.path.isdir(agents_dir):
|
|
51
|
+
return agent_map
|
|
52
|
+
for filename in os.listdir(agents_dir):
|
|
53
|
+
if filename.startswith("arckit-") and filename.endswith(".md"):
|
|
54
|
+
# arckit-research.md -> research.md
|
|
55
|
+
name = filename.replace("arckit-", "", 1).replace(".md", "")
|
|
56
|
+
command_filename = f"{name}.md"
|
|
57
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
58
|
+
if is_subagent_file(agent_path):
|
|
59
|
+
continue
|
|
60
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
61
|
+
agent_content = f.read()
|
|
62
|
+
agent_prompt = extract_agent_prompt(agent_content)
|
|
63
|
+
agent_map[command_filename] = (agent_path, agent_prompt)
|
|
64
|
+
return agent_map
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def extract_frontmatter_and_prompt(content):
|
|
68
|
+
"""Extract YAML frontmatter dict and prompt body from markdown."""
|
|
69
|
+
frontmatter = {}
|
|
70
|
+
prompt = content
|
|
71
|
+
if content.startswith("---"):
|
|
72
|
+
parts = content.split("---", 2)
|
|
73
|
+
if len(parts) > 2:
|
|
74
|
+
try:
|
|
75
|
+
frontmatter = yaml.safe_load(parts[1]) or {}
|
|
76
|
+
except yaml.YAMLError:
|
|
77
|
+
frontmatter = {}
|
|
78
|
+
prompt = parts[2].strip()
|
|
79
|
+
return frontmatter, prompt
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def extract_agent_prompt(content):
|
|
83
|
+
"""Extract prompt body from agent file, stripping agent-specific frontmatter."""
|
|
84
|
+
if content.startswith("---"):
|
|
85
|
+
parts = content.split("---", 2)
|
|
86
|
+
if len(parts) > 2:
|
|
87
|
+
return parts[2].strip()
|
|
88
|
+
return content
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def is_subagent_file(agent_path):
|
|
92
|
+
"""True if the agent file's frontmatter has `subagent: true`.
|
|
93
|
+
|
|
94
|
+
Subagents are reader/writer subagents dispatched by an orchestrator
|
|
95
|
+
via the Claude Code Agent tool. They are Claude-only — non-Claude
|
|
96
|
+
runtimes (Codex, Gemini, OpenCode, Copilot) do not support subagent
|
|
97
|
+
dispatch, so the converter filters them out of those targets.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
101
|
+
content = f.read()
|
|
102
|
+
except OSError:
|
|
103
|
+
return False
|
|
104
|
+
if not content.startswith("---"):
|
|
105
|
+
return False
|
|
106
|
+
parts = content.split("---", 2)
|
|
107
|
+
if len(parts) < 3:
|
|
108
|
+
return False
|
|
109
|
+
try:
|
|
110
|
+
fm = yaml.safe_load(parts[1]) or {}
|
|
111
|
+
except yaml.YAMLError:
|
|
112
|
+
return False
|
|
113
|
+
return bool(fm.get("subagent"))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def copy_agent_stripped(src_path, dest_path, config=None):
|
|
117
|
+
"""Copy an agent file to dest, stripping Claude-only frontmatter fields."""
|
|
118
|
+
with open(src_path, "r", encoding="utf-8") as f:
|
|
119
|
+
content = f.read()
|
|
120
|
+
if content.startswith("---"):
|
|
121
|
+
parts = content.split("---", 2)
|
|
122
|
+
if len(parts) > 2:
|
|
123
|
+
try:
|
|
124
|
+
fm = yaml.safe_load(parts[1]) or {}
|
|
125
|
+
except yaml.YAMLError:
|
|
126
|
+
fm = {}
|
|
127
|
+
for field in CLAUDE_ONLY_AGENT_FIELDS:
|
|
128
|
+
fm.pop(field, None)
|
|
129
|
+
rebuilt = "---\n" + yaml.dump(fm, default_flow_style=False, allow_unicode=True) + "---" + parts[2]
|
|
130
|
+
if config:
|
|
131
|
+
rebuilt = rewrite_paths(rebuilt, config)
|
|
132
|
+
with open(dest_path, "w", encoding="utf-8") as f:
|
|
133
|
+
f.write(rebuilt)
|
|
134
|
+
return
|
|
135
|
+
if config:
|
|
136
|
+
content = rewrite_paths(content, config)
|
|
137
|
+
# No frontmatter — plain copy
|
|
138
|
+
with open(dest_path, "w", encoding="utf-8") as f:
|
|
139
|
+
f.write(content)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def render_handoffs_section(handoffs, command_format="/arckit:{cmd}"):
|
|
143
|
+
"""Render handoffs list as a markdown Suggested Next Steps section."""
|
|
144
|
+
if not handoffs:
|
|
145
|
+
return ""
|
|
146
|
+
lines = [
|
|
147
|
+
"",
|
|
148
|
+
"## Suggested Next Steps",
|
|
149
|
+
"",
|
|
150
|
+
"After completing this command, consider running:",
|
|
151
|
+
"",
|
|
152
|
+
]
|
|
153
|
+
for h in handoffs:
|
|
154
|
+
cmd = h.get("command", "")
|
|
155
|
+
desc = h.get("description", "")
|
|
156
|
+
cond = h.get("condition", "")
|
|
157
|
+
invocation = (
|
|
158
|
+
command_format(cmd)
|
|
159
|
+
if callable(command_format)
|
|
160
|
+
else command_format.format(cmd=cmd)
|
|
161
|
+
)
|
|
162
|
+
line = f"- `{invocation}`"
|
|
163
|
+
if desc:
|
|
164
|
+
line += f" -- {desc}"
|
|
165
|
+
if cond:
|
|
166
|
+
line += f" *(when {cond})*"
|
|
167
|
+
lines.append(line)
|
|
168
|
+
lines.append("")
|
|
169
|
+
return "\n".join(lines)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def codex_skill_name(command_name):
|
|
173
|
+
"""Return a Codex-compatible skill name for an ArcKit command name."""
|
|
174
|
+
return f"arckit-{command_name.replace('.', '-')}"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def codex_skill_invocation(command_name):
|
|
178
|
+
"""Return the invocation string for a Codex skill-backed command."""
|
|
179
|
+
return f"${codex_skill_name(command_name)}"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def vibe_skill_name(command_name):
|
|
183
|
+
"""Return the Vibe skill filename/name for an ArcKit command name."""
|
|
184
|
+
return f"arckit-{command_name.replace('.', '-')}"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def titleize_arckit_name(name):
|
|
188
|
+
"""Return a human-readable ArcKit display name."""
|
|
189
|
+
stem = name.replace("arckit-", "", 1).replace(".", "-")
|
|
190
|
+
return "ArcKit " + " ".join(part.capitalize() for part in stem.split("-") if part)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
EXTENSION_FILE_ACCESS_BLOCK = """\
|
|
194
|
+
**IMPORTANT — Gemini Extension File Access**:
|
|
195
|
+
This command runs as a Gemini CLI extension. The extension directory \
|
|
196
|
+
(`~/.gemini/extensions/arckit/`) is outside the workspace sandbox, so you \
|
|
197
|
+
CANNOT use the read_file tool to access it. Instead:
|
|
198
|
+
|
|
199
|
+
- To read templates/files: use a shell command, e.g. `cat ~/.gemini/extensions/arckit/templates/foo-template.md`
|
|
200
|
+
- To list files: use `ls ~/.gemini/extensions/arckit/templates/`
|
|
201
|
+
- To run scripts: use `python3 ~/.gemini/extensions/arckit/scripts/python/create-project.py --json`
|
|
202
|
+
- To check file existence: use `test -f ~/.gemini/extensions/arckit/templates/foo-template.md && echo exists`
|
|
203
|
+
All extension file access MUST go through shell commands.
|
|
204
|
+
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
CONTEXT_HOOK_NOTE = (
|
|
208
|
+
"> **Note**: The ArcKit Project Context hook has already detected all "
|
|
209
|
+
"projects, artifacts, external documents, and global policies. Use that "
|
|
210
|
+
"context below \u2014 no need to scan directories manually."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
CONTEXT_HOOK_REPLACEMENT = (
|
|
214
|
+
"> **Note**: Before generating, scan `projects/` for existing project "
|
|
215
|
+
"directories. For each project, list all `ARC-*.md` artifacts, check "
|
|
216
|
+
"`external/` for reference documents, and check `000-global/` for "
|
|
217
|
+
"cross-project policies. If no external docs exist but they would "
|
|
218
|
+
"improve output, ask the user."
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# --- Plugin source directories merged into each non-Claude extension output ---
|
|
223
|
+
#
|
|
224
|
+
# After the v5.0.0 plugin split, commands live across 6 directories. Non-Claude
|
|
225
|
+
# extensions stay monolithic (per the v5 spec), so the converter walks every
|
|
226
|
+
# source and merges into one output per format.
|
|
227
|
+
#
|
|
228
|
+
# Order: community plugins first, core last. Filenames are jurisdiction-prefixed
|
|
229
|
+
# (uae-*, fr-*, ca-*, eu-*, at-*) so collisions don't happen, but if they ever
|
|
230
|
+
# did, core-last means core wins.
|
|
231
|
+
|
|
232
|
+
PLUGIN_SOURCES = [
|
|
233
|
+
"plugins/arckit-uae",
|
|
234
|
+
"plugins/arckit-fr",
|
|
235
|
+
"plugins/arckit-ca",
|
|
236
|
+
"plugins/arckit-eu",
|
|
237
|
+
"plugins/arckit-at",
|
|
238
|
+
"plugins/arckit-au",
|
|
239
|
+
"plugins/arckit-au-energy",
|
|
240
|
+
"plugins/arckit-us",
|
|
241
|
+
"plugins/arckit-uk-finance",
|
|
242
|
+
"plugins/arckit-uk-nhs",
|
|
243
|
+
"plugins/arckit-togaf-adm",
|
|
244
|
+
"plugins/arckit-agent-architecture",
|
|
245
|
+
"plugins/arckit-claude", # core last
|
|
246
|
+
]
|
|
247
|
+
# Intentionally EXCLUDED from PLUGIN_SOURCES (Claude Code only, not converted):
|
|
248
|
+
# - arckit-fde : standalone site-generator tooling plugin
|
|
249
|
+
# - arckit-uk-gcloud : PROPRIETARY overlay — must NOT be copied into the
|
|
250
|
+
# MIT-licensed public extension repos (licence leak).
|
|
251
|
+
# Ships as a Claude Code marketplace plugin only.
|
|
252
|
+
# (Both still appear in marketplace.json; exclusion here is deliberate, not drift.)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# --- Agent configuration: adding a new AI target = adding a dictionary entry ---
|
|
256
|
+
|
|
257
|
+
AGENT_CONFIG = {
|
|
258
|
+
"codex_extension": {
|
|
259
|
+
"name": "Codex Extension",
|
|
260
|
+
"output_dir": "extensions/arckit-codex/prompts",
|
|
261
|
+
"filename_pattern": "arckit.{name}.md",
|
|
262
|
+
"format": "markdown",
|
|
263
|
+
"path_prefix": ".arckit",
|
|
264
|
+
"extension_dir": "extensions/arckit-codex",
|
|
265
|
+
"copy_commands_to_extension": True,
|
|
266
|
+
"copy_agents_to_extension": True,
|
|
267
|
+
"project_template_overrides": True,
|
|
268
|
+
"has_context_hook": False,
|
|
269
|
+
"has_sync_guides_hook": False,
|
|
270
|
+
},
|
|
271
|
+
"codex_skills": {
|
|
272
|
+
"name": "Codex Skills",
|
|
273
|
+
"output_dir": "extensions/arckit-codex/skills",
|
|
274
|
+
"format": "skill",
|
|
275
|
+
"path_prefix": ".arckit",
|
|
276
|
+
"project_template_overrides": True,
|
|
277
|
+
"has_context_hook": False,
|
|
278
|
+
"has_sync_guides_hook": False,
|
|
279
|
+
},
|
|
280
|
+
"opencode": {
|
|
281
|
+
"name": "OpenCode CLI",
|
|
282
|
+
"output_dir": "extensions/arckit-opencode/commands",
|
|
283
|
+
"filename_pattern": "arckit.{name}.md",
|
|
284
|
+
"format": "markdown",
|
|
285
|
+
"path_prefix": ".arckit",
|
|
286
|
+
"extension_dir": "extensions/arckit-opencode",
|
|
287
|
+
"copy_agents_to_extension": True,
|
|
288
|
+
"has_context_hook": False,
|
|
289
|
+
"has_sync_guides_hook": False,
|
|
290
|
+
},
|
|
291
|
+
"gemini": {
|
|
292
|
+
"name": "Gemini CLI",
|
|
293
|
+
"output_dir": "extensions/arckit-gemini/commands/arckit",
|
|
294
|
+
"filename_pattern": "{name}.toml",
|
|
295
|
+
"format": "toml",
|
|
296
|
+
"path_prefix": "~/.gemini/extensions/arckit",
|
|
297
|
+
"arg_placeholder": "{{args}}",
|
|
298
|
+
"extension_dir": "extensions/arckit-gemini",
|
|
299
|
+
"prepend_block": EXTENSION_FILE_ACCESS_BLOCK,
|
|
300
|
+
"rewrite_read_instructions": True,
|
|
301
|
+
"has_context_hook": True,
|
|
302
|
+
"has_sync_guides_hook": False,
|
|
303
|
+
},
|
|
304
|
+
"copilot": {
|
|
305
|
+
"name": "Copilot",
|
|
306
|
+
"output_dir": "extensions/arckit-copilot/prompts",
|
|
307
|
+
"filename_pattern": "arckit-{name}.prompt.md",
|
|
308
|
+
"format": "prompt",
|
|
309
|
+
"path_prefix": ".arckit",
|
|
310
|
+
"arg_placeholder": "${input:topic:Enter project name or topic}",
|
|
311
|
+
"extension_dir": "extensions/arckit-copilot",
|
|
312
|
+
"copy_commands_to_extension": False,
|
|
313
|
+
"copy_agents_to_extension": False,
|
|
314
|
+
"has_context_hook": False,
|
|
315
|
+
"has_sync_guides_hook": False,
|
|
316
|
+
},
|
|
317
|
+
"paperclip": {
|
|
318
|
+
"name": "Paperclip",
|
|
319
|
+
"output_dir": "extensions/arckit-paperclip/src/data",
|
|
320
|
+
"format": "json",
|
|
321
|
+
"path_prefix": "scripts/bash",
|
|
322
|
+
"script_path_prefix": "scripts",
|
|
323
|
+
"arg_placeholder": "{topic}",
|
|
324
|
+
"extension_dir": "extensions/arckit-paperclip",
|
|
325
|
+
"copy_commands_to_extension": False,
|
|
326
|
+
"copy_agents_to_extension": False,
|
|
327
|
+
"copy_scripts_to_extension": False,
|
|
328
|
+
"has_context_hook": False,
|
|
329
|
+
"has_sync_guides_hook": False,
|
|
330
|
+
},
|
|
331
|
+
"vibe": {
|
|
332
|
+
"name": "Mistral Vibe",
|
|
333
|
+
"output_dir": "extensions/arckit-vibe/skills",
|
|
334
|
+
"filename_pattern": "{name}.md",
|
|
335
|
+
"format": "vibe_skill",
|
|
336
|
+
"path_prefix": "${VIBE_EXTENSION_ROOT}",
|
|
337
|
+
"extension_dir": "extensions/arckit-vibe",
|
|
338
|
+
"arg_placeholder": "${args}",
|
|
339
|
+
"copy_commands_to_extension": False,
|
|
340
|
+
"copy_agents_to_extension": False,
|
|
341
|
+
"copy_core_skills_to_extension": False,
|
|
342
|
+
"copy_scripts_to_extension": True,
|
|
343
|
+
"copy_references_to_extension": True,
|
|
344
|
+
"copy_schemas_to_extension": True,
|
|
345
|
+
"clean_output_dir": True,
|
|
346
|
+
"has_context_hook": False,
|
|
347
|
+
"has_sync_guides_hook": False,
|
|
348
|
+
},
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def rewrite_paths(prompt, config):
|
|
353
|
+
"""Rewrite ${CLAUDE_PLUGIN_ROOT} paths using agent config."""
|
|
354
|
+
result = rewrite_user_config_placeholders(prompt)
|
|
355
|
+
|
|
356
|
+
# Claude commands use literal `.arckit/templates/` for project-local
|
|
357
|
+
# overrides and `${CLAUDE_PLUGIN_ROOT}/templates/` for shipped defaults.
|
|
358
|
+
# Codex projects keep shipped defaults in `.arckit/templates/`, so their
|
|
359
|
+
# project override path must be rewritten before plugin-root expansion.
|
|
360
|
+
if config.get("project_template_overrides"):
|
|
361
|
+
result = result.replace(".arckit/templates/", ".arckit/templates-custom/")
|
|
362
|
+
|
|
363
|
+
if config.get("script_path_prefix"):
|
|
364
|
+
result = result.replace(
|
|
365
|
+
"${CLAUDE_PLUGIN_ROOT}/scripts/",
|
|
366
|
+
f"{config['script_path_prefix']}/",
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
result = result.replace("${CLAUDE_PLUGIN_ROOT}", config["path_prefix"])
|
|
370
|
+
|
|
371
|
+
if config.get("rewrite_read_instructions"):
|
|
372
|
+
result = re.sub(
|
|
373
|
+
r"Read `(" + re.escape(config["path_prefix"]) + r"/[^`]+)`",
|
|
374
|
+
r"Run `cat \1` to read the file",
|
|
375
|
+
result,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
if config.get("prepend_block"):
|
|
379
|
+
result = config["prepend_block"] + result
|
|
380
|
+
|
|
381
|
+
if config.get("arg_placeholder"):
|
|
382
|
+
result = result.replace("$ARGUMENTS", config["arg_placeholder"])
|
|
383
|
+
|
|
384
|
+
if config.get("format") == "prompt":
|
|
385
|
+
result = rewrite_copilot_command_invocations(result)
|
|
386
|
+
|
|
387
|
+
return result
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def rewrite_hook_dependencies(prompt, config):
|
|
391
|
+
"""Replace hook-dependent content for platforms without hooks."""
|
|
392
|
+
result = prompt
|
|
393
|
+
|
|
394
|
+
# Context injection: replace hook note with self-scan instructions
|
|
395
|
+
if not config.get("has_context_hook", False):
|
|
396
|
+
result = result.replace(CONTEXT_HOOK_NOTE, CONTEXT_HOOK_REPLACEMENT)
|
|
397
|
+
|
|
398
|
+
return result
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# Default Copilot tools for most ArcKit commands
|
|
402
|
+
_COPILOT_DEFAULT_TOOLS = [
|
|
403
|
+
"readFile", "editFiles", "runCommand", "codebase", "search",
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
# Additional tools for research-heavy commands
|
|
407
|
+
_COPILOT_RESEARCH_TOOLS = [
|
|
408
|
+
"fetch", "readFile", "editFiles", "runCommand", "codebase", "search",
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _copilot_tools_for_prompt(prompt):
|
|
413
|
+
"""Determine Copilot tools based on prompt content."""
|
|
414
|
+
if any(kw in prompt for kw in ["WebSearch", "WebFetch", "web research",
|
|
415
|
+
"search the web", "fetch", "MCP"]):
|
|
416
|
+
return _COPILOT_RESEARCH_TOOLS
|
|
417
|
+
return _COPILOT_DEFAULT_TOOLS
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def format_output(description, prompt, fmt):
|
|
421
|
+
"""Format into target format: 'markdown', 'toml', 'prompt', 'skill', or 'vibe_skill'."""
|
|
422
|
+
if fmt == "toml":
|
|
423
|
+
prompt_escaped = prompt.replace("\\", "\\\\").replace('"', '\\"')
|
|
424
|
+
prompt_formatted = '"""\n' + prompt_escaped + '\n"""'
|
|
425
|
+
description_formatted = '"""\n' + description + '\n"""'
|
|
426
|
+
return f"description = {description_formatted}\nprompt = {prompt_formatted}\n"
|
|
427
|
+
elif fmt == "prompt":
|
|
428
|
+
prompt = rewrite_copilot_command_invocations(prompt)
|
|
429
|
+
escaped = description.replace("'", "''")
|
|
430
|
+
tools = _copilot_tools_for_prompt(prompt)
|
|
431
|
+
tools_yaml = "[" + ", ".join(f"'{t}'" for t in tools) + "]"
|
|
432
|
+
return (
|
|
433
|
+
f"---\n"
|
|
434
|
+
f"description: '{escaped}'\n"
|
|
435
|
+
f"agent: 'agent'\n"
|
|
436
|
+
f"tools: {tools_yaml}\n"
|
|
437
|
+
f"---\n\n"
|
|
438
|
+
f"{prompt}\n"
|
|
439
|
+
)
|
|
440
|
+
elif fmt == "vibe_skill":
|
|
441
|
+
return f"{prompt}\n"
|
|
442
|
+
else:
|
|
443
|
+
escaped = description.replace("\\", "\\\\").replace('"', '\\"')
|
|
444
|
+
return f'---\ndescription: "{escaped}"\n---\n\n{prompt}\n'
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def format_json_entry(name, description, prompt, template_content, handoffs):
|
|
448
|
+
"""Build a single JSON-serializable entry for commands.json."""
|
|
449
|
+
processed_handoffs = []
|
|
450
|
+
for h in (handoffs or []):
|
|
451
|
+
entry = {
|
|
452
|
+
"command": f"arckit-{h.get('command', '')}",
|
|
453
|
+
"description": h.get("description", ""),
|
|
454
|
+
}
|
|
455
|
+
if h.get("condition"):
|
|
456
|
+
entry["condition"] = h["condition"]
|
|
457
|
+
processed_handoffs.append(entry)
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
"name": f"arckit-{name}",
|
|
461
|
+
"description": description,
|
|
462
|
+
"prompt": prompt,
|
|
463
|
+
"template": template_content,
|
|
464
|
+
"handoffs": processed_handoffs,
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def read_template_for_command(name, templates_dir):
|
|
469
|
+
"""Read the template file for a command, if one exists.
|
|
470
|
+
|
|
471
|
+
Template naming convention: {name}-template.md
|
|
472
|
+
"""
|
|
473
|
+
template_path = os.path.join(templates_dir, f"{name}-template.md")
|
|
474
|
+
if os.path.isfile(template_path):
|
|
475
|
+
with open(template_path, "r", encoding="utf-8") as f:
|
|
476
|
+
return f.read()
|
|
477
|
+
return None
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def convert(commands_dirs, agents_dir):
|
|
481
|
+
"""Convert plugin commands to all configured AI agent formats.
|
|
482
|
+
|
|
483
|
+
Reads each plugin command once across all source directories, resolves
|
|
484
|
+
agent prompts once, then writes output formats with appropriate path
|
|
485
|
+
rewriting driven by AGENT_CONFIG.
|
|
486
|
+
|
|
487
|
+
Args:
|
|
488
|
+
commands_dirs: List of source command directories to merge
|
|
489
|
+
(e.g. ["plugins/arckit-uae/commands/", ..., "plugins/arckit-claude/commands/"]).
|
|
490
|
+
Multiple sources land in the same monolithic extension output per
|
|
491
|
+
the v5.0.0 plugin split design.
|
|
492
|
+
agents_dir: Single agents directory (agents stay in core).
|
|
493
|
+
"""
|
|
494
|
+
# Commands that depend on Claude Code-only features (parallel Agent dispatch,
|
|
495
|
+
# plugin skills, etc.). Skipped when generating non-Claude formats because
|
|
496
|
+
# they would silently fail or behave incorrectly on those platforms.
|
|
497
|
+
claude_only_commands = {"build.md"}
|
|
498
|
+
|
|
499
|
+
for config in AGENT_CONFIG.values():
|
|
500
|
+
os.makedirs(config["output_dir"], exist_ok=True)
|
|
501
|
+
if config.get("format") == "skill":
|
|
502
|
+
for dirname in os.listdir(config["output_dir"]):
|
|
503
|
+
if dirname.startswith("arckit-"):
|
|
504
|
+
skill_dir = os.path.join(config["output_dir"], dirname)
|
|
505
|
+
if os.path.isdir(skill_dir):
|
|
506
|
+
shutil.rmtree(skill_dir)
|
|
507
|
+
elif config.get("clean_output_dir"):
|
|
508
|
+
shutil.rmtree(config["output_dir"], ignore_errors=True)
|
|
509
|
+
os.makedirs(config["output_dir"], exist_ok=True)
|
|
510
|
+
|
|
511
|
+
agent_map = build_agent_map(agents_dir)
|
|
512
|
+
counts = {agent_id: 0 for agent_id in AGENT_CONFIG}
|
|
513
|
+
paperclip_entries = []
|
|
514
|
+
|
|
515
|
+
# Build merged file list across all plugin sources. Each entry is
|
|
516
|
+
# (commands_dir, filename) so per-source path lookups (templates,
|
|
517
|
+
# standalone overrides) resolve against the correct plugin's tree.
|
|
518
|
+
merged_files = []
|
|
519
|
+
seen_filenames = set()
|
|
520
|
+
for commands_dir in commands_dirs:
|
|
521
|
+
if not os.path.isdir(commands_dir):
|
|
522
|
+
continue
|
|
523
|
+
for filename in sorted(os.listdir(commands_dir)):
|
|
524
|
+
if not filename.endswith(".md"):
|
|
525
|
+
continue
|
|
526
|
+
if filename in seen_filenames:
|
|
527
|
+
# Collision (community vs core, or community vs community).
|
|
528
|
+
# Filenames are jurisdiction-prefixed so this shouldn't
|
|
529
|
+
# happen in practice; warn loudly if it does.
|
|
530
|
+
print(
|
|
531
|
+
f" WARNING: duplicate filename {filename} in {commands_dir} "
|
|
532
|
+
f"— skipping (first occurrence wins)"
|
|
533
|
+
)
|
|
534
|
+
continue
|
|
535
|
+
seen_filenames.add(filename)
|
|
536
|
+
merged_files.append((commands_dir, filename))
|
|
537
|
+
|
|
538
|
+
# Sort by filename so extension output order doesn't depend on the
|
|
539
|
+
# PLUGIN_SOURCES iteration order (paperclip's commands.json ordering
|
|
540
|
+
# was previously alphabetical across all commands; preserve that).
|
|
541
|
+
merged_files.sort(key=lambda entry: entry[1])
|
|
542
|
+
|
|
543
|
+
for commands_dir, filename in merged_files:
|
|
544
|
+
if filename in claude_only_commands:
|
|
545
|
+
print(f" Skipped Claude-only command: {filename}")
|
|
546
|
+
continue
|
|
547
|
+
|
|
548
|
+
command_path = os.path.join(commands_dir, filename)
|
|
549
|
+
|
|
550
|
+
with open(command_path, "r", encoding="utf-8") as f:
|
|
551
|
+
command_content = f.read()
|
|
552
|
+
|
|
553
|
+
# Extract frontmatter from command (always use command's description)
|
|
554
|
+
frontmatter, command_prompt = extract_frontmatter_and_prompt(command_content)
|
|
555
|
+
description = frontmatter.get("description", "")
|
|
556
|
+
handoffs = frontmatter.get("handoffs", [])
|
|
557
|
+
# Strip Claude-only fields — they have no meaning for Codex/OpenCode/Gemini/Copilot targets
|
|
558
|
+
for field in CLAUDE_ONLY_COMMAND_FIELDS:
|
|
559
|
+
frontmatter.pop(field, None)
|
|
560
|
+
|
|
561
|
+
# For agent-delegating commands, use the full agent prompt
|
|
562
|
+
# (non-Claude targets don't support the Task/agent architecture)
|
|
563
|
+
if filename in agent_map:
|
|
564
|
+
agent_path, agent_prompt = agent_map[filename]
|
|
565
|
+
prompt = agent_prompt
|
|
566
|
+
# Agent prompts don't contain $ARGUMENTS — append it so the
|
|
567
|
+
# user's query is injected into the generated command
|
|
568
|
+
if "$ARGUMENTS" not in prompt:
|
|
569
|
+
prompt += "\n\n## User Request\n\n```text\n$ARGUMENTS\n```\n"
|
|
570
|
+
source_label = f"{command_path} (agent: {agent_path})"
|
|
571
|
+
else:
|
|
572
|
+
prompt = command_prompt
|
|
573
|
+
source_label = command_path
|
|
574
|
+
|
|
575
|
+
base_name = filename.replace(".md", "")
|
|
576
|
+
|
|
577
|
+
# Collect entry for Paperclip JSON format
|
|
578
|
+
if "paperclip" in AGENT_CONFIG:
|
|
579
|
+
pc_config = AGENT_CONFIG["paperclip"]
|
|
580
|
+
pc_prompt = rewrite_paths(prompt, pc_config)
|
|
581
|
+
pc_prompt = rewrite_hook_dependencies(pc_prompt, pc_config)
|
|
582
|
+
template_content = read_template_for_command(
|
|
583
|
+
base_name,
|
|
584
|
+
os.path.join(os.path.dirname(commands_dir.rstrip(os.sep)), "templates"),
|
|
585
|
+
)
|
|
586
|
+
paperclip_entries.append(
|
|
587
|
+
format_json_entry(base_name, description, pc_prompt, template_content, handoffs)
|
|
588
|
+
)
|
|
589
|
+
counts["paperclip"] += 1
|
|
590
|
+
|
|
591
|
+
# Check for standalone command override once (result is agent-independent)
|
|
592
|
+
standalone_path = os.path.join(
|
|
593
|
+
os.path.dirname(commands_dir.rstrip(os.sep)), "commands-standalone", filename
|
|
594
|
+
)
|
|
595
|
+
has_standalone = os.path.isfile(standalone_path)
|
|
596
|
+
standalone_prompt = None
|
|
597
|
+
if has_standalone:
|
|
598
|
+
with open(standalone_path, "r", encoding="utf-8") as f:
|
|
599
|
+
standalone_content = f.read()
|
|
600
|
+
_, standalone_prompt = extract_frontmatter_and_prompt(standalone_content)
|
|
601
|
+
|
|
602
|
+
for agent_id, config in AGENT_CONFIG.items():
|
|
603
|
+
if config["format"] == "json":
|
|
604
|
+
continue # Handled separately (single file for all commands)
|
|
605
|
+
|
|
606
|
+
if has_standalone and not config.get("has_sync_guides_hook", False):
|
|
607
|
+
# Use standalone version for platforms lacking required hook
|
|
608
|
+
rewritten = rewrite_paths(standalone_prompt, config)
|
|
609
|
+
else:
|
|
610
|
+
rewritten = rewrite_paths(prompt, config)
|
|
611
|
+
rewritten = rewrite_hook_dependencies(rewritten, config)
|
|
612
|
+
|
|
613
|
+
# Determine handoff command format based on target
|
|
614
|
+
if config["format"] == "prompt":
|
|
615
|
+
cmd_fmt = "/arckit-{cmd}"
|
|
616
|
+
elif config["format"] == "skill":
|
|
617
|
+
cmd_fmt = codex_skill_invocation
|
|
618
|
+
elif config["format"] == "vibe_skill":
|
|
619
|
+
cmd_fmt = lambda cmd: f"/{vibe_skill_name(cmd)}"
|
|
620
|
+
else:
|
|
621
|
+
cmd_fmt = "/arckit:{cmd}"
|
|
622
|
+
|
|
623
|
+
handoffs_section = render_handoffs_section(handoffs, command_format=cmd_fmt)
|
|
624
|
+
|
|
625
|
+
if handoffs_section:
|
|
626
|
+
rewritten = rewritten.rstrip("\n") + "\n" + handoffs_section.rstrip("\n")
|
|
627
|
+
|
|
628
|
+
# For Copilot prompt format with agent-backed commands,
|
|
629
|
+
# generate a thin wrapper that references the .agent.md file
|
|
630
|
+
if config["format"] == "prompt" and filename in agent_map:
|
|
631
|
+
agent_name = filename.replace(".md", "")
|
|
632
|
+
agent_ref = f"arckit-{agent_name}"
|
|
633
|
+
escaped_desc = description.replace("'", "''")
|
|
634
|
+
tools = _copilot_tools_for_prompt(rewritten)
|
|
635
|
+
tools_yaml = "[" + ", ".join(f"'{t}'" for t in tools) + "]"
|
|
636
|
+
|
|
637
|
+
content = (
|
|
638
|
+
f"---\n"
|
|
639
|
+
f"description: '{escaped_desc}'\n"
|
|
640
|
+
f"agent: '{agent_ref}'\n"
|
|
641
|
+
f"tools: {tools_yaml}\n"
|
|
642
|
+
f"---\n\n"
|
|
643
|
+
f"Use the `{agent_ref}` agent to handle this request.\n"
|
|
644
|
+
)
|
|
645
|
+
if handoffs_section:
|
|
646
|
+
content += "\n" + handoffs_section.strip("\n") + "\n"
|
|
647
|
+
content = rewrite_copilot_command_invocations(content)
|
|
648
|
+
|
|
649
|
+
out_filename = config["filename_pattern"].format(name=base_name)
|
|
650
|
+
out_path = os.path.join(config["output_dir"], out_filename)
|
|
651
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
652
|
+
f.write(content)
|
|
653
|
+
print(f" {config['name'] + ':':14s}{source_label} -> {out_path} (agent wrapper)")
|
|
654
|
+
counts[agent_id] += 1
|
|
655
|
+
continue
|
|
656
|
+
|
|
657
|
+
if config["format"] == "skill":
|
|
658
|
+
skill_name = codex_skill_name(base_name)
|
|
659
|
+
skill_dir = os.path.join(config["output_dir"], skill_name)
|
|
660
|
+
os.makedirs(skill_dir, exist_ok=True)
|
|
661
|
+
os.makedirs(os.path.join(skill_dir, "agents"), exist_ok=True)
|
|
662
|
+
|
|
663
|
+
escaped_desc = description.replace('"', '\\"')
|
|
664
|
+
skill_md = f'---\nname: {skill_name}\ndescription: "{escaped_desc}"\n---\n\n{rewritten}\n'
|
|
665
|
+
openai_yaml = "policy:\n allow_implicit_invocation: false\n"
|
|
666
|
+
|
|
667
|
+
with open(os.path.join(skill_dir, "SKILL.md"), "w", encoding="utf-8") as f:
|
|
668
|
+
f.write(skill_md)
|
|
669
|
+
with open(os.path.join(skill_dir, "agents", "openai.yaml"), "w", encoding="utf-8") as f:
|
|
670
|
+
f.write(openai_yaml)
|
|
671
|
+
|
|
672
|
+
print(f" {config['name'] + ':':14s}{source_label} -> {skill_dir}/")
|
|
673
|
+
counts[agent_id] += 1
|
|
674
|
+
elif config["format"] == "vibe_skill":
|
|
675
|
+
skill_name = vibe_skill_name(base_name)
|
|
676
|
+
content_prompt = format_output(description, rewritten, config["format"])
|
|
677
|
+
escaped_desc = description.replace('"', '\\"')
|
|
678
|
+
skill_md = (
|
|
679
|
+
f"---\n"
|
|
680
|
+
f"name: {skill_name}\n"
|
|
681
|
+
f"display_name: {titleize_arckit_name(skill_name)}\n"
|
|
682
|
+
f"description: \"{escaped_desc}\"\n"
|
|
683
|
+
f"tags: [arckit, architecture, governance]\n"
|
|
684
|
+
f"---\n\n"
|
|
685
|
+
f"{content_prompt}"
|
|
686
|
+
)
|
|
687
|
+
out_filename = config["filename_pattern"].format(name=skill_name)
|
|
688
|
+
out_path = os.path.join(config["output_dir"], out_filename)
|
|
689
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
690
|
+
f.write(skill_md)
|
|
691
|
+
print(f" {config['name'] + ':':14s}{source_label} -> {out_path}")
|
|
692
|
+
counts[agent_id] += 1
|
|
693
|
+
else:
|
|
694
|
+
content = format_output(description, rewritten, config["format"])
|
|
695
|
+
out_filename = config["filename_pattern"].format(name=base_name)
|
|
696
|
+
out_path = os.path.join(config["output_dir"], out_filename)
|
|
697
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
698
|
+
f.write(content)
|
|
699
|
+
print(f" {config['name'] + ':':14s}{source_label} -> {out_path}")
|
|
700
|
+
counts[agent_id] += 1
|
|
701
|
+
|
|
702
|
+
# Write Paperclip commands.json (single file for all commands)
|
|
703
|
+
if "paperclip" in AGENT_CONFIG and paperclip_entries:
|
|
704
|
+
pc_config = AGENT_CONFIG["paperclip"]
|
|
705
|
+
os.makedirs(pc_config["output_dir"], exist_ok=True)
|
|
706
|
+
out_path = os.path.join(pc_config["output_dir"], "commands.json")
|
|
707
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
708
|
+
json.dump(paperclip_entries, f, indent=2, ensure_ascii=False)
|
|
709
|
+
print(f" {'Paperclip:':14s}Generated {out_path} ({len(paperclip_entries)} commands)")
|
|
710
|
+
|
|
711
|
+
return counts
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def copy_extension_files(plugin_sources):
|
|
715
|
+
"""Copy supporting files from all plugin sources to extension directories.
|
|
716
|
+
|
|
717
|
+
After the v5.0.0 plugin split, `templates/` lives in 6 different source
|
|
718
|
+
directories (one per plugin). Non-Claude extensions stay monolithic, so
|
|
719
|
+
templates from every source are merged into one `templates/` per extension.
|
|
720
|
+
Other directories (scripts, guides, config, schemas, skills, references)
|
|
721
|
+
only exist in `arckit-claude` and are copied from there.
|
|
722
|
+
|
|
723
|
+
Args:
|
|
724
|
+
plugin_sources: List of plugin source dirs (e.g. ["plugins/arckit-uae",
|
|
725
|
+
..., "plugins/arckit-claude"]). The last entry MUST be the core plugin
|
|
726
|
+
("plugins/arckit-claude") since that's where scripts/guides/etc. live.
|
|
727
|
+
"""
|
|
728
|
+
core_plugin_dir = plugin_sources[-1]
|
|
729
|
+
|
|
730
|
+
# Categories that exist only in the core plugin and are copied from there.
|
|
731
|
+
core_only_copies = [
|
|
732
|
+
("scripts/bash", "scripts/bash"),
|
|
733
|
+
("scripts/python", "scripts/python"),
|
|
734
|
+
("scripts/validate-handoff.mjs", "scripts/validate-handoff.mjs"),
|
|
735
|
+
("scripts/owm-to-mermaid.mjs", "scripts/owm-to-mermaid.mjs"),
|
|
736
|
+
("scripts/export-okf.mjs", "scripts/export-okf.mjs"),
|
|
737
|
+
("scripts/import-okf.mjs", "scripts/import-okf.mjs"),
|
|
738
|
+
# owm-tidy.mjs is invoked by /arckit:wardley --tidy-owm; ship it and its
|
|
739
|
+
# placement-engine dependency so the flag works on non-Claude CLIs too.
|
|
740
|
+
("hooks/owm-tidy.mjs", "hooks/owm-tidy.mjs"),
|
|
741
|
+
("hooks/okf-frontmatter.mjs", "hooks/okf-frontmatter.mjs"),
|
|
742
|
+
("hooks/wardley-label-placement.mjs", "hooks/wardley-label-placement.mjs"),
|
|
743
|
+
("docs/guides", "docs/guides"),
|
|
744
|
+
("config", "config"),
|
|
745
|
+
("schemas", "schemas"),
|
|
746
|
+
("skills", "skills"),
|
|
747
|
+
("references", "references"),
|
|
748
|
+
]
|
|
749
|
+
|
|
750
|
+
# Skills that depend on Claude Code-only features (parallel Agent tool
|
|
751
|
+
# dispatch, plugin hooks). Skipped when copying to non-Claude extensions
|
|
752
|
+
# because they would either silently fail or behave incorrectly there.
|
|
753
|
+
claude_only_skills = {"arckit-build"}
|
|
754
|
+
|
|
755
|
+
for config in AGENT_CONFIG.values():
|
|
756
|
+
ext_dir = config.get("extension_dir")
|
|
757
|
+
if not ext_dir:
|
|
758
|
+
continue
|
|
759
|
+
copy_scripts = config.get("copy_scripts_to_extension", True)
|
|
760
|
+
print(f"Copying to {config['name']} extension ({ext_dir})...")
|
|
761
|
+
|
|
762
|
+
# Merge templates from every plugin source into one templates/ dir.
|
|
763
|
+
ext_templates_dir = os.path.join(ext_dir, "templates")
|
|
764
|
+
if os.path.isdir(ext_templates_dir):
|
|
765
|
+
shutil.rmtree(ext_templates_dir)
|
|
766
|
+
os.makedirs(ext_templates_dir, exist_ok=True)
|
|
767
|
+
merged_template_count = 0
|
|
768
|
+
for src_plugin in plugin_sources:
|
|
769
|
+
src_templates = os.path.join(src_plugin, "templates")
|
|
770
|
+
if not os.path.isdir(src_templates):
|
|
771
|
+
continue
|
|
772
|
+
for entry in os.listdir(src_templates):
|
|
773
|
+
src_path = os.path.join(src_templates, entry)
|
|
774
|
+
dst_path = os.path.join(ext_templates_dir, entry)
|
|
775
|
+
if os.path.isfile(src_path):
|
|
776
|
+
shutil.copy2(src_path, dst_path)
|
|
777
|
+
merged_template_count += 1
|
|
778
|
+
elif os.path.isdir(src_path):
|
|
779
|
+
if os.path.isdir(dst_path):
|
|
780
|
+
shutil.rmtree(dst_path)
|
|
781
|
+
shutil.copytree(src_path, dst_path)
|
|
782
|
+
merged_template_count += sum(
|
|
783
|
+
len(files) for _, _, files in os.walk(dst_path)
|
|
784
|
+
)
|
|
785
|
+
print(
|
|
786
|
+
f" Merged templates from {len(plugin_sources)} plugin source(s) "
|
|
787
|
+
f"-> {ext_templates_dir} ({merged_template_count} files)"
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
# Core-only categories
|
|
791
|
+
for src_rel, dst_rel in core_only_copies:
|
|
792
|
+
if not copy_scripts and src_rel.startswith("scripts/"):
|
|
793
|
+
continue
|
|
794
|
+
if src_rel == "skills" and not config.get("copy_core_skills_to_extension", True):
|
|
795
|
+
continue
|
|
796
|
+
src = os.path.join(core_plugin_dir, src_rel)
|
|
797
|
+
dst = os.path.join(ext_dir, dst_rel)
|
|
798
|
+
if os.path.isdir(src):
|
|
799
|
+
if os.path.isdir(dst):
|
|
800
|
+
shutil.rmtree(dst)
|
|
801
|
+
shutil.copytree(src, dst)
|
|
802
|
+
if dst_rel == "skills":
|
|
803
|
+
# Skip Claude-only skills for non-Claude targets
|
|
804
|
+
for skill_name in claude_only_skills:
|
|
805
|
+
skill_path = os.path.join(dst, skill_name)
|
|
806
|
+
if os.path.isdir(skill_path):
|
|
807
|
+
shutil.rmtree(skill_path)
|
|
808
|
+
print(f" Skipped Claude-only skill: {skill_name}")
|
|
809
|
+
strip_claude_only_skill_fields(dst)
|
|
810
|
+
file_count = sum(len(files) for _, _, files in os.walk(dst))
|
|
811
|
+
print(f" Copied: {src} -> {dst} ({file_count} files)")
|
|
812
|
+
elif os.path.isfile(src):
|
|
813
|
+
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
|
814
|
+
shutil.copy2(src, dst)
|
|
815
|
+
print(f" Copied: {src} -> {dst}")
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def strip_claude_only_skill_fields(skills_dir):
|
|
819
|
+
"""Strip Claude-only frontmatter fields (e.g. paths) from SKILL.md files."""
|
|
820
|
+
if not os.path.isdir(skills_dir):
|
|
821
|
+
return
|
|
822
|
+
for root, _dirs, files in os.walk(skills_dir):
|
|
823
|
+
for filename in files:
|
|
824
|
+
if filename != "SKILL.md":
|
|
825
|
+
continue
|
|
826
|
+
filepath = os.path.join(root, filename)
|
|
827
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
828
|
+
content = f.read()
|
|
829
|
+
if not content.startswith("---"):
|
|
830
|
+
continue
|
|
831
|
+
parts = content.split("---", 2)
|
|
832
|
+
if len(parts) <= 2:
|
|
833
|
+
continue
|
|
834
|
+
try:
|
|
835
|
+
fm = yaml.safe_load(parts[1]) or {}
|
|
836
|
+
except yaml.YAMLError:
|
|
837
|
+
continue
|
|
838
|
+
if "paths" not in fm:
|
|
839
|
+
continue
|
|
840
|
+
fm.pop("paths", None)
|
|
841
|
+
rebuilt = (
|
|
842
|
+
"---\n"
|
|
843
|
+
+ yaml.dump(fm, default_flow_style=False, allow_unicode=True, sort_keys=False)
|
|
844
|
+
+ "---"
|
|
845
|
+
+ parts[2]
|
|
846
|
+
)
|
|
847
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
848
|
+
f.write(rebuilt)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def generate_codex_config_toml(mcp_json_path, agents_dir, output_path):
|
|
852
|
+
"""Generate config.toml for Codex extension with MCP servers and agent roles."""
|
|
853
|
+
def hook_command(event_name):
|
|
854
|
+
return (
|
|
855
|
+
"command = 'HOOK=\"${CODEX_PLUGIN_ROOT:+$CODEX_PLUGIN_ROOT/hooks/arckit-codex-hook.mjs}\"; "
|
|
856
|
+
"[ -f \"$HOOK\" ] || HOOK=\"$(git rev-parse --show-toplevel 2>/dev/null)/.codex/hooks/arckit-codex-hook.mjs\"; "
|
|
857
|
+
"[ -f \"$HOOK\" ] || HOOK=\"$(ls -td \"$HOME\"/.codex/plugins/cache/arckit/arckit-codex/*/hooks/arckit-codex-hook.mjs 2>/dev/null | head -n 1)\"; "
|
|
858
|
+
f"node \"$HOOK\" {event_name}'"
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
lines = [
|
|
862
|
+
"# ArcKit Codex Extension Configuration",
|
|
863
|
+
"# Auto-generated by scripts/converter.py — do not edit directly",
|
|
864
|
+
"",
|
|
865
|
+
"[features]",
|
|
866
|
+
"hooks = true",
|
|
867
|
+
"plugin_hooks = true",
|
|
868
|
+
"",
|
|
869
|
+
"# ── Lifecycle Hooks ─────────────────────────────────",
|
|
870
|
+
"# Resolve hook scripts from plugin root, project config, or installed plugin cache.",
|
|
871
|
+
"",
|
|
872
|
+
"[[hooks.SessionStart]]",
|
|
873
|
+
'matcher = "startup|resume|clear"',
|
|
874
|
+
"",
|
|
875
|
+
"[[hooks.SessionStart.hooks]]",
|
|
876
|
+
'type = "command"',
|
|
877
|
+
hook_command("SessionStart"),
|
|
878
|
+
"timeout = 10",
|
|
879
|
+
'statusMessage = "Loading ArcKit context"',
|
|
880
|
+
"",
|
|
881
|
+
"[[hooks.UserPromptSubmit]]",
|
|
882
|
+
"",
|
|
883
|
+
"[[hooks.UserPromptSubmit.hooks]]",
|
|
884
|
+
'type = "command"',
|
|
885
|
+
hook_command("UserPromptSubmit"),
|
|
886
|
+
"timeout = 10",
|
|
887
|
+
'statusMessage = "Checking ArcKit prompt"',
|
|
888
|
+
"",
|
|
889
|
+
"[[hooks.PreToolUse]]",
|
|
890
|
+
'matcher = "Read|Bash|apply_patch|Edit|Write"',
|
|
891
|
+
"",
|
|
892
|
+
"[[hooks.PreToolUse.hooks]]",
|
|
893
|
+
'type = "command"',
|
|
894
|
+
hook_command("PreToolUse"),
|
|
895
|
+
"timeout = 10",
|
|
896
|
+
'statusMessage = "Checking ArcKit file policy"',
|
|
897
|
+
"",
|
|
898
|
+
"[[hooks.PostToolUse]]",
|
|
899
|
+
'matcher = "apply_patch|Edit|Write"',
|
|
900
|
+
"",
|
|
901
|
+
"[[hooks.PostToolUse.hooks]]",
|
|
902
|
+
'type = "command"',
|
|
903
|
+
hook_command("PostToolUse"),
|
|
904
|
+
"timeout = 10",
|
|
905
|
+
'statusMessage = "Updating ArcKit metadata"',
|
|
906
|
+
"",
|
|
907
|
+
"[[hooks.PermissionRequest]]",
|
|
908
|
+
'matcher = "mcp__.*"',
|
|
909
|
+
"",
|
|
910
|
+
"[[hooks.PermissionRequest.hooks]]",
|
|
911
|
+
'type = "command"',
|
|
912
|
+
hook_command("PermissionRequest"),
|
|
913
|
+
"timeout = 10",
|
|
914
|
+
'statusMessage = "Checking ArcKit MCP policy"',
|
|
915
|
+
"",
|
|
916
|
+
"[[hooks.Stop]]",
|
|
917
|
+
"",
|
|
918
|
+
"[[hooks.Stop.hooks]]",
|
|
919
|
+
'type = "command"',
|
|
920
|
+
hook_command("Stop"),
|
|
921
|
+
"timeout = 10",
|
|
922
|
+
'statusMessage = "Recording ArcKit session"',
|
|
923
|
+
"",
|
|
924
|
+
]
|
|
925
|
+
|
|
926
|
+
# MCP servers section
|
|
927
|
+
if os.path.isfile(mcp_json_path):
|
|
928
|
+
with open(mcp_json_path, "r", encoding="utf-8") as f:
|
|
929
|
+
mcp_config = json.load(f)
|
|
930
|
+
servers = mcp_config.get("mcpServers", {})
|
|
931
|
+
if servers:
|
|
932
|
+
lines.append("# ── MCP Servers ─────────────────────────────────────")
|
|
933
|
+
lines.append("")
|
|
934
|
+
# Claude Code-only MCP fields that other platforms (Codex/Gemini/OpenCode)
|
|
935
|
+
# don't understand and shouldn't see in their generated configs.
|
|
936
|
+
CLAUDE_ONLY_MCP_FIELDS = {"alwaysLoad"}
|
|
937
|
+
for name, server in servers.items():
|
|
938
|
+
lines.append(f"[mcp_servers.{name}]")
|
|
939
|
+
for key, value in server.items():
|
|
940
|
+
if key in CLAUDE_ONLY_MCP_FIELDS:
|
|
941
|
+
continue
|
|
942
|
+
if key == "headers":
|
|
943
|
+
header_parts = []
|
|
944
|
+
for hk, hv in value.items():
|
|
945
|
+
header_parts.append(f'"{hk}" = "{rewrite_user_config_placeholders(hv)}"')
|
|
946
|
+
lines.append(f"headers = {{ {', '.join(header_parts)} }}")
|
|
947
|
+
else:
|
|
948
|
+
lines.append(f'{key} = "{rewrite_user_config_placeholders(value)}"')
|
|
949
|
+
lines.append("")
|
|
950
|
+
|
|
951
|
+
# Agent roles section
|
|
952
|
+
if os.path.isdir(agents_dir):
|
|
953
|
+
agent_files = sorted(
|
|
954
|
+
f for f in os.listdir(agents_dir)
|
|
955
|
+
if f.startswith("arckit-") and f.endswith(".md")
|
|
956
|
+
)
|
|
957
|
+
if agent_files:
|
|
958
|
+
lines.append("# ── Agent Roles (experimental) ──────────────────────")
|
|
959
|
+
lines.append("# Requires: codex multi-agent feature flag enabled")
|
|
960
|
+
lines.append("")
|
|
961
|
+
lines.append("[agents]")
|
|
962
|
+
lines.append("max_threads = 3")
|
|
963
|
+
lines.append("max_depth = 1")
|
|
964
|
+
lines.append("job_max_runtime_seconds = 600")
|
|
965
|
+
lines.append("")
|
|
966
|
+
|
|
967
|
+
for filename in agent_files:
|
|
968
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
969
|
+
if is_subagent_file(agent_path):
|
|
970
|
+
continue
|
|
971
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
972
|
+
content = f.read()
|
|
973
|
+
frontmatter, _ = extract_frontmatter_and_prompt(content)
|
|
974
|
+
name = frontmatter.get("name", filename.replace(".md", ""))
|
|
975
|
+
desc = frontmatter.get("description", "")
|
|
976
|
+
first_line = desc.strip().split("\n")[0].strip()
|
|
977
|
+
toml_name = filename.replace(".md", "")
|
|
978
|
+
|
|
979
|
+
lines.append(f"[agents.{name}]")
|
|
980
|
+
escaped_desc = first_line.replace('"', '\\"')
|
|
981
|
+
lines.append(f'description = "{escaped_desc}"')
|
|
982
|
+
lines.append(f'config_file = "agents/{toml_name}.toml"')
|
|
983
|
+
lines.append("")
|
|
984
|
+
|
|
985
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
986
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
987
|
+
f.write("\n".join(lines))
|
|
988
|
+
print(f" Generated: {output_path}")
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
def generate_codex_mcp_json(mcp_json_path, output_path):
|
|
992
|
+
"""Generate Codex plugin MCP config from Claude MCP config."""
|
|
993
|
+
if not os.path.isfile(mcp_json_path):
|
|
994
|
+
return
|
|
995
|
+
|
|
996
|
+
with open(mcp_json_path, "r", encoding="utf-8") as f:
|
|
997
|
+
mcp_config = json.load(f)
|
|
998
|
+
|
|
999
|
+
servers = mcp_config.get("mcpServers", {})
|
|
1000
|
+
codex_servers = {}
|
|
1001
|
+
for name, server in servers.items():
|
|
1002
|
+
codex_server = {}
|
|
1003
|
+
for key, value in server.items():
|
|
1004
|
+
if key == "alwaysLoad":
|
|
1005
|
+
continue
|
|
1006
|
+
if key == "headers":
|
|
1007
|
+
codex_server[key] = {
|
|
1008
|
+
header_name: rewrite_user_config_placeholders(header_value)
|
|
1009
|
+
for header_name, header_value in value.items()
|
|
1010
|
+
}
|
|
1011
|
+
else:
|
|
1012
|
+
codex_server[key] = rewrite_user_config_placeholders(value)
|
|
1013
|
+
codex_servers[name] = codex_server
|
|
1014
|
+
|
|
1015
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
1016
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
1017
|
+
json.dump({"mcpServers": codex_servers}, f, indent=2)
|
|
1018
|
+
f.write("\n")
|
|
1019
|
+
print(f" Generated: {output_path}")
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
def generate_codex_plugin_manifest(output_dir):
|
|
1023
|
+
"""Generate Codex plugin manifest for the standalone ArcKit Codex bundle."""
|
|
1024
|
+
version_path = os.path.join(output_dir, "VERSION")
|
|
1025
|
+
version = "0.0.0"
|
|
1026
|
+
if os.path.isfile(version_path):
|
|
1027
|
+
with open(version_path, "r", encoding="utf-8") as f:
|
|
1028
|
+
version = f.read().strip() or version
|
|
1029
|
+
|
|
1030
|
+
manifest = {
|
|
1031
|
+
"name": "arckit-codex",
|
|
1032
|
+
"version": version,
|
|
1033
|
+
"description": "Enterprise architecture governance, procurement, research, and delivery workflows for Codex.",
|
|
1034
|
+
"author": {
|
|
1035
|
+
"name": "ArcKit",
|
|
1036
|
+
"url": "https://github.com/tractorjuice/arc-kit",
|
|
1037
|
+
},
|
|
1038
|
+
"homepage": "https://github.com/tractorjuice/arckit-codex",
|
|
1039
|
+
"repository": "https://github.com/tractorjuice/arckit-codex",
|
|
1040
|
+
"license": "MIT",
|
|
1041
|
+
"keywords": [
|
|
1042
|
+
"enterprise-architecture",
|
|
1043
|
+
"governance",
|
|
1044
|
+
"procurement",
|
|
1045
|
+
"public-sector",
|
|
1046
|
+
"codex",
|
|
1047
|
+
],
|
|
1048
|
+
"skills": "./skills/",
|
|
1049
|
+
"mcpServers": "./.mcp.json",
|
|
1050
|
+
"hooks": "./hooks/hooks.json",
|
|
1051
|
+
"interface": {
|
|
1052
|
+
"displayName": "ArcKit",
|
|
1053
|
+
"shortDescription": "Architecture governance workflows for Codex",
|
|
1054
|
+
"longDescription": "Use ArcKit to create, review, and connect architecture, procurement, governance, compliance, research, and delivery artifacts in Codex.",
|
|
1055
|
+
"developerName": "ArcKit",
|
|
1056
|
+
"category": "Productivity",
|
|
1057
|
+
"capabilities": [
|
|
1058
|
+
"Interactive",
|
|
1059
|
+
"Write",
|
|
1060
|
+
"MCP",
|
|
1061
|
+
],
|
|
1062
|
+
"websiteURL": "https://github.com/tractorjuice/arc-kit",
|
|
1063
|
+
"defaultPrompt": [
|
|
1064
|
+
"Use ArcKit to start an architecture governance project.",
|
|
1065
|
+
"Use ArcKit to assess requirements, risks, decisions, and procurement options.",
|
|
1066
|
+
],
|
|
1067
|
+
"brandColor": "#2F6F6D",
|
|
1068
|
+
},
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
manifest_dir = os.path.join(output_dir, ".codex-plugin")
|
|
1072
|
+
os.makedirs(manifest_dir, exist_ok=True)
|
|
1073
|
+
manifest_path = os.path.join(manifest_dir, "plugin.json")
|
|
1074
|
+
with open(manifest_path, "w", encoding="utf-8") as f:
|
|
1075
|
+
json.dump(manifest, f, indent=2)
|
|
1076
|
+
f.write("\n")
|
|
1077
|
+
print(f" Generated: {manifest_path}")
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
def generate_agent_toml_files(agents_dir, output_dir, path_prefix=".arckit"):
|
|
1081
|
+
"""Generate per-agent .toml config files for Codex extension."""
|
|
1082
|
+
if not os.path.isdir(agents_dir):
|
|
1083
|
+
return
|
|
1084
|
+
|
|
1085
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
1086
|
+
count = 0
|
|
1087
|
+
|
|
1088
|
+
for filename in sorted(os.listdir(agents_dir)):
|
|
1089
|
+
if not (filename.startswith("arckit-") and filename.endswith(".md")):
|
|
1090
|
+
continue
|
|
1091
|
+
|
|
1092
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
1093
|
+
if is_subagent_file(agent_path):
|
|
1094
|
+
continue
|
|
1095
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
1096
|
+
content = f.read()
|
|
1097
|
+
|
|
1098
|
+
frontmatter, prompt = extract_frontmatter_and_prompt(content)
|
|
1099
|
+
prompt = rewrite_paths(
|
|
1100
|
+
prompt,
|
|
1101
|
+
{
|
|
1102
|
+
"path_prefix": path_prefix,
|
|
1103
|
+
"project_template_overrides": True,
|
|
1104
|
+
},
|
|
1105
|
+
)
|
|
1106
|
+
prompt_escaped = prompt.replace("\\", "\\\\").replace('"""', '\\"\\"\\"')
|
|
1107
|
+
|
|
1108
|
+
agent_name = frontmatter.get("name", filename.replace(".md", ""))
|
|
1109
|
+
|
|
1110
|
+
toml_name = filename.replace(".md", ".toml")
|
|
1111
|
+
toml_path = os.path.join(output_dir, toml_name)
|
|
1112
|
+
|
|
1113
|
+
toml_content = (
|
|
1114
|
+
f"# Auto-generated from plugins/arckit-claude/agents/{filename}\n"
|
|
1115
|
+
f"# Do not edit — edit the source and re-run scripts/converter.py\n"
|
|
1116
|
+
f"\n"
|
|
1117
|
+
f'name = "{agent_name}"\n'
|
|
1118
|
+
f"\n"
|
|
1119
|
+
f'developer_instructions = """\n'
|
|
1120
|
+
f"{prompt_escaped}\n"
|
|
1121
|
+
f'"""\n'
|
|
1122
|
+
)
|
|
1123
|
+
|
|
1124
|
+
with open(toml_path, "w", encoding="utf-8") as f:
|
|
1125
|
+
f.write(toml_content)
|
|
1126
|
+
count += 1
|
|
1127
|
+
|
|
1128
|
+
print(f" Generated {count} agent .toml files in {output_dir}")
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
VIBE_TOOL_MAP = {
|
|
1132
|
+
"Read": "read_file",
|
|
1133
|
+
"Glob": "glob",
|
|
1134
|
+
"Grep": "grep",
|
|
1135
|
+
"Write": "write_file",
|
|
1136
|
+
"Edit": "edit_file",
|
|
1137
|
+
"MultiEdit": "edit_file",
|
|
1138
|
+
"Bash": "bash",
|
|
1139
|
+
"TodoWrite": "todo",
|
|
1140
|
+
"WebSearch": "web_search",
|
|
1141
|
+
"WebFetch": "web_fetch",
|
|
1142
|
+
"AskUserQuestion": "ask_user_question",
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
def vibe_tool_name(tool_name):
|
|
1147
|
+
"""Translate Claude Code tool identifiers to Vibe tool identifiers."""
|
|
1148
|
+
if tool_name.startswith("mcp__plugin_arckit_"):
|
|
1149
|
+
return "mcp_" + tool_name.replace("mcp__plugin_arckit_", "", 1)
|
|
1150
|
+
return VIBE_TOOL_MAP.get(tool_name, tool_name)
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
def toml_string(value):
|
|
1154
|
+
"""Return a TOML-safe basic string."""
|
|
1155
|
+
return json.dumps(value or "", ensure_ascii=False)
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
def generate_vibe_agent_toml_files(agents_dir, output_dir, version, path_prefix="${VIBE_EXTENSION_ROOT}"):
|
|
1159
|
+
"""Generate Mistral Vibe agent .toml files from Claude agent definitions."""
|
|
1160
|
+
if not os.path.isdir(agents_dir):
|
|
1161
|
+
return []
|
|
1162
|
+
|
|
1163
|
+
shutil.rmtree(output_dir, ignore_errors=True)
|
|
1164
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
1165
|
+
generated = []
|
|
1166
|
+
|
|
1167
|
+
for filename in sorted(os.listdir(agents_dir)):
|
|
1168
|
+
if not (filename.startswith("arckit-") and filename.endswith(".md")):
|
|
1169
|
+
continue
|
|
1170
|
+
|
|
1171
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
1172
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
1173
|
+
content = f.read()
|
|
1174
|
+
|
|
1175
|
+
frontmatter, prompt = extract_frontmatter_and_prompt(content)
|
|
1176
|
+
prompt = rewrite_paths(
|
|
1177
|
+
prompt,
|
|
1178
|
+
{
|
|
1179
|
+
"path_prefix": path_prefix,
|
|
1180
|
+
"project_template_overrides": True,
|
|
1181
|
+
},
|
|
1182
|
+
)
|
|
1183
|
+
|
|
1184
|
+
agent_name = frontmatter.get("name", filename.replace(".md", ""))
|
|
1185
|
+
toml_name = f"{agent_name}.toml"
|
|
1186
|
+
toml_path = os.path.join(output_dir, toml_name)
|
|
1187
|
+
description = frontmatter.get("description", "")
|
|
1188
|
+
max_turns = int(frontmatter.get("maxTurns", 30) or 30)
|
|
1189
|
+
effort = frontmatter.get("effort", "high")
|
|
1190
|
+
model = frontmatter.get("model", "mistral-large-2")
|
|
1191
|
+
if model == "inherit":
|
|
1192
|
+
model = "mistral-large-2"
|
|
1193
|
+
tools = [vibe_tool_name(tool) for tool in frontmatter.get("tools", [])]
|
|
1194
|
+
|
|
1195
|
+
lines = [
|
|
1196
|
+
f"# ArcKit {titleize_arckit_name(agent_name)} Agent",
|
|
1197
|
+
f"# Derived from {agent_path}",
|
|
1198
|
+
"# Part of the ArcKit Enterprise Architecture Governance Harness",
|
|
1199
|
+
"",
|
|
1200
|
+
'agent_type = "subagent"',
|
|
1201
|
+
f"display_name = {toml_string(titleize_arckit_name(agent_name))}",
|
|
1202
|
+
"",
|
|
1203
|
+
f"description = {toml_string(description)}",
|
|
1204
|
+
"",
|
|
1205
|
+
'safety = "safe"',
|
|
1206
|
+
f"max_turns = {max_turns}",
|
|
1207
|
+
f"effort = {toml_string(effort)}",
|
|
1208
|
+
"",
|
|
1209
|
+
"# Tool permissions",
|
|
1210
|
+
f"enabled_tools = {json.dumps(tools, ensure_ascii=False)}",
|
|
1211
|
+
"disabled_tools = []",
|
|
1212
|
+
"",
|
|
1213
|
+
"# Model configuration",
|
|
1214
|
+
f"model = {toml_string(model)}",
|
|
1215
|
+
"",
|
|
1216
|
+
"# System prompt",
|
|
1217
|
+
f"system_prompt = {toml_string(prompt)}",
|
|
1218
|
+
"",
|
|
1219
|
+
"[metadata]",
|
|
1220
|
+
f"source = {toml_string(agent_path)}",
|
|
1221
|
+
f"version = {toml_string(version)}",
|
|
1222
|
+
f"tags = {json.dumps(['arckit', agent_name], ensure_ascii=False)}",
|
|
1223
|
+
"",
|
|
1224
|
+
]
|
|
1225
|
+
|
|
1226
|
+
with open(toml_path, "w", encoding="utf-8") as f:
|
|
1227
|
+
f.write("\n".join(lines))
|
|
1228
|
+
generated.append(toml_name)
|
|
1229
|
+
|
|
1230
|
+
print(f" Generated {len(generated)} Vibe agent .toml files in {output_dir}")
|
|
1231
|
+
return generated
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
def generate_vibe_config_toml(output_path, version, agent_files):
|
|
1235
|
+
"""Generate Mistral Vibe extension config."""
|
|
1236
|
+
lines = [
|
|
1237
|
+
"# ArcKit Mistral Vibe Extension Configuration",
|
|
1238
|
+
f"# Version: {version}",
|
|
1239
|
+
"# Generated from ArcKit canonical plugin (plugins/arckit-claude/)",
|
|
1240
|
+
"",
|
|
1241
|
+
"[extension]",
|
|
1242
|
+
'name = "arckit"',
|
|
1243
|
+
f"version = {toml_string(version)}",
|
|
1244
|
+
'description = """',
|
|
1245
|
+
"The Enterprise Architecture Governance Harness - 73+ slash commands across",
|
|
1246
|
+
"strategy, architecture, delivery, and assurance. Enables enterprise architects",
|
|
1247
|
+
"to manage architecture principles, requirements, vendor evaluation, risk",
|
|
1248
|
+
"management, and compliance workflows in Mistral Vibe.",
|
|
1249
|
+
'"""',
|
|
1250
|
+
'author = "TractorJuice"',
|
|
1251
|
+
'repository = "https://github.com/tractorjuice/arckit-vibe"',
|
|
1252
|
+
'license = "MIT"',
|
|
1253
|
+
'homepage = "https://tractorjuice.github.io/arc-kit/"',
|
|
1254
|
+
"",
|
|
1255
|
+
"[extension.feature_flags]",
|
|
1256
|
+
"enable_community_overlays = true",
|
|
1257
|
+
"enable_experimental = false",
|
|
1258
|
+
"",
|
|
1259
|
+
"[extension.mcp]",
|
|
1260
|
+
"servers = [",
|
|
1261
|
+
' "aws-knowledge",',
|
|
1262
|
+
' "microsoft-learn",',
|
|
1263
|
+
' "google-developer-knowledge",',
|
|
1264
|
+
' "govreposcrape",',
|
|
1265
|
+
' "datacommons-mcp"',
|
|
1266
|
+
"]",
|
|
1267
|
+
"",
|
|
1268
|
+
"[extension.agents]",
|
|
1269
|
+
"files = [",
|
|
1270
|
+
]
|
|
1271
|
+
for index, filename in enumerate(agent_files):
|
|
1272
|
+
suffix = "," if index < len(agent_files) - 1 else ""
|
|
1273
|
+
lines.append(f" {toml_string(filename)}{suffix}")
|
|
1274
|
+
lines.extend(
|
|
1275
|
+
[
|
|
1276
|
+
"]",
|
|
1277
|
+
"",
|
|
1278
|
+
"[extension.defaults]",
|
|
1279
|
+
'organisation_name = ""',
|
|
1280
|
+
'default_classification = "OFFICIAL"',
|
|
1281
|
+
'governance_framework = "Generic"',
|
|
1282
|
+
'classification_scheme = "UK"',
|
|
1283
|
+
'path_prefix = "${VIBE_EXTENSION_ROOT}"',
|
|
1284
|
+
'templates_dir = ".arckit/templates"',
|
|
1285
|
+
'custom_templates_dir = ".arckit/templates-custom"',
|
|
1286
|
+
"",
|
|
1287
|
+
]
|
|
1288
|
+
)
|
|
1289
|
+
|
|
1290
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
1291
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
1292
|
+
f.write("\n".join(lines))
|
|
1293
|
+
print(f" Generated: {output_path}")
|
|
1294
|
+
|
|
1295
|
+
|
|
1296
|
+
def copy_vibe_reference_skills(src_skills_dir, dest_skills_dir):
|
|
1297
|
+
"""Copy non-command reference skills into the Vibe extension."""
|
|
1298
|
+
if not os.path.isdir(src_skills_dir):
|
|
1299
|
+
return
|
|
1300
|
+
|
|
1301
|
+
os.makedirs(dest_skills_dir, exist_ok=True)
|
|
1302
|
+
count = 0
|
|
1303
|
+
for entry in sorted(os.listdir(src_skills_dir)):
|
|
1304
|
+
src = os.path.join(src_skills_dir, entry)
|
|
1305
|
+
if entry.startswith("arckit-") or not os.path.isdir(src):
|
|
1306
|
+
continue
|
|
1307
|
+
dst = os.path.join(dest_skills_dir, entry)
|
|
1308
|
+
if os.path.isdir(dst):
|
|
1309
|
+
shutil.rmtree(dst)
|
|
1310
|
+
shutil.copytree(src, dst)
|
|
1311
|
+
count += 1
|
|
1312
|
+
|
|
1313
|
+
print(f" Copied {count} Vibe reference skill dirs to {dest_skills_dir}")
|
|
1314
|
+
|
|
1315
|
+
|
|
1316
|
+
def rewrite_codex_skills(skills_dir):
|
|
1317
|
+
"""Rewrite Claude Code-specific references in skills for Codex extension.
|
|
1318
|
+
|
|
1319
|
+
- /arckit:X -> $arckit-X (skill invocation syntax)
|
|
1320
|
+
- /arckit.X -> $arckit-X
|
|
1321
|
+
- /prompts:arckit.X -> $arckit-X
|
|
1322
|
+
- Remove SessionStart hook references
|
|
1323
|
+
- ${CLAUDE_PLUGIN_ROOT} -> .arckit
|
|
1324
|
+
"""
|
|
1325
|
+
if not os.path.isdir(skills_dir):
|
|
1326
|
+
return
|
|
1327
|
+
|
|
1328
|
+
def normalize_codex_invocation(match):
|
|
1329
|
+
return codex_skill_invocation(match.group(1))
|
|
1330
|
+
|
|
1331
|
+
count = 0
|
|
1332
|
+
for root, dirs, files in os.walk(skills_dir):
|
|
1333
|
+
for filename in files:
|
|
1334
|
+
if not filename.endswith(".md"):
|
|
1335
|
+
continue
|
|
1336
|
+
filepath = os.path.join(root, filename)
|
|
1337
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
1338
|
+
content = f.read()
|
|
1339
|
+
|
|
1340
|
+
original = content
|
|
1341
|
+
|
|
1342
|
+
# Rewrite a small number of Claude Code-only workflow notes that
|
|
1343
|
+
# otherwise leak into generated Codex skills. Do this before the
|
|
1344
|
+
# generic command invocation rewrite so filesystem paths such as
|
|
1345
|
+
# `.claude/commands/arckit.foo.md` are converted as paths, not
|
|
1346
|
+
# accidentally rewritten into malformed `$arckit-foo` snippets.
|
|
1347
|
+
if os.path.basename(root) == "arckit-template-builder":
|
|
1348
|
+
content = content.replace("Slash Command", "Codex Skill")
|
|
1349
|
+
content = content.replace("slash command", "Codex skill")
|
|
1350
|
+
content = content.replace(
|
|
1351
|
+
"Ask these questions BEFORE reading any templates. Call the **AskUserQuestion** tool exactly once with all 4 questions below in a single call. Do NOT proceed until the user has answered.",
|
|
1352
|
+
"Ask these questions BEFORE reading any templates. Present all 4 questions together, then wait for the user's answers before continuing.",
|
|
1353
|
+
)
|
|
1354
|
+
content = content.replace(
|
|
1355
|
+
"Use the Read tool only — do NOT use Bash, Glob, or Agent to search for templates.",
|
|
1356
|
+
"Read these files directly. Do not search broadly or delegate this step.",
|
|
1357
|
+
)
|
|
1358
|
+
content = content.replace(" using the Write tool", "")
|
|
1359
|
+
content = content.replace(" using the Write tool.", ".")
|
|
1360
|
+
content = content.replace(
|
|
1361
|
+
"The Write tool MUST be used for all file creation (avoids token limit issues)",
|
|
1362
|
+
"Write generated artifacts to files instead of printing full content in the response",
|
|
1363
|
+
)
|
|
1364
|
+
content = content.replace("command file", "skill file")
|
|
1365
|
+
content = content.replace("Command Structure", "Skill Structure")
|
|
1366
|
+
content = content.replace(
|
|
1367
|
+
"Generate a matching `$arckit-community-{name}` skill file",
|
|
1368
|
+
"Generate a matching `$arckit-community-{name}` skill",
|
|
1369
|
+
)
|
|
1370
|
+
content = content.replace(
|
|
1371
|
+
"If \"Codex Skill\" is selected, generate a skill file in Step 6.",
|
|
1372
|
+
"If \"Codex Skill\" is selected, generate a skill in Step 6.",
|
|
1373
|
+
)
|
|
1374
|
+
content = content.replace(
|
|
1375
|
+
"description: {Brief description of what this command generates}\nargument-hint: \"<project ID or name>\"",
|
|
1376
|
+
"name: arckit-community-{name}\ndescription: \"{Brief description of what this skill generates}\"",
|
|
1377
|
+
)
|
|
1378
|
+
content = content.replace(
|
|
1379
|
+
".claude/commands/arckit.community.{name}.md",
|
|
1380
|
+
".agents/skills/arckit-community-{name}/SKILL.md",
|
|
1381
|
+
)
|
|
1382
|
+
content = content.replace(
|
|
1383
|
+
".claude/commands/arckit.community.security-assessment.md",
|
|
1384
|
+
".agents/skills/arckit-community-security-assessment/SKILL.md",
|
|
1385
|
+
)
|
|
1386
|
+
content = content.replace(".claude/commands/", ".agents/skills/")
|
|
1387
|
+
content = content.replace(".claude/commands", ".agents/skills")
|
|
1388
|
+
content = content.replace(
|
|
1389
|
+
"arckit.community.{name}.md",
|
|
1390
|
+
"arckit-community-{name}/SKILL.md",
|
|
1391
|
+
)
|
|
1392
|
+
content = content.replace(
|
|
1393
|
+
"arckit.community.security-assessment.md",
|
|
1394
|
+
"arckit-community-security-assessment/SKILL.md",
|
|
1395
|
+
)
|
|
1396
|
+
content = content.replace(
|
|
1397
|
+
"/arckit:community.{name}",
|
|
1398
|
+
"$arckit-community-{name}",
|
|
1399
|
+
)
|
|
1400
|
+
content = content.replace(
|
|
1401
|
+
"/arckit:community.security-assessment",
|
|
1402
|
+
"$arckit-community-security-assessment",
|
|
1403
|
+
)
|
|
1404
|
+
content = content.replace(
|
|
1405
|
+
"arckit.community.{name}",
|
|
1406
|
+
"$arckit-community-{name}",
|
|
1407
|
+
)
|
|
1408
|
+
content = content.replace(
|
|
1409
|
+
"arckit.community.security-assessment",
|
|
1410
|
+
"$arckit-community-security-assessment",
|
|
1411
|
+
)
|
|
1412
|
+
content = content.replace(
|
|
1413
|
+
"This location is auto-discovered by Claude Code as a project-level Codex skill",
|
|
1414
|
+
"This location is auto-discovered by Codex as a project-level skill",
|
|
1415
|
+
)
|
|
1416
|
+
|
|
1417
|
+
# Rewrite /arckit:X -> $arckit-X (colon-prefixed plugin format)
|
|
1418
|
+
content = re.sub(
|
|
1419
|
+
r"(?<![\w/])/arckit:(\w[\w.-]*)",
|
|
1420
|
+
normalize_codex_invocation,
|
|
1421
|
+
content,
|
|
1422
|
+
)
|
|
1423
|
+
|
|
1424
|
+
# Rewrite /arckit.X -> $arckit-X (dot-prefixed format)
|
|
1425
|
+
content = re.sub(
|
|
1426
|
+
r"(?<![\w/])/arckit\.(\w[\w.-]*)",
|
|
1427
|
+
normalize_codex_invocation,
|
|
1428
|
+
content,
|
|
1429
|
+
)
|
|
1430
|
+
|
|
1431
|
+
# Rewrite /prompts:arckit.X -> $arckit-X (old Codex prompt format)
|
|
1432
|
+
content = re.sub(
|
|
1433
|
+
r"/prompts:arckit\.(\w[\w.-]*)",
|
|
1434
|
+
normalize_codex_invocation,
|
|
1435
|
+
content,
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
# Normalize any already-rewritten skill invocations that still
|
|
1439
|
+
# contain command-name dots, such as $arckit-wardley.climate.
|
|
1440
|
+
content = re.sub(
|
|
1441
|
+
r"\$arckit-([A-Za-z0-9][A-Za-z0-9.-]*\.[A-Za-z0-9.-]*)",
|
|
1442
|
+
normalize_codex_invocation,
|
|
1443
|
+
content,
|
|
1444
|
+
)
|
|
1445
|
+
content = re.sub(r"(?<![\w/])/arckit:\*", "$arckit-*", content)
|
|
1446
|
+
content = re.sub(r"(?<![\w/])/arckit:", "$arckit-", content)
|
|
1447
|
+
content = re.sub(r"(?<![\w/])/arckit\.", "$arckit-", content)
|
|
1448
|
+
content = content.replace("`/$arckit-", "`$arckit-")
|
|
1449
|
+
content = content.replace("(/$arckit-", "($arckit-")
|
|
1450
|
+
content = content.replace("Run `/$arckit-", "Run `$arckit-")
|
|
1451
|
+
|
|
1452
|
+
# Codex skills should ask the user directly instead of naming
|
|
1453
|
+
# Claude Code's AskUserQuestion UI tool.
|
|
1454
|
+
content = re.sub(
|
|
1455
|
+
r"use the \*\*AskUserQuestion\*\* tool to gather",
|
|
1456
|
+
"ask the user for",
|
|
1457
|
+
content,
|
|
1458
|
+
flags=re.IGNORECASE,
|
|
1459
|
+
)
|
|
1460
|
+
content = re.sub(
|
|
1461
|
+
r"use the \*\*AskUserQuestion\*\* tool to ask",
|
|
1462
|
+
"ask the user",
|
|
1463
|
+
content,
|
|
1464
|
+
flags=re.IGNORECASE,
|
|
1465
|
+
)
|
|
1466
|
+
content = re.sub(
|
|
1467
|
+
r"use the AskUserQuestion tool to interactively gather",
|
|
1468
|
+
"ask the user for",
|
|
1469
|
+
content,
|
|
1470
|
+
flags=re.IGNORECASE,
|
|
1471
|
+
)
|
|
1472
|
+
content = re.sub(
|
|
1473
|
+
r"use the AskUserQuestion tool to gather",
|
|
1474
|
+
"ask the user for",
|
|
1475
|
+
content,
|
|
1476
|
+
flags=re.IGNORECASE,
|
|
1477
|
+
)
|
|
1478
|
+
content = re.sub(
|
|
1479
|
+
r"use AskUserQuestion to ask",
|
|
1480
|
+
"ask the user",
|
|
1481
|
+
content,
|
|
1482
|
+
flags=re.IGNORECASE,
|
|
1483
|
+
)
|
|
1484
|
+
content = re.sub(
|
|
1485
|
+
r"use AskUserQuestion to confirm",
|
|
1486
|
+
"ask the user to confirm",
|
|
1487
|
+
content,
|
|
1488
|
+
flags=re.IGNORECASE,
|
|
1489
|
+
)
|
|
1490
|
+
content = re.sub(
|
|
1491
|
+
r"use AskUserQuestion to clarify with the user",
|
|
1492
|
+
"ask the user to clarify",
|
|
1493
|
+
content,
|
|
1494
|
+
flags=re.IGNORECASE,
|
|
1495
|
+
)
|
|
1496
|
+
content = content.replace("using AskUserQuestion", "by asking the user")
|
|
1497
|
+
content = content.replace(
|
|
1498
|
+
"AskUserQuestion with multiple-choice options",
|
|
1499
|
+
"multiple-choice options",
|
|
1500
|
+
)
|
|
1501
|
+
content = content.replace("single AskUserQuestion call", "single message")
|
|
1502
|
+
content = content.replace("AskUserQuestion", "direct user question")
|
|
1503
|
+
|
|
1504
|
+
if os.path.basename(root) == "arckit-template-builder":
|
|
1505
|
+
content = content.replace(
|
|
1506
|
+
"For official promotion: rename command (drop `community.` prefix), change banner to `Template Origin: Official`, and open a PR.",
|
|
1507
|
+
"For official promotion: rename the generated skill if needed, change banner to `Template Origin: Official`, and open a PR.",
|
|
1508
|
+
)
|
|
1509
|
+
content = content.replace(
|
|
1510
|
+
"Rename skill file: drop `community.` prefix",
|
|
1511
|
+
"Rename or relocate the community skill if promoting it to an official ArcKit command",
|
|
1512
|
+
)
|
|
1513
|
+
content = content.replace(
|
|
1514
|
+
"Rename command file: drop `community.` prefix",
|
|
1515
|
+
"Rename or relocate the community skill if promoting it to an official ArcKit command",
|
|
1516
|
+
)
|
|
1517
|
+
content = content.replace(
|
|
1518
|
+
"Copy of the command (if generated)",
|
|
1519
|
+
"Copy of the skill (if generated)",
|
|
1520
|
+
)
|
|
1521
|
+
content = content.replace(
|
|
1522
|
+
"Copy the command (if generated)",
|
|
1523
|
+
"Copy of the skill (if generated)",
|
|
1524
|
+
)
|
|
1525
|
+
content = content.replace(
|
|
1526
|
+
"Community commands use the `community.` prefix",
|
|
1527
|
+
"Community skills use the `arckit-community-` prefix",
|
|
1528
|
+
)
|
|
1529
|
+
|
|
1530
|
+
content = content.replace(
|
|
1531
|
+
"Claude Code's 32K token output limit",
|
|
1532
|
+
"Codex output limits",
|
|
1533
|
+
)
|
|
1534
|
+
content = content.replace(
|
|
1535
|
+
"The Stop hook (`validate-wardley-math.mjs`) checks both blocks for consistency.",
|
|
1536
|
+
"Manually check that the OWM source and Mermaid output stay consistent after conversion.",
|
|
1537
|
+
)
|
|
1538
|
+
content = content.replace(
|
|
1539
|
+
"### Example 5: Continuous Monitoring with `/loop`",
|
|
1540
|
+
"### Example 5: Repeat Monitoring",
|
|
1541
|
+
)
|
|
1542
|
+
content = content.replace(
|
|
1543
|
+
"```bash\n/loop 30m $arckit-health SEVERITY=HIGH\n```",
|
|
1544
|
+
"```text\n$arckit-health SEVERITY=HIGH\n```",
|
|
1545
|
+
)
|
|
1546
|
+
content = content.replace(
|
|
1547
|
+
"Runs the health check every 30 minutes during your session, surfacing HIGH severity findings as they appear. Useful during long architecture sessions where multiple artifacts are being created or updated. Requires Claude Code v2.1.97+.",
|
|
1548
|
+
"Re-run this health check periodically during long architecture sessions to surface HIGH severity findings as artifacts change. Codex does not provide a built-in loop command; use a scheduler if you need automation.",
|
|
1549
|
+
)
|
|
1550
|
+
|
|
1551
|
+
# Remove SessionStart hook reference
|
|
1552
|
+
content = content.replace(
|
|
1553
|
+
"- Use ArcKit Project Context from the SessionStart hook if available\n",
|
|
1554
|
+
"",
|
|
1555
|
+
)
|
|
1556
|
+
|
|
1557
|
+
# Rewrite plugin root paths
|
|
1558
|
+
content = content.replace("${CLAUDE_PLUGIN_ROOT}", ".arckit")
|
|
1559
|
+
|
|
1560
|
+
if content != original:
|
|
1561
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
1562
|
+
f.write(content)
|
|
1563
|
+
rel_path = os.path.relpath(filepath, skills_dir)
|
|
1564
|
+
print(f" Rewrote: {skills_dir}/{rel_path}")
|
|
1565
|
+
count += 1
|
|
1566
|
+
|
|
1567
|
+
if count:
|
|
1568
|
+
print(f" Rewrote {count} skill files for Codex skill invocation format")
|
|
1569
|
+
|
|
1570
|
+
|
|
1571
|
+
def generate_gemini_agents(agents_dir, output_dir):
|
|
1572
|
+
"""Generate Gemini CLI sub-agent markdown files from Claude Code agents.
|
|
1573
|
+
|
|
1574
|
+
Reads each arckit-{name}.md from agents_dir, converts the YAML frontmatter
|
|
1575
|
+
(keeping name/description, dropping model, adding max_turns/timeout_mins),
|
|
1576
|
+
rewrites paths and Read instructions for Gemini, prepends the extension
|
|
1577
|
+
file access block, and writes to output_dir.
|
|
1578
|
+
"""
|
|
1579
|
+
if not os.path.isdir(agents_dir):
|
|
1580
|
+
print(f" Skipped: {agents_dir} not found")
|
|
1581
|
+
return
|
|
1582
|
+
|
|
1583
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
1584
|
+
gemini_path_prefix = "~/.gemini/extensions/arckit"
|
|
1585
|
+
count = 0
|
|
1586
|
+
|
|
1587
|
+
for filename in sorted(os.listdir(agents_dir)):
|
|
1588
|
+
if not (filename.startswith("arckit-") and filename.endswith(".md")):
|
|
1589
|
+
continue
|
|
1590
|
+
|
|
1591
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
1592
|
+
if is_subagent_file(agent_path):
|
|
1593
|
+
continue
|
|
1594
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
1595
|
+
content = f.read()
|
|
1596
|
+
|
|
1597
|
+
frontmatter, prompt = extract_frontmatter_and_prompt(content)
|
|
1598
|
+
|
|
1599
|
+
# Build Gemini frontmatter: keep name/description, drop model,
|
|
1600
|
+
# add Gemini-specific fields
|
|
1601
|
+
gemini_fm = {}
|
|
1602
|
+
if "name" in frontmatter:
|
|
1603
|
+
gemini_fm["name"] = frontmatter["name"]
|
|
1604
|
+
if "description" in frontmatter:
|
|
1605
|
+
gemini_fm["description"] = frontmatter["description"]
|
|
1606
|
+
gemini_fm["max_turns"] = 25
|
|
1607
|
+
gemini_fm["timeout_mins"] = 10
|
|
1608
|
+
|
|
1609
|
+
# Rewrite paths: ${CLAUDE_PLUGIN_ROOT} -> ~/.gemini/extensions/arckit
|
|
1610
|
+
prompt = prompt.replace("${CLAUDE_PLUGIN_ROOT}", gemini_path_prefix)
|
|
1611
|
+
prompt = rewrite_user_config_placeholders(prompt)
|
|
1612
|
+
|
|
1613
|
+
# Rewrite Read instructions to shell commands
|
|
1614
|
+
prompt = re.sub(
|
|
1615
|
+
r"Read `(" + re.escape(gemini_path_prefix) + r"/[^`]+)`",
|
|
1616
|
+
r"Run `cat \1` to read the file",
|
|
1617
|
+
prompt,
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
# Prepend extension file access block
|
|
1621
|
+
prompt = EXTENSION_FILE_ACCESS_BLOCK + prompt
|
|
1622
|
+
|
|
1623
|
+
# Serialize frontmatter with yaml for correct multi-line handling
|
|
1624
|
+
fm_str = yaml.dump(gemini_fm, default_flow_style=False, sort_keys=False).rstrip()
|
|
1625
|
+
output_content = f"---\n{fm_str}\n---\n\n{prompt}\n"
|
|
1626
|
+
|
|
1627
|
+
out_path = os.path.join(output_dir, filename)
|
|
1628
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
1629
|
+
f.write(output_content)
|
|
1630
|
+
print(f" {filename}")
|
|
1631
|
+
count += 1
|
|
1632
|
+
|
|
1633
|
+
print(f" Generated {count} Gemini sub-agent files in {output_dir}")
|
|
1634
|
+
|
|
1635
|
+
|
|
1636
|
+
def generate_gemini_hooks(output_dir):
|
|
1637
|
+
"""Generate hooks.json for Gemini CLI extension.
|
|
1638
|
+
|
|
1639
|
+
Creates extensions/arckit-gemini/hooks/hooks.json which tells Gemini CLI
|
|
1640
|
+
which hook scripts to run for each lifecycle event.
|
|
1641
|
+
"""
|
|
1642
|
+
hooks_dir = os.path.join(output_dir, "hooks")
|
|
1643
|
+
os.makedirs(hooks_dir, exist_ok=True)
|
|
1644
|
+
|
|
1645
|
+
hooks_config = {
|
|
1646
|
+
"hooks": {
|
|
1647
|
+
"SessionStart": [
|
|
1648
|
+
{
|
|
1649
|
+
"hooks": [
|
|
1650
|
+
{
|
|
1651
|
+
"type": "command",
|
|
1652
|
+
"command": "python3 ${extensionPath}/hooks/scripts/session-start.py",
|
|
1653
|
+
"name": "ArcKit Session Init",
|
|
1654
|
+
"timeout": 5000,
|
|
1655
|
+
"description": "Inject ArcKit version and project context",
|
|
1656
|
+
}
|
|
1657
|
+
]
|
|
1658
|
+
}
|
|
1659
|
+
],
|
|
1660
|
+
"BeforeAgent": [
|
|
1661
|
+
{
|
|
1662
|
+
"hooks": [
|
|
1663
|
+
{
|
|
1664
|
+
"type": "command",
|
|
1665
|
+
"command": "python3 ${extensionPath}/hooks/scripts/context-inject.py",
|
|
1666
|
+
"name": "ArcKit Context",
|
|
1667
|
+
"timeout": 10000,
|
|
1668
|
+
"description": "Inject project context before agent planning",
|
|
1669
|
+
}
|
|
1670
|
+
]
|
|
1671
|
+
}
|
|
1672
|
+
],
|
|
1673
|
+
"BeforeTool": [
|
|
1674
|
+
{
|
|
1675
|
+
"matcher": "write_file",
|
|
1676
|
+
"hooks": [
|
|
1677
|
+
{
|
|
1678
|
+
"type": "command",
|
|
1679
|
+
"command": "python3 ${extensionPath}/hooks/scripts/validate-filename.py",
|
|
1680
|
+
"name": "ARC Filename Validator",
|
|
1681
|
+
"timeout": 5000,
|
|
1682
|
+
"description": "Validate ARC-xxx filename convention",
|
|
1683
|
+
}
|
|
1684
|
+
],
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
"matcher": "write_file|edit_file",
|
|
1688
|
+
"hooks": [
|
|
1689
|
+
{
|
|
1690
|
+
"type": "command",
|
|
1691
|
+
"command": "python3 ${extensionPath}/hooks/scripts/file-protection.py",
|
|
1692
|
+
"name": "File Protection",
|
|
1693
|
+
"timeout": 5000,
|
|
1694
|
+
"description": "Protect ArcKit system files from modification",
|
|
1695
|
+
}
|
|
1696
|
+
],
|
|
1697
|
+
},
|
|
1698
|
+
],
|
|
1699
|
+
"AfterTool": [
|
|
1700
|
+
{
|
|
1701
|
+
"matcher": "write_file",
|
|
1702
|
+
"hooks": [
|
|
1703
|
+
{
|
|
1704
|
+
"type": "command",
|
|
1705
|
+
"command": "python3 ${extensionPath}/hooks/scripts/update-manifest.py",
|
|
1706
|
+
"name": "Manifest Updater",
|
|
1707
|
+
"timeout": 5000,
|
|
1708
|
+
"description": "Update manifest.json after writing project files",
|
|
1709
|
+
}
|
|
1710
|
+
]
|
|
1711
|
+
}
|
|
1712
|
+
],
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
hooks_path = os.path.join(hooks_dir, "hooks.json")
|
|
1717
|
+
with open(hooks_path, "w", encoding="utf-8") as f:
|
|
1718
|
+
json.dump(hooks_config, f, indent=2)
|
|
1719
|
+
f.write("\n")
|
|
1720
|
+
|
|
1721
|
+
print(f" Generated: {hooks_path}")
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
def generate_gemini_policies(output_dir):
|
|
1725
|
+
"""Generate policies/rules.toml for Gemini CLI extension."""
|
|
1726
|
+
policies_dir = os.path.join(output_dir, "policies")
|
|
1727
|
+
os.makedirs(policies_dir, exist_ok=True)
|
|
1728
|
+
|
|
1729
|
+
rules = '''\
|
|
1730
|
+
# ArcKit Gemini Extension Policies
|
|
1731
|
+
# Auto-generated by scripts/converter.py
|
|
1732
|
+
|
|
1733
|
+
# Protect ArcKit extension files from modification
|
|
1734
|
+
[[rules]]
|
|
1735
|
+
description = "Prevent modification of ArcKit extension system files"
|
|
1736
|
+
when = "tool_name in ['write_file', 'edit_file'] and '~/.gemini/extensions/arckit/' in tool_input.get('path', '')"
|
|
1737
|
+
decision = "deny"
|
|
1738
|
+
reason = "Cannot modify ArcKit extension files. These are managed by the extension."
|
|
1739
|
+
|
|
1740
|
+
# Warn on potential secret patterns in file content
|
|
1741
|
+
[[rules]]
|
|
1742
|
+
description = "Warn when writing files containing potential secrets"
|
|
1743
|
+
when = "tool_name == 'write_file' and any(p in tool_input.get('content', '') for p in ['PRIVATE KEY', 'password=', 'secret=', 'api_key='])"
|
|
1744
|
+
decision = "ask"
|
|
1745
|
+
reason = "File content may contain secrets. Please confirm this is intentional."
|
|
1746
|
+
'''
|
|
1747
|
+
|
|
1748
|
+
rules_path = os.path.join(policies_dir, "rules.toml")
|
|
1749
|
+
with open(rules_path, "w", encoding="utf-8") as f:
|
|
1750
|
+
f.write(rules)
|
|
1751
|
+
print(f" Generated: {rules_path}")
|
|
1752
|
+
|
|
1753
|
+
|
|
1754
|
+
def generate_copilot_agents(agents_dir, output_dir):
|
|
1755
|
+
"""Generate Copilot custom agent .agent.md files from Claude Code agents."""
|
|
1756
|
+
if not os.path.isdir(agents_dir):
|
|
1757
|
+
print(f" Skipped: {agents_dir} not found")
|
|
1758
|
+
return
|
|
1759
|
+
|
|
1760
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
1761
|
+
count = 0
|
|
1762
|
+
|
|
1763
|
+
for filename in sorted(os.listdir(agents_dir)):
|
|
1764
|
+
if not (filename.startswith("arckit-") and filename.endswith(".md")):
|
|
1765
|
+
continue
|
|
1766
|
+
|
|
1767
|
+
agent_path = os.path.join(agents_dir, filename)
|
|
1768
|
+
if is_subagent_file(agent_path):
|
|
1769
|
+
continue
|
|
1770
|
+
with open(agent_path, "r", encoding="utf-8") as f:
|
|
1771
|
+
content = f.read()
|
|
1772
|
+
|
|
1773
|
+
frontmatter, prompt = extract_frontmatter_and_prompt(content)
|
|
1774
|
+
|
|
1775
|
+
copilot_fm = {}
|
|
1776
|
+
if "name" in frontmatter:
|
|
1777
|
+
copilot_fm["name"] = frontmatter["name"]
|
|
1778
|
+
if "description" in frontmatter:
|
|
1779
|
+
desc = frontmatter["description"].strip().split("\n")[0].strip()
|
|
1780
|
+
copilot_fm["description"] = desc
|
|
1781
|
+
copilot_fm["tools"] = _copilot_tools_for_prompt(prompt)
|
|
1782
|
+
copilot_fm["user-invocable"] = False
|
|
1783
|
+
|
|
1784
|
+
prompt = prompt.replace("${CLAUDE_PLUGIN_ROOT}", ".arckit")
|
|
1785
|
+
prompt = prompt.replace(CONTEXT_HOOK_NOTE, CONTEXT_HOOK_REPLACEMENT)
|
|
1786
|
+
prompt = rewrite_user_config_placeholders(prompt)
|
|
1787
|
+
prompt = rewrite_copilot_command_invocations(prompt)
|
|
1788
|
+
|
|
1789
|
+
fm_str = yaml.dump(copilot_fm, default_flow_style=False, sort_keys=False).rstrip()
|
|
1790
|
+
out_filename = filename.replace(".md", ".agent.md")
|
|
1791
|
+
output_content = f"---\n{fm_str}\n---\n\n{prompt}\n"
|
|
1792
|
+
|
|
1793
|
+
out_path = os.path.join(output_dir, out_filename)
|
|
1794
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
1795
|
+
f.write(output_content)
|
|
1796
|
+
print(f" {out_filename}")
|
|
1797
|
+
count += 1
|
|
1798
|
+
|
|
1799
|
+
print(f" Generated {count} Copilot agent files in {output_dir}")
|
|
1800
|
+
|
|
1801
|
+
|
|
1802
|
+
def generate_copilot_instructions(output_path):
|
|
1803
|
+
"""Generate copilot-instructions.md for Copilot repos using ArcKit."""
|
|
1804
|
+
content = """\
|
|
1805
|
+
# ArcKit Enterprise Architecture Toolkit
|
|
1806
|
+
|
|
1807
|
+
This project uses ArcKit for architecture governance. Available commands
|
|
1808
|
+
are in `.github/prompts/arckit-*.prompt.md` (type `/` in Copilot Chat).
|
|
1809
|
+
|
|
1810
|
+
## Conventions
|
|
1811
|
+
|
|
1812
|
+
- All architecture artifacts go in `projects/` directories (e.g., `projects/001-project-name/`)
|
|
1813
|
+
- Use `bash .arckit/scripts/bash/create-project.sh --json` to create numbered project dirs
|
|
1814
|
+
- Use `bash .arckit/scripts/bash/generate-document-id.sh` for document IDs (e.g., ARC-001-REQ-v1.0)
|
|
1815
|
+
- Templates are in `.arckit/templates/` (custom overrides in `.arckit/templates-custom/`)
|
|
1816
|
+
- Always write large documents to files (avoid output token limits)
|
|
1817
|
+
- Show only a summary to the user after generating artifacts
|
|
1818
|
+
|
|
1819
|
+
## Document ID Format
|
|
1820
|
+
|
|
1821
|
+
`ARC-{project}-{type}-v{version}` (e.g., `ARC-001-REQ-v1.0`)
|
|
1822
|
+
|
|
1823
|
+
## Requirement ID Prefixes
|
|
1824
|
+
|
|
1825
|
+
- BR-xxx: Business Requirements
|
|
1826
|
+
- FR-xxx: Functional Requirements
|
|
1827
|
+
- NFR-xxx: Non-Functional Requirements (NFR-P-xxx Performance, NFR-SEC-xxx Security)
|
|
1828
|
+
- INT-xxx: Integration Requirements
|
|
1829
|
+
- DR-xxx: Data Requirements
|
|
1830
|
+
|
|
1831
|
+
## Project Structure
|
|
1832
|
+
|
|
1833
|
+
```text
|
|
1834
|
+
projects/
|
|
1835
|
+
├── 000-global/ # Cross-project artifacts (principles, policies)
|
|
1836
|
+
└── 001-project-name/ # Numbered project directories
|
|
1837
|
+
├── ARC-001-REQ-v1.0.md
|
|
1838
|
+
├── ARC-001-STKE-v1.0.md
|
|
1839
|
+
├── external/ # Reference documents
|
|
1840
|
+
└── vendors/ # Vendor evaluations
|
|
1841
|
+
```
|
|
1842
|
+
"""
|
|
1843
|
+
os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
|
|
1844
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
1845
|
+
f.write(content)
|
|
1846
|
+
print(f" Generated: {output_path}")
|
|
1847
|
+
|
|
1848
|
+
|
|
1849
|
+
if __name__ == "__main__":
|
|
1850
|
+
commands_dirs = [os.path.join(src, "commands") for src in PLUGIN_SOURCES]
|
|
1851
|
+
agents_dir = "plugins/arckit-claude/agents/"
|
|
1852
|
+
plugin_dir = "plugins/arckit-claude" # for downstream functions that only touch core
|
|
1853
|
+
|
|
1854
|
+
print(
|
|
1855
|
+
"Converting plugin commands to Codex, OpenCode, Gemini, and Copilot extension formats..."
|
|
1856
|
+
)
|
|
1857
|
+
print()
|
|
1858
|
+
print(f"Sources: {len(PLUGIN_SOURCES)} plugin dirs")
|
|
1859
|
+
for src in PLUGIN_SOURCES:
|
|
1860
|
+
cmd_count = (
|
|
1861
|
+
len([f for f in os.listdir(os.path.join(src, "commands"))
|
|
1862
|
+
if f.endswith(".md")])
|
|
1863
|
+
if os.path.isdir(os.path.join(src, "commands")) else 0
|
|
1864
|
+
)
|
|
1865
|
+
print(f" {src}: {cmd_count} commands")
|
|
1866
|
+
print(f"Agents: {agents_dir}")
|
|
1867
|
+
for config in AGENT_CONFIG.values():
|
|
1868
|
+
ext_dir = config.get("extension_dir")
|
|
1869
|
+
if ext_dir:
|
|
1870
|
+
print(f"{config['name'] + ' Ext:':14s}{ext_dir}/")
|
|
1871
|
+
print()
|
|
1872
|
+
|
|
1873
|
+
# Copy extension supporting files BEFORE convert so reference skills
|
|
1874
|
+
# are in place before command skills are generated on top
|
|
1875
|
+
print("Copying extension supporting files...")
|
|
1876
|
+
copy_extension_files(PLUGIN_SOURCES)
|
|
1877
|
+
|
|
1878
|
+
print()
|
|
1879
|
+
counts = convert(commands_dirs, agents_dir)
|
|
1880
|
+
|
|
1881
|
+
# Post-processing: copy commands and agents to extension directories
|
|
1882
|
+
for agent_id, config in AGENT_CONFIG.items():
|
|
1883
|
+
ext_dir = config.get("extension_dir")
|
|
1884
|
+
if not ext_dir:
|
|
1885
|
+
continue
|
|
1886
|
+
|
|
1887
|
+
if config.get("copy_commands_to_extension"):
|
|
1888
|
+
ext_commands_dir = os.path.join(ext_dir, "commands")
|
|
1889
|
+
os.makedirs(ext_commands_dir, exist_ok=True)
|
|
1890
|
+
src_dir = config["output_dir"]
|
|
1891
|
+
if os.path.isdir(src_dir):
|
|
1892
|
+
for filename in sorted(os.listdir(src_dir)):
|
|
1893
|
+
if filename.endswith(".md"):
|
|
1894
|
+
shutil.copy2(
|
|
1895
|
+
os.path.join(src_dir, filename),
|
|
1896
|
+
os.path.join(ext_commands_dir, filename),
|
|
1897
|
+
)
|
|
1898
|
+
print(
|
|
1899
|
+
f" Copied {counts[agent_id]} commands to {config['name']} extension: {ext_commands_dir}"
|
|
1900
|
+
)
|
|
1901
|
+
|
|
1902
|
+
if config.get("copy_agents_to_extension"):
|
|
1903
|
+
# Copy agents to local dir (sibling of output_dir) and extension dir
|
|
1904
|
+
local_agents_dir = os.path.join(
|
|
1905
|
+
os.path.dirname(config["output_dir"]), "agents"
|
|
1906
|
+
)
|
|
1907
|
+
ext_agents_dir = os.path.join(ext_dir, "agents")
|
|
1908
|
+
agent_output_dirs = {local_agents_dir, ext_agents_dir}
|
|
1909
|
+
for agent_output_dir in agent_output_dirs:
|
|
1910
|
+
if os.path.isdir(agent_output_dir):
|
|
1911
|
+
shutil.rmtree(agent_output_dir)
|
|
1912
|
+
os.makedirs(agent_output_dir, exist_ok=True)
|
|
1913
|
+
if os.path.isdir(agents_dir):
|
|
1914
|
+
for filename in sorted(os.listdir(agents_dir)):
|
|
1915
|
+
if filename.startswith("arckit-") and filename.endswith(".md"):
|
|
1916
|
+
src_agent = os.path.join(agents_dir, filename)
|
|
1917
|
+
if is_subagent_file(src_agent):
|
|
1918
|
+
continue
|
|
1919
|
+
copy_agent_stripped(
|
|
1920
|
+
src_agent,
|
|
1921
|
+
os.path.join(local_agents_dir, filename),
|
|
1922
|
+
config,
|
|
1923
|
+
)
|
|
1924
|
+
copy_agent_stripped(
|
|
1925
|
+
src_agent,
|
|
1926
|
+
os.path.join(ext_agents_dir, filename),
|
|
1927
|
+
config,
|
|
1928
|
+
)
|
|
1929
|
+
print(
|
|
1930
|
+
f" Copied agents to {local_agents_dir} and {ext_agents_dir}"
|
|
1931
|
+
)
|
|
1932
|
+
|
|
1933
|
+
print()
|
|
1934
|
+
print("Generating Codex extension config...")
|
|
1935
|
+
generate_codex_plugin_manifest("extensions/arckit-codex")
|
|
1936
|
+
generate_codex_mcp_json(
|
|
1937
|
+
os.path.join(plugin_dir, ".mcp.json"),
|
|
1938
|
+
"extensions/arckit-codex/.mcp.json",
|
|
1939
|
+
)
|
|
1940
|
+
generate_codex_config_toml(
|
|
1941
|
+
os.path.join(plugin_dir, ".mcp.json"),
|
|
1942
|
+
agents_dir,
|
|
1943
|
+
"extensions/arckit-codex/config.toml",
|
|
1944
|
+
)
|
|
1945
|
+
generate_agent_toml_files(
|
|
1946
|
+
agents_dir,
|
|
1947
|
+
"extensions/arckit-codex/agents",
|
|
1948
|
+
path_prefix=".arckit",
|
|
1949
|
+
)
|
|
1950
|
+
|
|
1951
|
+
print()
|
|
1952
|
+
print("Rewriting Codex extension skills for Codex command format...")
|
|
1953
|
+
rewrite_codex_skills("extensions/arckit-codex/skills")
|
|
1954
|
+
|
|
1955
|
+
print()
|
|
1956
|
+
print("Generating Gemini CLI sub-agents...")
|
|
1957
|
+
generate_gemini_agents(agents_dir, "extensions/arckit-gemini/agents")
|
|
1958
|
+
|
|
1959
|
+
print()
|
|
1960
|
+
print("Generating Gemini extension hooks...")
|
|
1961
|
+
generate_gemini_hooks("extensions/arckit-gemini")
|
|
1962
|
+
|
|
1963
|
+
print()
|
|
1964
|
+
print("Generating Gemini extension policies...")
|
|
1965
|
+
generate_gemini_policies("extensions/arckit-gemini")
|
|
1966
|
+
|
|
1967
|
+
print()
|
|
1968
|
+
print("Generating Copilot custom agents...")
|
|
1969
|
+
generate_copilot_agents(agents_dir, "extensions/arckit-copilot/agents")
|
|
1970
|
+
|
|
1971
|
+
print()
|
|
1972
|
+
print("Generating Copilot instructions...")
|
|
1973
|
+
generate_copilot_instructions("extensions/arckit-copilot/copilot-instructions.md")
|
|
1974
|
+
|
|
1975
|
+
print()
|
|
1976
|
+
print("Generating Mistral Vibe extension config...")
|
|
1977
|
+
copy_vibe_reference_skills(
|
|
1978
|
+
os.path.join(plugin_dir, "skills"),
|
|
1979
|
+
"extensions/arckit-vibe/skills",
|
|
1980
|
+
)
|
|
1981
|
+
vibe_version = "0.0.0"
|
|
1982
|
+
vibe_version_path = "extensions/arckit-vibe/VERSION"
|
|
1983
|
+
if os.path.isfile(vibe_version_path):
|
|
1984
|
+
with open(vibe_version_path, "r", encoding="utf-8") as f:
|
|
1985
|
+
vibe_version = f.read().strip() or vibe_version
|
|
1986
|
+
vibe_agent_files = generate_vibe_agent_toml_files(
|
|
1987
|
+
agents_dir,
|
|
1988
|
+
"extensions/arckit-vibe/agents",
|
|
1989
|
+
version=vibe_version,
|
|
1990
|
+
)
|
|
1991
|
+
generate_vibe_config_toml(
|
|
1992
|
+
"extensions/arckit-vibe/vibe-config.toml",
|
|
1993
|
+
vibe_version,
|
|
1994
|
+
vibe_agent_files,
|
|
1995
|
+
)
|
|
1996
|
+
|
|
1997
|
+
print()
|
|
1998
|
+
total = sum(counts.values())
|
|
1999
|
+
parts = " + ".join(
|
|
2000
|
+
f"{counts[aid]} {cfg['name']}" for aid, cfg in AGENT_CONFIG.items()
|
|
2001
|
+
)
|
|
2002
|
+
print(f"Generated {parts} = {total} total files.")
|