diff --git a/plugins/agent-engineering-skills/.codex-plugin/plugin.json b/plugins/agent-engineering-skills/.codex-plugin/plugin.json index 50aa4b9c..e4563802 100644 --- a/plugins/agent-engineering-skills/.codex-plugin/plugin.json +++ b/plugins/agent-engineering-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agent-engineering-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Agent-system design, orchestration, scheduling, external-agent, and evaluation workflow skills.", "author": { "name": "Gale", diff --git a/plugins/agent-engineering-skills/pyproject.toml b/plugins/agent-engineering-skills/pyproject.toml index a1de1e88..6ed3940f 100644 --- a/plugins/agent-engineering-skills/pyproject.toml +++ b/plugins/agent-engineering-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agent-engineering-skills-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for agent-engineering-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/agent-engineering-skills/uv.lock b/plugins/agent-engineering-skills/uv.lock index ea4e16a2..34bc4ecd 100644 --- a/plugins/agent-engineering-skills/uv.lock +++ b/plugins/agent-engineering-skills/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.11" [[package]] name = "agent-engineering-skills-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/agent-portability-skills/.codex-plugin/plugin.json b/plugins/agent-portability-skills/.codex-plugin/plugin.json index 81d06a1d..9e41a04f 100644 --- a/plugins/agent-portability-skills/.codex-plugin/plugin.json +++ b/plugins/agent-portability-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agent-portability-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Maintainer skills for Socket-owned agent skill portability, Codex plugin surfaces, and host adapter guidance.", "author": { "name": "Gale", diff --git a/plugins/agent-portability-skills/pyproject.toml b/plugins/agent-portability-skills/pyproject.toml index 637e9eed..e7d1a66f 100644 --- a/plugins/agent-portability-skills/pyproject.toml +++ b/plugins/agent-portability-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agent-portability-skills-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for Agent Portability Skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/agent-portability-skills/uv.lock b/plugins/agent-portability-skills/uv.lock index 924882ad..96eda36e 100644 --- a/plugins/agent-portability-skills/uv.lock +++ b/plugins/agent-portability-skills/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "agent-portability-skills-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/agentdeck/.codex-plugin/plugin.json b/plugins/agentdeck/.codex-plugin/plugin.json index 9d34d680..1480b73e 100644 --- a/plugins/agentdeck/.codex-plugin/plugin.json +++ b/plugins/agentdeck/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentdeck", - "version": "9.29.0", + "version": "9.29.1", "description": "Local Codex runtime utilities for thread, hook, and app-server workflows.", "author": { "name": "Gale", diff --git a/plugins/android-dev-skills/.codex-plugin/plugin.json b/plugins/android-dev-skills/.codex-plugin/plugin.json index 78484ddb..e0d704d3 100644 --- a/plugins/android-dev-skills/.codex-plugin/plugin.json +++ b/plugins/android-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "android-dev-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Android, Kotlin, Java, Gradle, Android Gradle Plugin, testing, lint, UI implementation, and release-readiness workflow skills.", "author": { "name": "Gale", diff --git a/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json b/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json index 84183330..6bac5f3c 100644 --- a/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json +++ b/plugins/apple-creator-studio-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "apple-creator-studio-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Human-facing and Computer Use-aware Apple Creator Studio workflows for Final Cut Pro editing, Motion templates, Compressor delivery, Logic Pro production, MainStage concert preparation, and GarageBand projects.", "author": { "name": "Gale", diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index c348da0c..168c1e1a 100644 --- a/plugins/apple-dev-skills/.codex-plugin/plugin.json +++ b/plugins/apple-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "apple-dev-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Apple development workflows for Codex, including macOS privacy permissions, sandbox file access, entitlement diagnosis, virtualization, SwiftPM, Xcode, app extensions, media, provisioning, SwiftUI, AppKit, Safari, security, OpenAPI, and DocC.", "author": { "name": "Gale", diff --git a/plugins/apple-dev-skills/pyproject.toml b/plugins/apple-dev-skills/pyproject.toml index 397f2afc..945c43aa 100644 --- a/plugins/apple-dev-skills/pyproject.toml +++ b/plugins/apple-dev-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "apple-dev-skills-maintainer" -version = "9.29.0" +version = "9.29.1" description = "Maintainer tooling for the apple-dev-skills repository" requires-python = ">=3.10" dependencies = [] diff --git a/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/assets/AGENTS.md b/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/assets/AGENTS.md index 7d404f9f..1888e8e5 100644 --- a/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/assets/AGENTS.md +++ b/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/assets/AGENTS.md @@ -49,6 +49,7 @@ - Do not assume Xcode's Build Settings UI writes edited values back into `.xcconfig` files. If a GUI edit creates a generated project override, move intentional tracked settings into the owning `.xcconfig` before regenerating. - Prefer Swift Testing for modern unit-style tests, keep XCTest where Apple tooling or dependencies still require it, and use XCUITest with explicit element wait APIs instead of fixed sleeps. - Keep `.xctestplan` files versioned when the project depends on repeatable test-plan configurations, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- For macOS prompt-heavy UI tests, record the launcher, responsible executable, target app or helper, protected operation, and test-plan configuration before changing permissions. Keep ordinary tests on a test-owned Debug product and test-specific storage; do not use `open`, `NSWorkspace`, or a wrapper script to restore an installed app as routine test cleanup. Put a real installed-app or protected-operation scenario behind an opt-in `.xctestplan` configuration. - Prefer a checked-in repo-root `.swiftformat` file as the Swift formatting source of truth. - Prefer a pre-commit hook such as `Scripts/repo-maintenance/hooks/pre-commit.sample` that formats staged Swift sources and then verifies them with `swiftformat --lint` before commit. - Treat SwiftLint as an optional complementary signal layer for clarity, safety, and maintainability after SwiftFormat owns formatting shape. diff --git a/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/scripts/bootstrap_xcode_app_project.py b/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/scripts/bootstrap_xcode_app_project.py index 4a4bf767..29f5f8f1 100755 --- a/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/scripts/bootstrap_xcode_app_project.py +++ b/plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/scripts/bootstrap_xcode_app_project.py @@ -51,6 +51,13 @@ "Sources/Services/Provided", ) +XCODE_IGNORED_OUTPUTS = ( + "Build/", + "DerivedData/", + "xcuserdata/", + "*.xcuserstate", +) + def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description=__doc__) @@ -137,6 +144,12 @@ def install_standard_directories(target_dir: Path) -> list[str]: return installed_paths +def install_default_gitignore(target_dir: Path) -> str: + gitignore_path = target_dir / ".gitignore" + write_text(gitignore_path, "\n".join(XCODE_IGNORED_OUTPUTS) + "\n") + return str(gitignore_path) + + def install_local_environment(target_dir: Path, scheme_name: str) -> str: template_path = ( Path(__file__).resolve().parents[3] @@ -283,6 +296,7 @@ def main() -> int: target_dir.mkdir(parents=True, exist_ok=True) standard_directory_paths = install_standard_directories(target_dir) + gitignore_path = install_default_gitignore(target_dir) try: xcodegen_template_paths = install_xcodegen_templates( @@ -438,6 +452,7 @@ def main() -> int: "xcodegen_template_paths": xcodegen_template_paths, "string_catalog_path": str(target_dir / "Sources/Resources/Localizable.xcstrings"), "standard_directory_paths": standard_directory_paths, + "gitignore_path": gitignore_path, "local_environment_path": local_environment_path, "agents_copied": agents_copied, "stdout": proc_install_toolkit.stdout + proc_generate.stdout + validation_stdout, diff --git a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md index c8b1e681..124e9cc9 100644 --- a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md +++ b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md @@ -7,7 +7,7 @@ description: Sync repo guidance for one existing native Apple app project manage ## Purpose -Bring an existing Xcode app repository up to the expected guidance baseline without overloading the main Xcode execution skill. This skill owns repo-guidance alignment for existing Apple app repos, including deterministic `AGENTS.md` creation or bounded section append behavior, and runs `maintain-project-repo` with the `xcode-app` profile alongside that guidance. `scripts/run_workflow.py` is the runtime entrypoint, and `scripts/sync_xcode_project_guidance.py` applies the current sync behavior. +Bring an existing Xcode app repository up to the expected guidance baseline without overloading the main Xcode execution skill. This skill owns repo-guidance alignment for existing Apple app repos, including deterministic `AGENTS.md` creation or bounded section append behavior, migration-safe `.gitignore` output rules, and `maintain-project-repo` refresh with the `xcode-app` profile. It creates a missing `.gitignore` with `Build/`, `DerivedData/`, `xcuserdata/`, and `*.xcuserstate`, or appends only missing entries while preserving existing comments, ordering, and user-owned rules. `scripts/run_workflow.py` is the runtime entrypoint, and `scripts/sync_xcode_project_guidance.py` applies the current sync behavior. ## Companion Plugin Requirement @@ -67,6 +67,7 @@ This skill can be discovered from a standalone `apple-dev-skills` install, but i - if `AGENTS.md` is missing, copy `assets/AGENTS.md` - if `AGENTS.md` exists and already contains the managed section, keep the file unchanged - if `AGENTS.md` exists but lacks the managed section, append `assets/append-section.md` as a bounded section + - if `.gitignore` is missing, create it with the four standard Xcode output rules; if it already exists, append only missing rules without rewriting existing content 7. Validate the synced repo guidance: - verify `AGENTS.md` exists - verify the synced file mentions `xcode-build-run-workflow` and `xcode-testing-workflow` diff --git a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/AGENTS.md b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/AGENTS.md index a239e5a4..2b37f1a5 100644 --- a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/AGENTS.md +++ b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/AGENTS.md @@ -53,6 +53,7 @@ - After regenerating an XcodeGen project, review the spec diff, `.xcconfig` diff, and generated `.xcodeproj` diff, then validate the affected scheme with explicit `xcodebuild` commands. - Prefer Swift Testing for modern unit-style tests, keep XCTest where Apple tooling or dependencies still require it, and use XCUITest with explicit element wait APIs instead of fixed sleeps. - Keep `.xctestplan` files versioned when the project depends on repeatable test-plan configurations, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- For macOS prompt-heavy UI tests, record the launcher, responsible executable, target app or helper, protected operation, and test-plan configuration before changing permissions. Keep ordinary tests on a test-owned Debug product and test-specific storage; do not use `open`, `NSWorkspace`, or a wrapper script to restore an installed app as routine test cleanup. Put a real installed-app or protected-operation scenario behind an opt-in `.xctestplan` configuration. - Prefer normal Xcode and XCTest parallel execution for ordinary Swift Testing, XCTest, and XCUITest runs when the project, scheme, destination, and test plan support it. Do not serialize regular tests just because they use Swift, XCTest, async tests, UI automation, or `.xctestplan` matrices. - Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time, and call `unload_models` on Gale's live TTS service before the heavy run and `reload_models` after it ends, even when the run fails or is interrupted. - Prefer a checked-in repo-root `.swiftformat` file as the Swift formatting source of truth. diff --git a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/append-section.md b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/append-section.md index f394b4f1..12c1035d 100644 --- a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/append-section.md +++ b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/assets/append-section.md @@ -52,6 +52,7 @@ - After regenerating an XcodeGen project, review the spec diff, `.xcconfig` diff, and generated `.xcodeproj` diff, then validate the affected scheme with explicit `xcodebuild` commands. - Prefer Swift Testing for modern unit-style tests, keep XCTest where Apple tooling or dependencies still require it, and use XCUITest with explicit element wait APIs instead of fixed sleeps. - Keep `.xctestplan` files versioned when the project depends on repeatable test-plan configurations, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- For macOS prompt-heavy UI tests, record the launcher, responsible executable, target app or helper, protected operation, and test-plan configuration before changing permissions. Keep ordinary tests on a test-owned Debug product and test-specific storage; do not use `open`, `NSWorkspace`, or a wrapper script to restore an installed app as routine test cleanup. Put a real installed-app or protected-operation scenario behind an opt-in `.xctestplan` configuration. - Prefer normal Xcode and XCTest parallel execution for ordinary Swift Testing, XCTest, and XCUITest runs when the project, scheme, destination, and test plan support it. Do not serialize regular tests just because they use Swift, XCTest, async tests, UI automation, or `.xctestplan` matrices. - Treat tests that load large local AI or ML models, especially models over 500 million parameters, as heavy system-resource tests. Run those tests sequentially, one at a time, and call `unload_models` on Gale's live TTS service before the heavy run and `reload_models` after it ends, even when the run fails or is interrupted. - Treat accessibility semantics and Apple UI accessibility review as a separate concern from UI automation; use `apple-ui-accessibility-workflow` for the semantic side and `xcode-testing-workflow` for runtime verification and XCUITest follow-through. diff --git a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/run_workflow.py b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/run_workflow.py index 48f9e0c5..4b6305aa 100755 --- a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/run_workflow.py +++ b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/run_workflow.py @@ -234,6 +234,14 @@ def main() -> int: else: actions.append("install .codex/environments/xcode-project.toml from template") + gitignore_path = repo_root / ".gitignore" + if gitignore_path.exists() and gitignore_path.is_file(): + actions.append("inspect .gitignore and append only missing standard Xcode output rules") + elif gitignore_path.exists(): + actions.append("report that .gitignore exists but is not a regular file") + else: + actions.append("create .gitignore with standard Xcode output rules") + if args.dry_run: payload = { "status": "success", diff --git a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/sync_xcode_project_guidance.py b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/sync_xcode_project_guidance.py index e3c730d8..85444fe3 100755 --- a/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/sync_xcode_project_guidance.py +++ b/plugins/apple-dev-skills/skills/sync-xcode-project-guidance/scripts/sync_xcode_project_guidance.py @@ -36,6 +36,13 @@ DEFAULT_STRING_CATALOG = "Sources/Resources/Localizable.xcstrings" +XCODE_IGNORED_OUTPUTS = ( + "Build/", + "DerivedData/", + "xcuserdata/", + "*.xcuserstate", +) + def version_sort_key(path: Path) -> tuple[int, ...]: parts = [] @@ -71,6 +78,36 @@ def read_asset(name: str) -> str: return (Path(__file__).resolve().parents[1] / "assets" / name).read_text(encoding="utf-8").rstrip() + "\n" +def missing_xcode_gitignore_entries(gitignore_path: Path) -> tuple[str, ...]: + if gitignore_path.exists() and not gitignore_path.is_file(): + raise RuntimeError(f"The .gitignore path exists but is not a regular file: {gitignore_path}") + if not gitignore_path.exists(): + return XCODE_IGNORED_OUTPUTS + + existing_entries = { + line.strip() + for line in gitignore_path.read_text(encoding="utf-8").splitlines() + if line.strip() and not line.lstrip().startswith("#") + } + return tuple(entry for entry in XCODE_IGNORED_OUTPUTS if entry not in existing_entries) + + +def sync_xcode_gitignore(gitignore_path: Path) -> str: + missing_entries = missing_xcode_gitignore_entries(gitignore_path) + if not missing_entries: + return "left existing .gitignore Xcode output rules unchanged" + if not gitignore_path.exists(): + gitignore_path.write_text("\n".join(missing_entries) + "\n", encoding="utf-8") + return "created .gitignore with standard Xcode output rules" + + current = gitignore_path.read_text(encoding="utf-8") + separator = "" if not current or current.endswith("\n") else "\n" + if current.strip(): + separator += "\n" + gitignore_path.write_text(current + separator + "\n".join(missing_entries) + "\n", encoding="utf-8") + return "appended missing standard Xcode output rules to .gitignore" + + def local_environment_scheme_name(detected_state: dict, workspace_path: str | None) -> str: if workspace_path: return Path(workspace_path).stem @@ -249,6 +286,7 @@ def main() -> int: args = build_parser().parse_args() repo_root = Path(args.repo_root).expanduser().resolve() agents_path = repo_root / "AGENTS.md" + gitignore_path = repo_root / ".gitignore" detected_state = discover_xcode_state(repo_root) structure_audit = audit_xcode_app_structure(repo_root) actions: list[str] = [] @@ -285,6 +323,24 @@ def main() -> int: print(json.dumps(payload, indent=2, sort_keys=True)) return 1 + try: + missing_xcode_gitignore_entries(gitignore_path) + except RuntimeError as exc: + payload = { + "status": "blocked", + "path_type": "primary", + "repo_root": str(repo_root), + "agents_path": str(agents_path), + "detected_state": detected_state, + "validation_result": None, + "structure_audit": structure_audit, + "actions": actions, + "stderr": str(exc), + "next_step": "Resolve the .gitignore path conflict and rerun sync-xcode-project-guidance.", + } + print(json.dumps(payload, indent=2, sort_keys=True)) + return 1 + if not agents_path.exists(): if not args.copy_agents_template: payload = { @@ -366,6 +422,8 @@ def main() -> int: print(json.dumps(payload, indent=2, sort_keys=True)) return 1 + actions.append(sync_xcode_gitignore(gitignore_path)) + try: runner = maintain_project_repo_runner() except RuntimeError as exc: diff --git a/plugins/apple-dev-skills/skills/xcode-testing-workflow/SKILL.md b/plugins/apple-dev-skills/skills/xcode-testing-workflow/SKILL.md index 2bb72709..23c90b0a 100644 --- a/plugins/apple-dev-skills/skills/xcode-testing-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/xcode-testing-workflow/SKILL.md @@ -46,6 +46,7 @@ Use this skill as the primary execution workflow for test-focused work in or aro - `references/xcuitest-and-xcuiautomation.md` for UI automation mechanics, waits, interruption handling, activities, and attachments - `references/ios-ui-automation-destinations.md` for iOS simulator-versus-physical-device XCUITest decisions, destination evidence, and physical-device debugging handoffs - `references/ui-accessibility-verification.md` for accessibility-specific runtime verification expectations and coordination with `apple-ui-accessibility-workflow` + - `references/macos-ui-test-permission-ownership.md` for macOS prompt attribution, test-host ownership, app launch/restore boundaries, and opt-in prompt-heavy test plans - `references/instruments-performance-profiling.md` for Instruments, `xctrace`, Time Profiler, Metal System Trace, Allocations, VM Tracker, Points of Interest, and signpost-aligned trace evidence - `references/testing-plans-file-membership-and-configurations.md` for the condensed cross-cutting summary and file-membership reminder 6. Use `references/xcodegen-project-maintenance.md` when the repo is XcodeGen-backed and the task touches generated test targets, scheme test actions, test-plan references, launch arguments, environment variables, or test bundle membership. @@ -126,6 +127,7 @@ Use this skill as the primary execution workflow for test-focused work in or aro - `references/xcuitest-and-xcuiautomation.md` - `references/ios-ui-automation-destinations.md` - `references/ui-accessibility-verification.md` +- `references/macos-ui-test-permission-ownership.md` - `references/instruments-performance-profiling.md` - `references/testing-plans-file-membership-and-configurations.md` - `references/xcodegen-project-maintenance.md` diff --git a/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/macos-ui-test-permission-ownership.md b/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/macos-ui-test-permission-ownership.md new file mode 100644 index 00000000..b5cc4bd9 --- /dev/null +++ b/plugins/apple-dev-skills/skills/xcode-testing-workflow/references/macos-ui-test-permission-ownership.md @@ -0,0 +1,37 @@ +# macOS UI-Test Permission Ownership + +## Purpose + +Diagnose and minimize recurring macOS privacy prompts by identifying the exact operation and responsible executable before changing test code, entitlements, or Privacy & Security settings. A build script, Xcode test host, UI-test runner, helper, Debug build product, and installed Release app are separate actors; do not infer a shared permission state from their shared source repository. + +## Attribution Record + +Before changing permissions or rerunning a prompt-heavy scenario, record: + +1. launcher: shell script, `xcodebuild`, Xcode, test plan, or another tool; +2. responsible executable: path, bundle identifier, Team ID, signing state, and build location; +3. launched or restored target: test-owned build product, installed app, helper, or external app; +4. protected operation and target resource: App Group/container data, protected folder, Accessibility, Automation, microphone, or another actual privacy class; +5. triggering API or command: `XCUIApplication.launch()`, `open`, `NSWorkspace`, helper IPC, direct file access, or another concrete operation; and +6. test configuration: test plan, environment variables, launch arguments, and whether the scenario is ordinary or opt-in prompt-heavy coverage. + +Do not treat a usage description, entitlement, sandbox capability, build flag, coverage option, result-bundle option, or a generic prompt string as proof of which executable requested access. + +## Default Test Path + +- Keep ordinary tests inside the test-owned Debug product and its test-specific storage. Prefer temporary paths or ignored repo-local artifacts; avoid Desktop, Documents, Downloads, home-directory roots, production App Groups, and user-selected folders unless the access behavior is the subject under test. +- Launch the product under test through the test framework's normal launch path. Do not use `open`, `NSWorkspace`, or a wrapper script to restore a separately installed app as routine cleanup after a test run. +- Keep protected setup and assertions in the product or helper that owns the user-facing permission. Do not make the Xcode test host perform Accessibility, Automation, or protected-data operations merely to arrange or inspect the scenario. +- Treat installation, verification, launch, termination, and restoration as distinct operations. A test that needs an installed artifact or external app is an explicit integration scenario, not a normal build/test side effect. + +## Prompt-Heavy Integration Path + +Use a dedicated, versioned `.xctestplan` configuration with an explicit environment gate for a scenario that genuinely needs a real app, helper, Accessibility, Automation, protected data, or a visible prompt. Keep it disabled from ordinary local and CI runs unless the test plan intentionally enables it. + +Before running it, state the exact visible action and expected prompt owner. After it, report the responsible executable, protected operation, test-plan configuration, observed prompt or denial, and whether the normal test path stayed prompt-free. If the operation belongs to a helper or installed product, test it through that product boundary rather than granting broad authority to Xcode, the terminal, or an agent host. + +## Escalation Boundary + +Use `macos-privacy-permissions-workflow` when the responsible executable, privacy class, signed artifact, or user-consent state is unclear. Use `diagnose-apple-entitlements` when tracked entitlements, embedded profiles, final signed code, and runtime behavior disagree. + +Do not reset permissions, automate System Settings, edit TCC state, grant Full Disk Access, or add a stable testing helper merely because ordinary test scripts launch or restore the wrong app. First remove that accidental launch path and prove whether a protected operation remains. diff --git a/plugins/apple-dev-skills/tests/test_xcode_app_bootstrap_workflow.py b/plugins/apple-dev-skills/tests/test_xcode_app_bootstrap_workflow.py index cb6695cd..f6388205 100644 --- a/plugins/apple-dev-skills/tests/test_xcode_app_bootstrap_workflow.py +++ b/plugins/apple-dev-skills/tests/test_xcode_app_bootstrap_workflow.py @@ -201,6 +201,12 @@ def test_xcodegen_path_can_succeed_with_fake_tools(self) -> None: self.assertEqual(payload["status"], "success") target = Path(payload["resolved_path"]) self.assertTrue((target / "project.yml").exists()) + gitignore_path = target / ".gitignore" + self.assertEqual( + gitignore_path.read_text(encoding="utf-8"), + "Build/\nDerivedData/\nxcuserdata/\n*.xcuserstate\n", + ) + self.assertEqual(payload["gitignore_path"], str(gitignore_path)) project_yml = (target / "project.yml").read_text(encoding="utf-8") self.assertIn("minimumXcodeGenVersion: 2.46.0", project_yml) self.assertIn("projectFormat: xcode16_0", project_yml) diff --git a/plugins/apple-dev-skills/tests/test_xcode_guidance_sync_workflow.py b/plugins/apple-dev-skills/tests/test_xcode_guidance_sync_workflow.py index 77745ad8..8efec4e2 100644 --- a/plugins/apple-dev-skills/tests/test_xcode_guidance_sync_workflow.py +++ b/plugins/apple-dev-skills/tests/test_xcode_guidance_sync_workflow.py @@ -57,6 +57,7 @@ def test_dry_run_plans_agents_creation(self) -> None: self.assertEqual(payload["status"], "success") self.assertEqual(payload["path_type"], "fallback") self.assertIn("create AGENTS.md from assets/AGENTS.md", payload["actions"]) + self.assertIn("create .gitignore with standard Xcode output rules", payload["actions"]) def test_sync_creates_agents_template(self) -> None: with tempfile.TemporaryDirectory() as tmpdir: @@ -70,6 +71,8 @@ def test_sync_creates_agents_template(self) -> None: self.assertIn("apple-ui-accessibility-workflow", agents_text) self.assertIn("sync-xcode-project-guidance", agents_text) self.assertIn(".xctestplan", agents_text) + self.assertIn("macOS prompt-heavy UI tests", agents_text) + self.assertIn("do not use `open`, `NSWorkspace`, or a wrapper script to restore an installed app", agents_text) self.assertIn("semantic side and `xcode-testing-workflow` for runtime verification", agents_text) self.assertIn("project membership, target membership, build phases, and resource inclusion", agents_text) self.assertIn("Localizable.xcstrings", agents_text) @@ -97,6 +100,11 @@ def test_sync_creates_agents_template(self) -> None: any(finding["path"] == "Sources/Views/Shared" for finding in payload["structure_audit"]["findings"]) ) self.assertTrue(Path(tmpdir, ".swiftformat").is_file()) + self.assertEqual( + Path(tmpdir, ".gitignore").read_text(encoding="utf-8"), + "Build/\nDerivedData/\nxcuserdata/\n*.xcuserstate\n", + ) + self.assertIn("created .gitignore with standard Xcode output rules", payload["actions"]) self.assertTrue(Path(tmpdir, "Scripts/repo-maintenance/hooks/pre-commit.sample").is_file()) self.assertTrue(Path(tmpdir, "Scripts/repo-maintenance/validate-all.sh").is_file()) self.assertTrue(Path(tmpdir, "Scripts/repo-maintenance/config/profile.env").is_file()) @@ -131,6 +139,8 @@ def test_sync_appends_section_to_existing_agents(self) -> None: self.assertIn("## Apple / Xcode Project Workflow", agents_text) self.assertIn("apple-ui-accessibility-workflow", agents_text) self.assertIn(".xctestplan", agents_text) + self.assertIn("macOS prompt-heavy UI tests", agents_text) + self.assertIn("do not use `open`, `NSWorkspace`, or a wrapper script to restore an installed app", agents_text) self.assertIn("semantic side and `xcode-testing-workflow` for runtime verification", agents_text) self.assertIn("project membership, target membership, build phases, and resource inclusion", agents_text) self.assertIn("Localizable.xcstrings", agents_text) @@ -174,6 +184,26 @@ def test_sync_preserves_existing_local_environment(self) -> None: payload["actions"], ) + def test_sync_appends_only_missing_xcode_gitignore_rules(self) -> None: + with tempfile.TemporaryDirectory() as tmpdir: + repo_root = Path(tmpdir) + (repo_root / "Demo.xcodeproj").mkdir() + gitignore_path = repo_root / ".gitignore" + gitignore_path.write_text( + "# Keep user rules in this order.\nCustomOutput/\nDerivedData/\n", + encoding="utf-8", + ) + + code, payload = self.run_script("--repo-root", tmpdir) + + self.assertEqual(code, 0) + self.assertEqual(payload["status"], "success") + self.assertEqual( + gitignore_path.read_text(encoding="utf-8"), + "# Keep user rules in this order.\nCustomOutput/\nDerivedData/\n\nBuild/\nxcuserdata/\n*.xcuserstate\n", + ) + self.assertIn("appended missing standard Xcode output rules to .gitignore", payload["actions"]) + def test_write_mode_can_disable_append_behavior(self) -> None: with tempfile.TemporaryDirectory() as tmpdir: Path(tmpdir, "Demo.xcodeproj").mkdir() diff --git a/plugins/apple-dev-skills/tests/test_xcode_testing_workflow.py b/plugins/apple-dev-skills/tests/test_xcode_testing_workflow.py index b976059c..602b7995 100644 --- a/plugins/apple-dev-skills/tests/test_xcode_testing_workflow.py +++ b/plugins/apple-dev-skills/tests/test_xcode_testing_workflow.py @@ -107,14 +107,25 @@ def test_skill_documents_accessibility_and_ui_automation_references(self) -> Non accessibility_text = ( ROOT / "skills/xcode-testing-workflow/references/ui-accessibility-verification.md" ).read_text(encoding="utf-8") + permission_text = ( + ROOT / "skills/xcode-testing-workflow/references/macos-ui-test-permission-ownership.md" + ).read_text(encoding="utf-8") self.assertIn("xctestplan-configurations-and-matrix.md", skill_text) self.assertIn("xcuitest-and-xcuiautomation.md", skill_text) self.assertIn("ios-ui-automation-destinations.md", skill_text) self.assertIn("ui-accessibility-verification.md", skill_text) + self.assertIn("macos-ui-test-permission-ownership.md", skill_text) self.assertIn("-only-test-configuration", plan_text) self.assertIn("waitForExistence(timeout:)", ui_text) self.assertIn("apple-ui-accessibility-workflow", accessibility_text) + for term in ( + "responsible executable", + "do not use `open`, `nsworkspace`, or a wrapper script to restore a separately installed app", + "opt-in prompt-heavy", + "macos-privacy-permissions-workflow", + ): + self.assertIn(term, permission_text.lower()) def test_skill_documents_ios_simulator_and_physical_device_boundaries(self) -> None: destination_text = ( diff --git a/plugins/apple-dev-skills/uv.lock b/plugins/apple-dev-skills/uv.lock index b71567c5..edb49494 100644 --- a/plugins/apple-dev-skills/uv.lock +++ b/plugins/apple-dev-skills/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.10" [[package]] name = "apple-dev-skills-maintainer" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/cardhop-app/.codex-plugin/plugin.json b/plugins/cardhop-app/.codex-plugin/plugin.json index bdfa24db..84e3cd2f 100644 --- a/plugins/cardhop-app/.codex-plugin/plugin.json +++ b/plugins/cardhop-app/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cardhop-app", - "version": "9.29.0", + "version": "9.29.1", "description": "Cardhop.app workflow guidance plus a bundled local MCP server for contact capture and updates on macOS.", "author": { "name": "Gale", diff --git a/plugins/cardhop-app/mcp/pyproject.toml b/plugins/cardhop-app/mcp/pyproject.toml index beedc562..824d27e2 100644 --- a/plugins/cardhop-app/mcp/pyproject.toml +++ b/plugins/cardhop-app/mcp/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cardhop-app-mcp" -version = "9.29.0" +version = "9.29.1" requires-python = ">=3.13" dependencies = [ "fastmcp>=3.0.2", diff --git a/plugins/cardhop-app/mcp/uv.lock b/plugins/cardhop-app/mcp/uv.lock index 69716dfd..4d6e08ca 100644 --- a/plugins/cardhop-app/mcp/uv.lock +++ b/plugins/cardhop-app/mcp/uv.lock @@ -141,7 +141,7 @@ wheels = [ [[package]] name = "cardhop-app-mcp" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/cloud-deployment-skills/.codex-plugin/plugin.json b/plugins/cloud-deployment-skills/.codex-plugin/plugin.json index 90a5d5fa..7a8fecfb 100644 --- a/plugins/cloud-deployment-skills/.codex-plugin/plugin.json +++ b/plugins/cloud-deployment-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cloud-deployment-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for routing cloud deployment work through official provider plugins, MCP servers, CLIs, and a reusable Dockerized-service release and deployment contract.", "author": { "name": "Gale", diff --git a/plugins/cloud-deployment-skills/skills/dockerized-service-release-deployment-workflow/SKILL.md b/plugins/cloud-deployment-skills/skills/dockerized-service-release-deployment-workflow/SKILL.md index 2c8eb05b..8ab3eea9 100644 --- a/plugins/cloud-deployment-skills/skills/dockerized-service-release-deployment-workflow/SKILL.md +++ b/plugins/cloud-deployment-skills/skills/dockerized-service-release-deployment-workflow/SKILL.md @@ -51,6 +51,14 @@ Inspect the repository's Dockerfile, CI workflows, release process, registry set Translate those sources into the actual project choices: registry, tag policy, environment policy, provider identity, health URL, and rollback command. +## Build Ownership Preflight + +Before starting an image build, record the deployment target's architecture, operating system, available memory, disk capacity, container runtime, and any provider constraints. Select the OCI platform from that evidence. For example, an Apple-silicon developer machine targeting an x86-64 Linux host builds `linux/amd64`; do not let the developer machine's architecture choose the release artifact by accident. + +Build release images in a clean CI checkout by default. A developer machine may run a bounded local image check when the user requested it and the target platform is already known, but a production host must only pull or load a finished immutable image and run it. Do not clone application source, resolve dependencies, compile Swift, or run `docker build` on a small production VPS unless the user explicitly directs that exceptional path. + +One build owns its Docker client session until it exits. Preserve the original progress-producing shell or durable log stream; do not replace it with blind polling. While that build is active, do not run Docker status, image-inspection, build-history, Buildx, Compose, or second-build commands unless the runtime explicitly documents concurrent client access as safe. If an orchestration wrapper returns before its child exits, inspect the real process rather than trusting the wrapper result, report that the build is still active, and wait before starting another package-manager or container command. + ## Hermes Compatibility This is portable instruction-only guidance and is exported through Socket's Hermes skill tap. It does not install a GitHub App, configure registry credentials, provision a cloud account, or bundle a deployment adapter for Hermes or Codex. @@ -132,6 +140,8 @@ Before enabling the workflow: - Do not deploy or modify a cloud account while creating this reusable guidance or template set. - Do not use a worktree, developer laptop, or production host to build the image that a release deploys. +- Do not start an image build before recording the target platform and host-resource constraints; stop and correct an architecture mismatch, insufficient capacity, or interrupted owning session before a deployment mutation. +- Do not probe Docker concurrently with an active build, start a second build after an early-returning wrapper, or substitute a new shell session for the original progress-producing build owner. - Do not publish a GitHub Release from a tag that is not anchored to the protected integration branch. - Do not publish a release with the workflow `GITHUB_TOKEN` when it must trigger another workflow; use the dedicated release-publisher token. - Do not deploy an unrecognized, draft, deleted, edited, or merely-created release. Stable releases deploy only to `production`; prereleases deploy only to enabled `test`. diff --git a/plugins/cloud-inference-skills/.codex-plugin/plugin.json b/plugins/cloud-inference-skills/.codex-plugin/plugin.json index 40457942..0feffc1e 100644 --- a/plugins/cloud-inference-skills/.codex-plugin/plugin.json +++ b/plugins/cloud-inference-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cloud-inference-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Cloud AI inference workflow skills for routing model serving, training, conversion, and GPU infrastructure work across Runpod, Hugging Face, AWS, Vast.ai, CoreWeave, and similar providers.", "author": { "name": "Gale", diff --git a/plugins/codebase-understanding-skills/.codex-plugin/plugin.json b/plugins/codebase-understanding-skills/.codex-plugin/plugin.json index 84a31d22..d9a2d82b 100644 --- a/plugins/codebase-understanding-skills/.codex-plugin/plugin.json +++ b/plugins/codebase-understanding-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "codebase-understanding-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Code-path exploration, call-site tracing, and evidence-based codebase explanation skills.", "author": { "name": "Gale", diff --git a/plugins/cybersecurity-skills/.codex-plugin/plugin.json b/plugins/cybersecurity-skills/.codex-plugin/plugin.json index f82b3c17..5d701a75 100644 --- a/plugins/cybersecurity-skills/.codex-plugin/plugin.json +++ b/plugins/cybersecurity-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cybersecurity-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Defensive cybersecurity, isolated Linux and macOS analysis labs, suspicious-content and malware analysis, macOS defense, vulnerability testing, pentesting, and incident response workflows.", "skills": "./skills/", "author": { diff --git a/plugins/documentation-skills/.codex-plugin/plugin.json b/plugins/documentation-skills/.codex-plugin/plugin.json index d15d848d..e4252c10 100644 --- a/plugins/documentation-skills/.codex-plugin/plugin.json +++ b/plugins/documentation-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "documentation-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Documentation maintenance skills for README, contributor, agent, API, accessibility, architecture, and roadmap surfaces.", "author": { "name": "Gale", diff --git a/plugins/documentation-skills/pyproject.toml b/plugins/documentation-skills/pyproject.toml index 105ab1e6..59708432 100644 --- a/plugins/documentation-skills/pyproject.toml +++ b/plugins/documentation-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "documentation-skills-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for documentation-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/documentation-skills/uv.lock b/plugins/documentation-skills/uv.lock index af337cef..a109bfe9 100644 --- a/plugins/documentation-skills/uv.lock +++ b/plugins/documentation-skills/uv.lock @@ -57,7 +57,7 @@ wheels = [ [[package]] name = "documentation-skills-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/dotnet-skills/.codex-plugin/plugin.json b/plugins/dotnet-skills/.codex-plugin/plugin.json index 05536e79..5c14bcb9 100644 --- a/plugins/dotnet-skills/.codex-plugin/plugin.json +++ b/plugins/dotnet-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "dotnet-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for choosing, bootstrapping, building, testing, packaging, diagnosing, and maintaining .NET projects, including F# web applications, with F# and C# as equal first-party languages.", "author": { "name": "Gale", diff --git a/plugins/game-dev-skills/.codex-plugin/plugin.json b/plugins/game-dev-skills/.codex-plugin/plugin.json index 323b93b1..0263e652 100644 --- a/plugins/game-dev-skills/.codex-plugin/plugin.json +++ b/plugins/game-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "game-dev-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Apple platform game development workflow skills for native Metal rendering, Game Porting Toolkit routing, MetalFX, GPU asset streaming, neural rendering, frameworks, input, haptics, and profiling.", "author": { "name": "Gale", diff --git a/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json b/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json index ed0c48ef..dd0dff29 100644 --- a/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json +++ b/plugins/messaging-collaboration-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "messaging-collaboration-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex workflows for chat apps, bots, collaboration, iMessage, Apple notifications and Push to Talk, VoIP, and default communication-app planning.", "author": { "name": "Gale", diff --git a/plugins/model-lab-skills/.codex-plugin/plugin.json b/plugins/model-lab-skills/.codex-plugin/plugin.json index 10a3795a..6fd478c8 100644 --- a/plugins/model-lab-skills/.codex-plugin/plugin.json +++ b/plugins/model-lab-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "model-lab-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Reproducible model training, evaluation, intervention, and runtime research workflows.", "author": { "name": "Gale" diff --git a/plugins/network-protocol-skills/.codex-plugin/plugin.json b/plugins/network-protocol-skills/.codex-plugin/plugin.json index 2f0a947f..0910e18e 100644 --- a/plugins/network-protocol-skills/.codex-plugin/plugin.json +++ b/plugins/network-protocol-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "network-protocol-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for choosing, planning, implementing, and diagnosing modern application transports and real-time networking protocols, including QUIC, HTTP/3, WebRTC, Media over QUIC, WebTransport-adjacent handoffs, protocol maturity checks, and stack-specific implementation routing.", "author": { "name": "Gale", diff --git a/plugins/professional-skills/.codex-plugin/plugin.json b/plugins/professional-skills/.codex-plugin/plugin.json index 782edfc5..16934476 100644 --- a/plugins/professional-skills/.codex-plugin/plugin.json +++ b/plugins/professional-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "professional-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Professional workflow skills for job search, career materials, and external professional services.", "author": { "name": "Gale", diff --git a/plugins/professional-skills/pyproject.toml b/plugins/professional-skills/pyproject.toml index b6a782ed..cdf0d5a9 100644 --- a/plugins/professional-skills/pyproject.toml +++ b/plugins/professional-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "professional-skills-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for professional-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/professional-skills/uv.lock b/plugins/professional-skills/uv.lock index 2be43832..0967ccb4 100644 --- a/plugins/professional-skills/uv.lock +++ b/plugins/professional-skills/uv.lock @@ -40,7 +40,7 @@ wheels = [ [[package]] name = "professional-skills-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/python-skills/.codex-plugin/plugin.json b/plugins/python-skills/.codex-plugin/plugin.json index 3ba542e2..13262f00 100644 --- a/plugins/python-skills/.codex-plugin/plugin.json +++ b/plugins/python-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "python-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Bundled Python-focused Codex skills for uv bootstrapping, project implementation, diagnostics, packaging, tooling, CI, upgrades, FastAPI service maintenance, FastMCP service maintenance, and testing workflows.", "author": { "name": "Gale", diff --git a/plugins/python-skills/pyproject.toml b/plugins/python-skills/pyproject.toml index 1b1b7ae0..b2e07c52 100644 --- a/plugins/python-skills/pyproject.toml +++ b/plugins/python-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "python-skills-maintainer" -version = "9.29.0" +version = "9.29.1" description = "Maintainer tooling for the python-skills repository" requires-python = ">=3.11" dependencies = [] diff --git a/plugins/python-skills/uv.lock b/plugins/python-skills/uv.lock index 314b1d14..7eb3b223 100644 --- a/plugins/python-skills/uv.lock +++ b/plugins/python-skills/uv.lock @@ -251,7 +251,7 @@ wheels = [ [[package]] name = "python-skills-maintainer" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/repository-skills/.codex-plugin/plugin.json b/plugins/repository-skills/.codex-plugin/plugin.json index 2beb1f65..01d05614 100644 --- a/plugins/repository-skills/.codex-plugin/plugin.json +++ b/plugins/repository-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "repository-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Repository operations, GitHub settings, worktree, validation, and release workflow skills.", "author": { "name": "Gale", diff --git a/plugins/repository-skills/pyproject.toml b/plugins/repository-skills/pyproject.toml index 921cbbd3..7f502e82 100644 --- a/plugins/repository-skills/pyproject.toml +++ b/plugins/repository-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "repository-skills-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for repository-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/repository-skills/uv.lock b/plugins/repository-skills/uv.lock index bb730a33..6b633581 100644 --- a/plugins/repository-skills/uv.lock +++ b/plugins/repository-skills/uv.lock @@ -310,7 +310,7 @@ wheels = [ [[package]] name = "repository-skills-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/reverse-engineering-skills/.codex-plugin/plugin.json b/plugins/reverse-engineering-skills/.codex-plugin/plugin.json index 70f46ea3..0a0d355d 100644 --- a/plugins/reverse-engineering-skills/.codex-plugin/plugin.json +++ b/plugins/reverse-engineering-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "reverse-engineering-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Workflow skills for reverse engineering, decompilation, disassembly, symbols, artifact analysis, and exact-build macOS security-control research.", "skills": "./skills/", "author": { diff --git a/plugins/rust-skills/.codex-plugin/plugin.json b/plugins/rust-skills/.codex-plugin/plugin.json index d6e4ab81..11594369 100644 --- a/plugins/rust-skills/.codex-plugin/plugin.json +++ b/plugins/rust-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "rust-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Rust, Cargo, rustup, crate, workspace, CLI, library, package, CI, testing, linting, and formatting workflow skills.", "skills": "./skills/", "author": { diff --git a/plugins/server-side-jvm/.codex-plugin/plugin.json b/plugins/server-side-jvm/.codex-plugin/plugin.json index 43b67349..7066e834 100644 --- a/plugins/server-side-jvm/.codex-plugin/plugin.json +++ b/plugins/server-side-jvm/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "server-side-jvm", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for choosing, building, testing, and maintaining server-side JVM backend projects with Java and Scala as equal first-party languages and future Clojure support planned.", "author": { "name": "Gale", diff --git a/plugins/server-side-swift/.codex-plugin/plugin.json b/plugins/server-side-swift/.codex-plugin/plugin.json index faa6e7b5..6cf1c969 100644 --- a/plugins/server-side-swift/.codex-plugin/plugin.json +++ b/plugins/server-side-swift/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "server-side-swift", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for bootstrapping, syncing, building, running, containerizing, deploying, and maintaining server-side Swift services, including Vapor, Leaf-rendered web and HTML email, Hummingbird, hb, persistence, Swift OpenAPI, RPC-fit decisions, SwiftNIO, observability, auth, app sync, Docker, Apple Containerization, Fly.io, and SwiftPM-first workflows.", "author": { "name": "Gale", diff --git a/plugins/server-side-swift/skills/bootstrap-hummingbird-service/SKILL.md b/plugins/server-side-swift/skills/bootstrap-hummingbird-service/SKILL.md index ffbae6c4..3b23810e 100644 --- a/plugins/server-side-swift/skills/bootstrap-hummingbird-service/SKILL.md +++ b/plugins/server-side-swift/skills/bootstrap-hummingbird-service/SKILL.md @@ -62,7 +62,7 @@ Use SwiftPM and Swift.org documentation for package, toolchain, and Linux behavi - `swift` - `git` - `hb` - - Docker-compatible runtime only when Compose validation is requested + - Docker-compatible runtime only when Compose validation is requested; if the requested validation needs an installed runtime that is stopped, announce and start that existing runtime rather than treating it as a permission boundary 3. Create the service with the official CLI: ```bash hb init @@ -107,6 +107,7 @@ Use SwiftPM and Swift.org documentation for package, toolchain, and Linux behavi - optional `docker compose up -d postgres` - optional migration command only after the app's migration command is known and safe - optional `swift run ` or `hb watch` only when runtime startup validation is requested + - before each additional SwiftPM, Docker, Compose, or package-manager command, confirm that the prior child process has exited; an early-returning wrapper is not proof that its build has finished 12. Return the created path, exact commands, selected CLI answers, config source, generated package shape, database defaults when present, validation results, and next handoff. ## Defaults diff --git a/plugins/server-side-swift/skills/bootstrap-hummingbird-service/assets/AGENTS.md b/plugins/server-side-swift/skills/bootstrap-hummingbird-service/assets/AGENTS.md index 2a1ec749..224c2bb9 100644 --- a/plugins/server-side-swift/skills/bootstrap-hummingbird-service/assets/AGENTS.md +++ b/plugins/server-side-swift/skills/bootstrap-hummingbird-service/assets/AGENTS.md @@ -38,6 +38,8 @@ swift run Use `hb watch` only for local rebuild-and-run development. Use Docker Compose PostgreSQL commands only when this repository includes local database support. +Before starting a SwiftPM, Docker, Compose, or package-manager command, confirm that any earlier child build process has exited; a wrapper returning is not proof that its spawned build finished. If requested Compose validation needs an installed Docker-compatible runtime that is stopped, announce and start that existing runtime rather than installing a replacement or treating its stopped state as a permission boundary. Keep one build session as the Docker client owner until it exits; do not run Docker probes or a second build concurrently. + ## Configuration And Secrets - Keep host, port, log level, database URL, migration behavior, and testing toggles in the Hummingbird configuration path. diff --git a/plugins/server-side-swift/skills/bootstrap-vapor-service/SKILL.md b/plugins/server-side-swift/skills/bootstrap-vapor-service/SKILL.md index a5c4fa42..566080e9 100644 --- a/plugins/server-side-swift/skills/bootstrap-vapor-service/SKILL.md +++ b/plugins/server-side-swift/skills/bootstrap-vapor-service/SKILL.md @@ -57,7 +57,7 @@ Use SwiftPM and Swift.org documentation for package, toolchain, and Linux behavi - `swift` - `git` - `vapor` - - Docker-compatible runtime only when Compose validation is requested + - Docker-compatible runtime only when Compose validation is requested; if the requested validation needs an installed runtime that is stopped, announce and start that existing runtime rather than treating it as a permission boundary 3. Create the service with the official CLI: ```bash vapor new @@ -99,6 +99,7 @@ Use SwiftPM and Swift.org documentation for package, toolchain, and Linux behavi - optional `docker compose up -d postgres` - optional `swift run App migrate` after confirming the generated database config and migration list - optional `swift run App serve` only when runtime startup validation is requested + - before each additional SwiftPM, Docker, Compose, or package-manager command, confirm that the prior child process has exited; an early-returning wrapper is not proof that its build has finished 11. Return the created path, exact commands, environment source, database defaults, validation results, and next handoff. ## Defaults diff --git a/plugins/server-side-swift/skills/bootstrap-vapor-service/assets/AGENTS.md b/plugins/server-side-swift/skills/bootstrap-vapor-service/assets/AGENTS.md index a04ba26d..ca193c6a 100644 --- a/plugins/server-side-swift/skills/bootstrap-vapor-service/assets/AGENTS.md +++ b/plugins/server-side-swift/skills/bootstrap-vapor-service/assets/AGENTS.md @@ -44,6 +44,8 @@ swift run App migrate swift run App serve ``` +Before starting a SwiftPM, Docker, Compose, or package-manager command, confirm that any earlier child build process has exited; a wrapper returning is not proof that its spawned build finished. If requested Compose validation needs an installed Docker-compatible runtime that is stopped, announce and start that existing runtime rather than installing a replacement or treating its stopped state as a permission boundary. Keep one build session as the Docker client owner until it exits; do not run Docker probes or a second build concurrently. + ## Configuration And Secrets - Use `app.environment` for environment-specific app setup. diff --git a/plugins/server-side-swift/skills/docker-workflow/SKILL.md b/plugins/server-side-swift/skills/docker-workflow/SKILL.md index e1e2689c..956132d5 100644 --- a/plugins/server-side-swift/skills/docker-workflow/SKILL.md +++ b/plugins/server-side-swift/skills/docker-workflow/SKILL.md @@ -73,6 +73,14 @@ Use `cloud-deployment-skills:dockerized-service-release-deployment-workflow` whe 7. Check runtime safety before treating an image as production-ready. 8. Validate the image with the narrowest useful build, test, run, or HTTP check. +## Runtime And Build-Session Policy + +Before a Docker or Compose command, inspect the configured Docker-compatible runtime and the deployment target platform. When the requested local workflow requires an installed runtime that is stopped, start that existing runtime as a normal implementation step after announcing the resource-intensive action; do not misclassify its stopped state as a permission boundary or silently install a replacement runtime. + +Treat the actual child build process as the source of truth. A wrapper, editor task, or orchestration command returning does not prove its spawned SwiftPM, Docker, Compose, or package-manager process has exited. Before another build, test, package, or package-manager command, confirm the prior child process is finished. If it remains active, report the owning command and wait; do not start a duplicate invocation against the same `.build` directory or Docker runtime. + +While Docker is building an image, preserve the original progress-producing session. Do not issue Docker status, image-inspection, Buildx, Compose, or second-build commands concurrently unless the runtime explicitly documents that client access as safe. If the progress session is lost, first determine whether the process is still alive without using Docker; do not begin another build. + ## Dockerfile Shape For production server-side Swift images: diff --git a/plugins/spotify/.codex-plugin/plugin.json b/plugins/spotify/.codex-plugin/plugin.json index d6b579bd..657930ab 100644 --- a/plugins/spotify/.codex-plugin/plugin.json +++ b/plugins/spotify/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "spotify", - "version": "9.29.0", + "version": "9.29.1", "description": "Placeholder plugin repository for future Spotify-focused Codex workflows.", "author": { "name": "Gale", diff --git a/plugins/swift-lang/.codex-plugin/plugin.json b/plugins/swift-lang/.codex-plugin/plugin.json index 77bbc76c..32edad53 100644 --- a/plugins/swift-lang/.codex-plugin/plugin.json +++ b/plugins/swift-lang/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "swift-lang", - "version": "9.29.0", + "version": "9.29.1", "description": "Shared Swift language and tooling skills for API style, errors, functional pipelines, formatting, source organization, SwiftSyntax, compiler inspection, SourceKit, indexing, SourceKit-LSP, and modernization.", "skills": "./skills/", "author": { diff --git a/plugins/swiftasb-skills/.codex-plugin/plugin.json b/plugins/swiftasb-skills/.codex-plugin/plugin.json index 017c2029..ce6564c6 100644 --- a/plugins/swiftasb-skills/.codex-plugin/plugin.json +++ b/plugins/swiftasb-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "swiftasb-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for explaining SwiftASB and building SwiftUI, AppKit, and Swift package integrations on top of it.", "author": { "name": "Gale", diff --git a/plugins/things-app/.codex-plugin/plugin.json b/plugins/things-app/.codex-plugin/plugin.json index ea74ee59..14b4e389 100644 --- a/plugins/things-app/.codex-plugin/plugin.json +++ b/plugins/things-app/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "things-app", - "version": "9.29.0", + "version": "9.29.1", "description": "Things.app skills and a bundled local MCP server for reminders, planning digests, and structured task workflows.", "author": { "name": "Gale", diff --git a/plugins/things-app/mcp/pyproject.toml b/plugins/things-app/mcp/pyproject.toml index 898b7a84..f797f739 100644 --- a/plugins/things-app/mcp/pyproject.toml +++ b/plugins/things-app/mcp/pyproject.toml @@ -7,7 +7,7 @@ packages = ["app"] [project] name = "things-mcp" -version = "9.29.0" +version = "9.29.1" requires-python = ">=3.13" dependencies = [ "fastmcp>=3.0.2", diff --git a/plugins/things-app/mcp/uv.lock b/plugins/things-app/mcp/uv.lock index 7b525f05..36f1bd19 100644 --- a/plugins/things-app/mcp/uv.lock +++ b/plugins/things-app/mcp/uv.lock @@ -1244,7 +1244,7 @@ wheels = [ [[package]] name = "things-mcp" -version = "9.29.0" +version = "9.29.1" source = { editable = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/things-app/pyproject.toml b/plugins/things-app/pyproject.toml index c794afb2..1764b319 100644 --- a/plugins/things-app/pyproject.toml +++ b/plugins/things-app/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "things-app-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Maintainer-only Python tooling baseline for things-app skills and plugin packaging." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/things-app/uv.lock b/plugins/things-app/uv.lock index accf99ec..1a3a8a90 100644 --- a/plugins/things-app/uv.lock +++ b/plugins/things-app/uv.lock @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "things-app-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/web-dev-skills/.codex-plugin/plugin.json b/plugins/web-dev-skills/.codex-plugin/plugin.json index 93fe5cf3..4fb88c0a 100644 --- a/plugins/web-dev-skills/.codex-plugin/plugin.json +++ b/plugins/web-dev-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "web-dev-skills", - "version": "9.29.0", + "version": "9.29.1", "description": "Codex skills for focused web and Expo native-boundary workflows.", "author": { "name": "Gale", diff --git a/pyproject.toml b/pyproject.toml index d28e2937..4abdd209 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "socket-maintenance" -version = "9.29.0" +version = "9.29.1" description = "Root uv tooling baseline for the socket superproject." requires-python = ">=3.11" dependencies = [] diff --git a/skills/dockerized-service-release-deployment-workflow/SKILL.md b/skills/dockerized-service-release-deployment-workflow/SKILL.md index 2c8eb05b..8ab3eea9 100644 --- a/skills/dockerized-service-release-deployment-workflow/SKILL.md +++ b/skills/dockerized-service-release-deployment-workflow/SKILL.md @@ -51,6 +51,14 @@ Inspect the repository's Dockerfile, CI workflows, release process, registry set Translate those sources into the actual project choices: registry, tag policy, environment policy, provider identity, health URL, and rollback command. +## Build Ownership Preflight + +Before starting an image build, record the deployment target's architecture, operating system, available memory, disk capacity, container runtime, and any provider constraints. Select the OCI platform from that evidence. For example, an Apple-silicon developer machine targeting an x86-64 Linux host builds `linux/amd64`; do not let the developer machine's architecture choose the release artifact by accident. + +Build release images in a clean CI checkout by default. A developer machine may run a bounded local image check when the user requested it and the target platform is already known, but a production host must only pull or load a finished immutable image and run it. Do not clone application source, resolve dependencies, compile Swift, or run `docker build` on a small production VPS unless the user explicitly directs that exceptional path. + +One build owns its Docker client session until it exits. Preserve the original progress-producing shell or durable log stream; do not replace it with blind polling. While that build is active, do not run Docker status, image-inspection, build-history, Buildx, Compose, or second-build commands unless the runtime explicitly documents concurrent client access as safe. If an orchestration wrapper returns before its child exits, inspect the real process rather than trusting the wrapper result, report that the build is still active, and wait before starting another package-manager or container command. + ## Hermes Compatibility This is portable instruction-only guidance and is exported through Socket's Hermes skill tap. It does not install a GitHub App, configure registry credentials, provision a cloud account, or bundle a deployment adapter for Hermes or Codex. @@ -132,6 +140,8 @@ Before enabling the workflow: - Do not deploy or modify a cloud account while creating this reusable guidance or template set. - Do not use a worktree, developer laptop, or production host to build the image that a release deploys. +- Do not start an image build before recording the target platform and host-resource constraints; stop and correct an architecture mismatch, insufficient capacity, or interrupted owning session before a deployment mutation. +- Do not probe Docker concurrently with an active build, start a second build after an early-returning wrapper, or substitute a new shell session for the original progress-producing build owner. - Do not publish a GitHub Release from a tag that is not anchored to the protected integration branch. - Do not publish a release with the workflow `GITHUB_TOKEN` when it must trigger another workflow; use the dedicated release-publisher token. - Do not deploy an unrecognized, draft, deleted, edited, or merely-created release. Stable releases deploy only to `production`; prereleases deploy only to enabled `test`. diff --git a/tests/test_deployment_build_safety_contracts.py b/tests/test_deployment_build_safety_contracts.py new file mode 100644 index 00000000..20ac6279 --- /dev/null +++ b/tests/test_deployment_build_safety_contracts.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +from pathlib import Path + + +ROOT = Path(__file__).resolve().parent.parent + + +def text(relative: str) -> str: + return (ROOT / relative).read_text(encoding="utf-8").lower() + + +def test_release_workflow_requires_target_and_session_preflight() -> None: + contents = text( + "plugins/cloud-deployment-skills/skills/" + "dockerized-service-release-deployment-workflow/SKILL.md" + ) + for phrase in ( + "deployment target's architecture", + "build release images in a clean ci checkout by default", + "one build owns its docker client session until it exits", + "do not run docker status", + "inspect the real process rather than trusting the wrapper result", + ): + assert phrase in contents + + +def test_server_docker_workflow_serializes_real_build_processes() -> None: + contents = text("plugins/server-side-swift/skills/docker-workflow/SKILL.md") + for phrase in ( + "start that existing runtime as a normal implementation step", + "treat the actual child build process as the source of truth", + "do not start a duplicate invocation", + "do not issue docker status", + ): + assert phrase in contents + + +def test_bootstrap_guidance_preserves_runtime_and_build_ownership() -> None: + for relative in ( + "plugins/server-side-swift/skills/bootstrap-hummingbird-service/SKILL.md", + "plugins/server-side-swift/skills/bootstrap-vapor-service/SKILL.md", + "plugins/server-side-swift/skills/bootstrap-hummingbird-service/assets/AGENTS.md", + "plugins/server-side-swift/skills/bootstrap-vapor-service/assets/AGENTS.md", + ): + contents = text(relative) + assert "early-returning wrapper" in contents or "wrapper returning" in contents + assert "runtime that is stopped" in contents diff --git a/uv.lock b/uv.lock index 4cc09846..b3ccd46b 100644 --- a/uv.lock +++ b/uv.lock @@ -286,7 +286,7 @@ wheels = [ [[package]] name = "socket-maintenance" -version = "9.29.0" +version = "9.29.1" source = { virtual = "." } [package.dev-dependencies]