From 5b1f8f3a64419bb876efc9e785fb3d200b7b6f29 Mon Sep 17 00:00:00 2001 From: Gale W Date: Tue, 12 May 2026 19:16:23 -0400 Subject: [PATCH 1/4] plugin: add Safari extension control skill --- .../.codex-plugin/plugin.json | 8 +- .../.github/scripts/sync_shared_snippets.sh | 1 + .../.github/scripts/validate_repo_docs.sh | 4 +- plugins/apple-dev-skills/README.md | 4 +- plugins/apple-dev-skills/ROADMAP.md | 29 +++ .../customization-consolidation-review.md | 6 +- .../SKILL.md | 143 ++++++++++++ .../agents/openai.yaml | 4 + .../references/customization-flow.md | 30 +++ .../references/customization.template.yaml | 3 + .../references/extension-shape-decision.md | 33 +++ .../messaging-shared-data-and-permissions.md | 51 +++++ .../safari-services-control-surfaces.md | 38 ++++ .../snippets/apple-xcode-project-core.md | 97 ++++++++ .../testing-debugging-and-distribution.md | 38 ++++ .../scripts/customization_config.py | 213 ++++++++++++++++++ ...test_customization_consolidation_review.py | 4 +- .../test_customization_template_paths.py | 1 + .../test_safari_extension_control_workflow.py | 57 +++++ 19 files changed, 754 insertions(+), 10 deletions(-) create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization-flow.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization.template.yaml create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/safari-services-control-surfaces.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md create mode 100755 plugins/apple-dev-skills/skills/safari-extension-control-workflow/scripts/customization_config.py create mode 100644 plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index 18b26d13..8594ac2b 100644 --- a/plugins/apple-dev-skills/.codex-plugin/plugin.json +++ b/plugins/apple-dev-skills/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "apple-dev-skills", "version": "6.7.26", - "description": "Apple development workflows for Codex, including SwiftUI architecture and DocC authoring guidance.", + "description": "Apple development workflows for Codex, including SwiftUI architecture, Safari integration, and DocC authoring guidance.", "author": { "name": "Gale", "email": "mail@galewilliams.com", @@ -18,6 +18,7 @@ "xcode", "mcp", "swiftui", + "safari", "ios", "macos" ], @@ -25,8 +26,8 @@ "mcpServers": "./.mcp.json", "interface": { "displayName": "Apple Dev Skills", - "shortDescription": "Apple, Swift, Xcode, SwiftUI, and DocC workflows for Codex.", - "longDescription": "Bundle Apple-platform development skills for Swift, SwiftUI architecture, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", + "shortDescription": "Apple, Swift, Xcode, SwiftUI, Safari, and DocC workflows for Codex.", + "longDescription": "Bundle Apple-platform development skills for Swift, SwiftUI architecture, Safari extension and SafariServices integration, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", "developerName": "Gale", "category": "Developer Tools", "capabilities": [ @@ -36,6 +37,7 @@ "websiteURL": "https://github.com/gaelic-ghost/apple-dev-skills", "defaultPrompt": [ "Explore the relevant Apple docs first, then explain the right SwiftUI or Xcode path for this repository.", + "Choose the right Safari extension, SafariServices, messaging, content blocker, or automation fallback path for this Mac app.", "Help me build, test, or debug this Swift or Xcode project using the repo's Apple workflows.", "Write or review DocC symbol comments, articles, extension files, and landing-page structure for this Swift repository.", "Sync the Apple project guidance in this repo without hand-editing Xcode project files, using Productivity Skills when repo-maintenance files must be installed or refreshed." diff --git a/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh b/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh index 49e8a76f..3e79772e 100755 --- a/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh +++ b/plugins/apple-dev-skills/.github/scripts/sync_shared_snippets.sh @@ -33,6 +33,7 @@ sync_one \ "$ROOT_DIR/skills/bootstrap-xcode-app-project/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/format-swift-sources/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/explore-apple-swift-docs/references/snippets/apple-xcode-project-core.md" \ + "$ROOT_DIR/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/swiftui-app-architecture-workflow/references/snippets/apple-xcode-project-core.md" \ "$ROOT_DIR/skills/sync-xcode-project-guidance/references/snippets/apple-xcode-project-core.md" diff --git a/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh b/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh index 3e0e549c..df38912d 100644 --- a/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh +++ b/plugins/apple-dev-skills/.github/scripts/validate_repo_docs.sh @@ -113,6 +113,7 @@ active_skill_mds=( "./skills/swift-package-testing-workflow/SKILL.md" "./skills/swift-package-workflow/SKILL.md" "./skills/author-swift-docc-docs/SKILL.md" + "./skills/safari-extension-control-workflow/SKILL.md" "./skills/swiftui-app-architecture-workflow/SKILL.md" "./skills/apple-ui-accessibility-workflow/SKILL.md" "./skills/explore-apple-swift-docs/SKILL.md" @@ -123,7 +124,7 @@ active_skill_mds=( "./skills/sync-xcode-project-guidance/SKILL.md" "./skills/sync-swift-package-guidance/SKILL.md" ) -[[ ${#active_skill_mds[@]} -eq 16 ]] || fail "Expected exactly 16 active skills, found ${#active_skill_mds[@]}." +[[ ${#active_skill_mds[@]} -eq 17 ]] || fail "Expected exactly 17 active skills, found ${#active_skill_mds[@]}." shared_xcode_snippet="./shared/agents-snippets/apple-xcode-project-core.md" shared_package_snippet="./shared/agents-snippets/apple-swift-package-core.md" @@ -209,6 +210,7 @@ for file in \ "skills/xcode-testing-workflow/SKILL.md" \ "skills/xcode-build-run-workflow/SKILL.md" \ "skills/author-swift-docc-docs/SKILL.md" \ + "skills/safari-extension-control-workflow/SKILL.md" \ "skills/swiftui-app-architecture-workflow/SKILL.md" \ "skills/sync-swift-package-guidance/SKILL.md" \ "skills/sync-xcode-project-guidance/SKILL.md" \ diff --git a/plugins/apple-dev-skills/README.md b/plugins/apple-dev-skills/README.md index 8a646f35..5b5cfd27 100644 --- a/plugins/apple-dev-skills/README.md +++ b/plugins/apple-dev-skills/README.md @@ -1,6 +1,6 @@ # apple-dev-skills -Apple, Swift, SwiftUI, Xcode, DocC, and `Dash.app` workflows for Codex. +Apple, Swift, SwiftUI, Safari, Xcode, DocC, and `Dash.app` workflows for Codex. ![Codex plugin directory filtered to the Socket marketplace, showing Apple Dev Skills listed alongside companion plugins below a Productivity Skills suggestion.](./docs/media/codex-plugin-directory-socket-apple-dev-skills.png) @@ -57,6 +57,7 @@ Use Apple Dev Skills when an agent is helping with: - Swift and SwiftUI implementation - Xcode build, run, test, and project workflows +- Safari extension and SafariServices integration choices - Swift package bootstrap, build, and testing - Apple UI accessibility work - DocC comments, articles, and documentation catalogs @@ -116,6 +117,7 @@ uv run pytest - `bootstrap-xcode-app-project` - `explore-apple-swift-docs` - `format-swift-sources` +- `safari-extension-control-workflow` - `structure-swift-sources` - `swift-package-build-run-workflow` - `swift-package-testing-workflow` diff --git a/plugins/apple-dev-skills/ROADMAP.md b/plugins/apple-dev-skills/ROADMAP.md index 8690621a..dd7f7f6d 100644 --- a/plugins/apple-dev-skills/ROADMAP.md +++ b/plugins/apple-dev-skills/ROADMAP.md @@ -17,6 +17,7 @@ - [Milestone 39: Swift Package Index Workflow](#milestone-39-swift-package-index-workflow) - [Milestone 40: SwiftUI UI Architecture Workflow](#milestone-40-swiftui-ui-architecture-workflow) - [Milestone 41: Swift Package Extension Workflow](#milestone-41-swift-package-extension-workflow) +- [Milestone 42: Safari Extension And Control Workflow](#milestone-42-safari-extension-and-control-workflow) - [Backlog Candidates](#backlog-candidates) - [History](#history) @@ -47,6 +48,7 @@ - Milestone 39: Swift Package Index Workflow - Planned - Milestone 40: SwiftUI UI Architecture Workflow - Completed - Milestone 41: Swift Package Extension Workflow - Planned +- Milestone 42: Safari Extension And Control Workflow - Completed ## Milestone 21: Swift Cleanup Automation Exploration @@ -391,12 +393,39 @@ Planned - [ ] Bootstrap and guidance-sync outputs encode the Swift `6.3.x` / `6.2.x` support window. - [ ] The skill is covered by repo validation and targeted tests. +## Milestone 42: Safari Extension And Control Workflow + +### Status + +Completed + +### Scope + +- [x] Add a dedicated Safari workflow for choosing between Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, authentication surfaces, and external automation fallbacks. +- [x] Keep the workflow docs-first and explicit about Apple-documented Safari behavior before implementation choices. +- [x] Teach agents to treat "control Safari from a macOS app" as a scoped integration question rather than assuming unrestricted browser control. +- [x] Keep Xcode target, signing, entitlement, build, run, and testing work routed into the existing Xcode skills. + +### Tickets + +- [x] Add `safari-extension-control-workflow` with repo-standard skill metadata, OpenAI interface metadata, customization contract files, and shared Xcode policy snippet coverage. +- [x] Add references for extension-shape choice, SafariServices control surfaces, messaging and shared data, permissions, testing, debugging, and distribution. +- [x] Add targeted pytest coverage for extension-shape boundaries, supported control surfaces, messaging contexts, privacy posture, and explicit handoffs. +- [x] Update the active skill inventory, repo validator, shared-snippet sync script, README, and customization review counts. + +### Exit Criteria + +- [x] The repository ships `safari-extension-control-workflow` as the explicit owner for Safari extension and SafariServices integration-shape guidance. +- [x] The workflow keeps WebExtension, Safari App Extension, content blocker, authentication, and external automation paths distinct. +- [x] The skill is covered by repo validation and targeted tests. + ## Backlog Candidates - [ ] Record plausible future work that is not yet committed to a milestone. ## History +- Added `safari-extension-control-workflow` as the explicit owner for Safari Web Extension, Safari App Extension, SafariServices, messaging, content blocker, authentication, and external automation decision guidance. - Tightened Xcode project guidance so tracked `.pbxproj` diffs produced by Xcode, XcodeGen, or other project-aware workflows are treated as critical project state that must be reviewed, staged, and committed before push, merge, release, or cleanup. - Updated standalone install guidance so `apple-dev-skills` defaults to Codex's Git-backed marketplace add/upgrade flow without an explicit ref, documents the optional `socket` marketplace path for Gale's broader plugin set, and keeps manual local clone marketplaces as development and fallback paths. - Tightened the Swift public API guidance across shared snippets, skill-local snippet copies, and generated `AGENTS.md` templates so public call sites default to streamlined typed APIs, optional defaulted parameters over overloads, request/options structs at four or more public parameters, and enum-backed choice modeling. diff --git a/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md b/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md index 744c2411..e2901f09 100644 --- a/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md +++ b/plugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.md @@ -8,8 +8,8 @@ Record the Milestone 20 audit of the current customization system, decide whethe ## Current State Summary -- The active skill surface ships `16` separate `references/customization.template.yaml` files. -- The active skill surface ships `16` separate `scripts/customization_config.py` entrypoints. +- The active skill surface ships `17` separate `references/customization.template.yaml` files. +- The active skill surface ships `17` separate `scripts/customization_config.py` entrypoints. - Those `customization_config.py` files are functionally identical and exist only because installed skills are expected to keep runtime resources inside the skill directory. - The current templates expose `21` knobs total: - `20` are documented as `runtime-enforced` @@ -30,7 +30,7 @@ Milestone 20 audited a larger surface before the implementation pass landed. - Milestone 27 applied the approved reduction so the live surface now reflects the smaller counts in the current-state summary above. - Milestone 38 later added the narrower `author-swift-docc-docs` skill with one runtime-enforced tutorial-handling knob, which is included in the current-state counts above. - The current-state counts also include `structure-swift-sources`, which now ships runtime-enforced header-policy and split-threshold knobs for the structural-cleanup workflow. -- The current-state counts now also include the policy-only `apple-ui-accessibility-workflow` and `swiftui-app-architecture-workflow` surfaces, both of which keep the customization-file contract without introducing runtime knobs. +- The current-state counts now also include the policy-only `apple-ui-accessibility-workflow`, `safari-extension-control-workflow`, and `swiftui-app-architecture-workflow` surfaces, all of which keep the customization-file contract without introducing runtime knobs. ## Decision diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md new file mode 100644 index 00000000..b1069c96 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md @@ -0,0 +1,143 @@ +--- +name: safari-extension-control-workflow +description: Guide macOS Safari integration decisions across Safari Web Extensions, Safari App Extensions, SafariServices APIs, content blockers, extension messaging, and app-to-Safari control surfaces. Use when the user wants a Mac app to extend, message, open, inspect, or coordinate with Safari without confusing WebExtension, native extension, content blocker, authentication, or AppleScript-style automation paths. +--- + +# Safari Extension Control Workflow + +## Purpose + +Guide Safari integration work for macOS apps, with enough platform awareness to choose the right Safari extension or SafariServices surface before implementation starts. + +This skill owns the decision between Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, and limited external automation paths. It is not a generic browser-extension guide and it is not a replacement for `xcode-build-run-workflow` or `xcode-testing-workflow`. + +## When To Use + +- Use this skill when the user wants a macOS app to extend Safari, communicate with Safari content, or coordinate native app state with a Safari extension. +- Use this skill when choosing between a Safari Web Extension, Safari App Extension, Safari content blocker, `SFSafariApplication`, `SFSafariExtensionManager`, `SFSafariViewController`, `ASWebAuthenticationSession`, AppleScript, Shortcuts, or URL-opening behavior. +- Use this skill when the work involves WebExtension manifests, native messaging, app groups, injected scripts, toolbar items, content blockers, Safari profiles, temporary extension loading, unsigned extension testing, or App Store distribution. +- Use this skill when a user says they want to "control Safari" from a Mac app and the first job is distinguishing supported SafariServices control from broader GUI or scripting automation. +- Recommend `explore-apple-swift-docs` when the user primarily needs direct Apple documentation lookup rather than integration-shape guidance. +- Recommend `xcode-build-run-workflow` when the next step is target setup, build settings, entitlements, signing, file membership, running the containing app, or guarded Xcode project mutation. +- Recommend `xcode-testing-workflow` when the next step is repeatable XCTest, XCUITest, extension-state checks, or test-plan work. +- Recommend `swiftui-app-architecture-workflow` when the Safari work is settled and the remaining question is native app scene, command, focus, or settings structure. + +## Single-Path Workflow + +1. Classify the Safari integration request: + - WebExtension-compatible browser feature + - macOS-only Safari App Extension feature + - declarative content blocking + - containing app to extension messaging + - extension to webpage or injected-script messaging + - app-initiated Safari window, tab, or extension-state operation + - authentication, reading list, associated-domain, or in-app Safari content + - external automation outside SafariServices +2. Apply the Apple docs gate before recommending shape: + - read the relevant SafariServices, Safari Web Extension, Safari App Extension, App Extension, or AuthenticationServices documentation first + - state the documented behavior or platform limit being relied on + - if Apple docs and the current code disagree, stop and surface that conflict + - if no relevant Apple documentation can be found, say that explicitly before proceeding +3. Choose the supported integration surface: + - Safari Web Extension for cross-browser-style JavaScript, HTML, CSS, manifest, browser APIs, iOS, visionOS, Mac web apps, or extension portability + - Safari App Extension for macOS-only native extension behavior that uses SafariServices classes and can share data with a containing Mac app + - Content blocker when the feature is declarative blocking and does not need to inspect page content or run arbitrary page logic + - `SFSafariApplication` and related Safari App Extension proxies only for supported Safari extension interactions such as opening windows, sending app-to-extension messages, or working with Safari windows, tabs, pages, and toolbar items from the extension context + - `SFSafariExtensionManager` for extension state checks before UI or feature claims + - `ASWebAuthenticationSession` for SSO-style browser authentication rather than embedding or automating Safari + - external automation only when the user explicitly needs behavior outside SafariServices and has accepted automation, permissions, fragility, and user-visible side effects +4. Plan data flow and permissions: + - keep app, extension, and JavaScript contexts explicit + - use app groups for shared app and extension data when Apple requires a shared container + - keep message names typed or centralized in code and document payload shapes + - model profile-aware behavior when Safari profile identifiers are exposed + - avoid logging sensitive URLs, cookies, page text, tokens, or browsing history +5. Plan validation: + - verify extension visibility and enabled state before debugging feature logic + - test unsigned-extension setup separately from signed distribution setup + - validate the containing app install path, Safari Settings state, profile state, and Web Inspector or system logs when relevant + - run Xcode build, signing, entitlements, target membership, or UI validation through the Xcode skills +6. Return one recommendation path with: + - chosen Safari surface + - documented Apple behavior relied on + - native app, extension, JavaScript, and Safari ownership boundaries + - messaging and shared-data plan + - validation plan + - one handoff if the work should move into docs lookup, Xcode execution, testing, SwiftUI architecture, or external automation + +## Inputs + +- `request`: optional free-text Safari integration request. +- `platform_context`: optional emphasis such as `macos`, `ios`, `visionos`, `mac-web-app`, or `mixed-apple`. +- `extension_shape`: optional explicit shape such as `web-extension`, `app-extension`, `content-blocker`, `unknown`, or `no-extension`. +- `control_goal`: optional explicit goal such as `open-url`, `open-window`, `send-message`, `read-page-state`, `modify-page`, `block-content`, `authenticate`, or `automate-ui`. +- Defaults: + - docs-first guidance always applies + - prefer Safari Web Extensions for portable browser-extension behavior + - prefer Safari App Extensions only when the macOS-only native extension model is the real requirement + - prefer SafariServices and AuthenticationServices over GUI scripting when the documented API surface covers the job + +## Outputs + +- `status` + - `success`: the request belongs to this workflow and a Safari integration recommendation is ready + - `handoff`: the request belongs to another Apple Dev skill after Safari-aware classification + - `blocked`: the request lacks enough context or relies on unsupported Safari behavior +- `path_type` + - `primary`: the recommendation uses a documented SafariServices, Web Extension, App Extension, content blocker, or authentication path + - `fallback`: the recommendation depends on external automation because the documented Safari API surface does not cover the requested behavior +- `output` + - resolved Safari integration class + - chosen Safari surface + - documented Apple behavior relied on + - app, extension, JavaScript, and Safari ownership boundaries + - messaging and shared-data plan + - validation plan + - recommended skill or automation handoff when needed + +## Guards and Stop Conditions + +- Do not claim a Mac app can freely inspect or control arbitrary Safari windows, tabs, cookies, page content, or user browsing state unless the documented SafariServices, extension, or automation surface actually supports it. +- Do not use AppleScript, Shortcuts, UI automation, accessibility automation, or browser GUI scripting as the first recommendation when a supported SafariServices or extension path exists. +- Do not collapse Safari Web Extension native messaging, Safari App Extension injected-script messaging, and app-group shared storage into one vague "bridge"; name the exact contexts and transport. +- Do not recommend a Safari App Extension for portable WebExtension behavior unless a macOS-only native extension requirement is explicit. +- Do not recommend a Safari Web Extension for arbitrary native control of Safari outside the browser-extension permission model. +- Stop with `blocked` when the feature requires user-private Safari data or privileged browser control that Apple does not expose through the documented APIs and the user has not explicitly opted into external automation. + +## Fallbacks and Handoffs + +- Recommend `explore-apple-swift-docs` when the real need is direct Apple docs lookup for SafariServices, Web Extensions, App Extensions, AuthenticationServices, or App Extensions. +- Recommend `xcode-build-run-workflow` when the next step is creating targets, adding entitlements, wiring app groups, signing, running the containing app, or debugging build/install state. +- Recommend `xcode-testing-workflow` when the next step is repeatable test design or extension-state verification. +- Recommend `swiftui-app-architecture-workflow` when Safari integration shape is settled and the native app shell needs scene, command, focus, settings, or menu ownership guidance. +- Recommend `references/snippets/apple-xcode-project-core.md` when the user needs reusable Xcode-project policy for a repo that will own the containing app and extension targets. +- Treat external automation as a conscious fallback, not the default. When it is requested, state the user-visible permissions, fragility, and Safari-version sensitivity before implementation. + +## Customization + +Use `references/customization-flow.md`. + +`scripts/customization_config.py` exists to preserve the repo-wide customization-file contract, but the first version of this skill defines no runtime-enforced knobs. + +Keep the first release focused on the documented Safari surface decision. If future iterations add deterministic checks for manifests, entitlements, or app-group configuration, document the knobs before runtime behavior depends on them. + +## References + +### Workflow References + +- `references/extension-shape-decision.md` +- `references/safari-services-control-surfaces.md` +- `references/messaging-shared-data-and-permissions.md` +- `references/testing-debugging-and-distribution.md` +- `references/customization-flow.md` + +### Support References + +- Recommend `explore-apple-swift-docs` when the user needs current Apple docs before a Safari implementation choice. +- Recommend `xcode-build-run-workflow` when the user needs target, signing, entitlements, build, run, or install follow-through. +- Recommend `xcode-testing-workflow` when the user needs repeatable extension-state or Safari UI verification. +- Recommend `references/snippets/apple-xcode-project-core.md` when the user needs reusable Xcode project guidance for containing-app and extension-target work. + +### Script Inventory + +- `scripts/customization_config.py` diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml new file mode 100644 index 00000000..b2c2306b --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Safari Extension Control Workflow" + short_description: "Choose Safari extension and app-control paths" + default_prompt: "Use $safari-extension-control-workflow to choose the right Safari integration shape for a macOS app across Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, native messaging, app groups, extension state checks, and external automation fallbacks. Start from current Apple docs, state the documented Safari behavior or limit being relied on, then hand off to $xcode-build-run-workflow, $xcode-testing-workflow, $swiftui-app-architecture-workflow, or $explore-apple-swift-docs when the next step belongs there." diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization-flow.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization-flow.md new file mode 100644 index 00000000..d3c34554 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization-flow.md @@ -0,0 +1,30 @@ +# Safari Extension Control Workflow Customization Contract + +## Purpose + +Preserve the repo-wide customization-file contract without pretending the first version of `safari-extension-control-workflow` already has runtime-tunable behavior. + +## Knobs + +The first version defines no documented runtime-enforced knobs. + +Keep the skill stable around its docs-first Safari surface decision model before introducing persistent settings. + +## Runtime Behavior + +- `scripts/customization_config.py` exists so the skill participates cleanly in the shared repo customization surface. +- `safari-extension-control-workflow` currently ignores persisted settings at runtime because no runtime-enforced knobs are documented yet. +- Future runtime knobs should only be added after the skill proves a stable need for deterministic configuration. + +## Update Flow + +1. Inspect current settings with `scripts/customization_config.py effective`. +2. If a real runtime knob is being introduced, update `SKILL.md` and the affected references first. +3. Persist the metadata change with `scripts/customization_config.py apply --input `. +4. Re-run `scripts/customization_config.py effective` and confirm the stored values match the documented knob set. +5. Verify the skill text and any future runtime logic agree on the same contract. + +## Validation + +1. Verify the skill does not claim runtime-tunable behavior that is not actually implemented. +2. Verify future knobs are documented in both `SKILL.md` and this file before runtime behavior depends on them. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization.template.yaml b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization.template.yaml new file mode 100644 index 00000000..cddd82d1 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/customization.template.yaml @@ -0,0 +1,3 @@ +schemaVersion: 1 +isCustomized: false +settings: {} diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md new file mode 100644 index 00000000..8e18ff07 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md @@ -0,0 +1,33 @@ +# Safari Extension Shape Decision + +## Documented Anchors + +- Apple Safari Services: https://developer.apple.com/documentation/safariservices/ +- Safari Web Extensions: https://developer.apple.com/documentation/SafariServices/safari-web-extensions +- Creating a Safari Web Extension: https://developer.apple.com/documentation/safariservices/creating-a-safari-web-extension +- Safari App Extensions: https://developer.apple.com/documentation/safariservices/safari_app_extensions +- Safari app extension Info.plist keys: https://developer.apple.com/documentation/safariservices/using-safari-app-extension-default-keys +- Content blockers: https://developer.apple.com/documentation/safariservices/creating-a-content-blocker + +## Decision Rules + +- Choose a Safari Web Extension when the core behavior is browser-extension-shaped: JavaScript, HTML, CSS, a manifest, browser extension APIs, content scripts, background scripts, toolbar UI, permissions, and portability to or from Chrome, Firefox, or Edge extension formats. +- Choose a Safari App Extension when the feature is macOS-only and needs native SafariServices app-extension objects such as `SFSafariExtensionHandler`, `SFSafariApplication`, `SFSafariWindow`, `SFSafariTab`, `SFSafariPage`, or toolbar-item callbacks. +- Choose a content blocker when the feature can be expressed as declarative blocking rules. Do not upgrade a content blocker to a Web Extension or App Extension unless the feature needs messaging, content scripts, arbitrary JavaScript, app data, or native UI. +- Choose `ASWebAuthenticationSession` when the user needs browser-backed authentication or SSO. Do not frame authentication as "controlling Safari" unless Safari extension behavior is actually involved. +- Choose `SFSafariViewController` only for supported in-app Safari-style browsing contexts on platforms where Apple documents it. For macOS app control of the Safari app, use documented Safari extension or automation surfaces instead. + +## Platform Boundaries + +- Safari Web Extensions are available beyond macOS, including iOS and visionOS, and can also be used in Mac web apps on supported macOS versions. +- Safari App Extensions are macOS-only. +- Safari content blockers can be useful on iOS and macOS, but they are intentionally narrower than Web Extensions or App Extensions. +- When a user asks for one codebase across Safari and other browsers, bias toward Safari Web Extensions unless a native macOS-only requirement is central. +- When a user asks for tight integration with a Mac app and Safari windows or pages, evaluate Safari App Extensions first, then decide whether a Web Extension with native messaging is enough. + +## Anti-Patterns + +- Do not recommend Safari App Extensions only because the containing app is native. If the browser-facing behavior is portable WebExtension work, use the Web Extension model. +- Do not recommend a Safari Web Extension when the feature requires native Safari App Extension callback objects that WebExtension APIs do not expose. +- Do not treat content blockers as a privacy-invasive inspection surface; their strength is declarative matching, not page introspection. +- Do not assume the containing app can silently enable an extension. Users manage extension enablement in Safari. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md new file mode 100644 index 00000000..aa9d8ac6 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md @@ -0,0 +1,51 @@ +# Messaging, Shared Data, And Permissions + +## Documented Anchors + +- Safari Web Extension app and JavaScript messaging: https://developer.apple.com/documentation/safariservices/messaging-between-the-app-and-javascript-in-a-safari-web-extension +- Messaging a Web Extension's native app: https://developer.apple.com/documentation/safariservices/messaging-a-web-extensions-native-app +- Safari App Extension injected-script messaging: https://developer.apple.com/documentation/safariservices/passing-messages-between-safari-app-extensions-and-injected-scripts +- `SFSafariPage.dispatchMessageToScript`: https://developer.apple.com/documentation/safariservices/sfsafaripage/dispatchmessagetoscript%28withname%3Auserinfo%3A%29 +- Managing Safari Web Extension permissions: https://developer.apple.com/documentation/safariservices/managing-safari-web-extension-permissions + +## Contexts To Name Explicitly + +For every Safari integration, name the participating contexts: + +- containing macOS app +- native app extension +- WebExtension JavaScript background or service worker context +- content script or injected script +- webpage +- Safari profile or Mac web app context when relevant + +## Web Extension Messaging + +Safari Web Extension messaging is split across sandboxed parts: the app, extension, and JavaScript files. Use native messaging when JavaScript needs to communicate with the containing app, and use app groups when the app and extension need shared persisted data. + +Keep message contracts narrow: + +- centralize message names +- document payload keys and scalar types +- reject unknown message names +- return descriptive errors for missing permissions, disabled extension state, missing app group data, or unsupported pages +- avoid passing sensitive page data unless the user explicitly granted the relevant extension permission + +## Safari App Extension Messaging + +Safari App Extension messaging uses Safari-specific injected-script APIs. Injected scripts can send messages to the app extension, and the app extension can dispatch messages back to a page script through `SFSafariPage`. + +Keep the distinction clear: + +- webpage JavaScript is not the same as the injected script context +- injected scripts communicate through the `safari` namespace Apple documents for Safari App Extensions +- containing-app messages to the extension use `SFSafariApplication.dispatchMessage` +- page messages back to scripts use `SFSafariPage.dispatchMessageToScript` + +## Permission And Privacy Rules + +- Treat browsing history, cookies, tokens, page text, URLs, and profile identifiers as sensitive by default. +- Prefer least-privilege host permissions in WebExtension manifests. +- For Safari profiles, keep profile-specific state separate when Apple exposes a profile identifier. +- Keep App Group identifiers explicit and consistent across the containing app and extension. +- Do not store page content or URL history in shared containers unless the user-facing feature clearly requires it. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/safari-services-control-surfaces.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/safari-services-control-surfaces.md new file mode 100644 index 00000000..82f20748 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/safari-services-control-surfaces.md @@ -0,0 +1,38 @@ +# SafariServices Control Surfaces + +## Documented Anchors + +- `SFSafariApplication`: https://developer.apple.com/documentation/safariservices/sfsafariapplication +- `SFSafariApplication.openWindow(with:)`: https://developer.apple.com/documentation/safariservices/sfsafariapplication/openwindow%28with%3Acompletionhandler%3A%29 +- `SFSafariApplication.dispatchMessage`: https://developer.apple.com/documentation/safariservices/sfsafariapplication/dispatchmessage%28withname%3Atoextensionwithidentifier%3Auserinfo%3Acompletionhandler%3A%29 +- `SFSafariExtensionManager.getStateOfSafariExtension`: https://developer.apple.com/documentation/safariservices/sfsafariextensionmanager/getstateofsafariextension%28withidentifier%3Acompletionhandler%3A%29 +- `SFSafariExtensionState`: https://developer.apple.com/documentation/safariservices/sfsafariextensionstate +- `SFSafariWindow`: https://developer.apple.com/documentation/safariservices/sfsafariwindow + +## Supported Control Model + +SafariServices provides specific proxy objects and extension-management APIs. Treat those APIs as scoped capabilities, not as general ownership of Safari. + +- `SFSafariExtensionManager` answers whether an embedded Safari app or web extension is enabled. +- `SFSafariApplication.openWindow(with:)` can open an HTTP or HTTPS URL in a new Safari window. +- `SFSafariApplication.dispatchMessage(withName:toExtensionWithIdentifier:userInfo:)` sends a message from the containing app to its Safari App Extension and may launch the user's default Safari variant to deliver it. +- `SFSafariWindow`, `SFSafariTab`, and `SFSafariPage` are proxy objects used in Safari App Extension workflows for supported window, tab, page, and toolbar interactions. + +## Control Boundary + +- If the user wants to open a page, use `NSWorkspace` or `SFSafariApplication.openWindow(with:)` depending on whether the target is just opening a URL or coordinating with a Safari App Extension. +- If the user wants to read or modify page content, use a Safari Web Extension content script or a Safari App Extension injected script, depending on the chosen extension model. +- If the user wants to send native app state into Safari, use the documented messaging model for the chosen extension shape. +- If the user wants to enumerate or manipulate unrelated user Safari state, stop and check whether SafariServices exposes that exact behavior. If it does not, discuss external automation explicitly. + +## External Automation Fallbacks + +External automation includes AppleScript, Shortcuts, UI automation, accessibility automation, and app-specific scripting. Use it only when the user explicitly wants behavior outside documented SafariServices or extension capabilities. + +Before implementation, state: + +- the permission prompt or accessibility automation requirement +- whether the action is visible to the user +- which Safari or macOS version behavior is assumed +- what breaks if Safari is closed, has multiple profiles, uses Safari Technology Preview, or changes UI labels +- how the app will report failure in a human-readable way diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md new file mode 100644 index 00000000..c1816aaa --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/snippets/apple-xcode-project-core.md @@ -0,0 +1,97 @@ +# Apple Xcode Project Core AGENTS Snippet + +Use this snippet in repository `AGENTS.md` files when you want baseline standards for an existing native Apple app project managed through Xcode. + +## General Swift Baseline + +- For any Swift, Apple-framework, Apple-platform, SwiftUI, SwiftData, Observation, AppKit, UIKit, Foundation-on-Apple, or Xcode-related task, read the relevant Apple documentation first before planning, proposing, or making changes. +- Use Dash or Xcode-local documentation first, then official Apple documentation when local docs are insufficient. +- Before proposing an architecture or implementation, state the documented API behavior, lifecycle rule, or workflow requirement being relied on. +- Do not rely on memory, habit, or analogy as the primary source when Apple documentation exists. +- If Apple documentation and the current code disagree, stop and report the conflict before continuing. +- If no relevant Apple documentation can be found, say that explicitly before proceeding. +- Prefer the simplest correct Swift that is easiest to read, reason about, and maintain. +- Treat idiomatic Swift, Cocoa conventions, and modern Swift features as tools in service of readability, not as goals by themselves. +- Do not add ceremony, abstraction, or boilerplate just to make code look more architectural, more generic, or more "Swifty". +- Strongly prefer synthesized, implicit, and framework-provided behavior over custom code. +- Prefer synthesized conformances (`Codable`, `Equatable`, `Hashable`, etc.) whenever they satisfy the actual requirements. +- Prefer memberwise and otherwise synthesized initializers, default property values, and framework defaults over handwritten setup code. +- Do not add `CodingKeys`, manual `Codable` methods, custom initializers, wrappers, helper types, protocols, coordinators, or extra layers unless they are required by a concrete constraint or they make the final code clearly easier to understand. +- Prefer applicable existing framework or platform error types before inventing custom error wrappers or error hierarchies. +- Prefer direct, simple error flows and small focused error enums only when they materially improve understanding. +- Prefer stable, source-of-truth naming across layers when the data and meaning have not changed. +- Treat naming consistency as a reliability feature: if the same data still serves the same purpose, keep the same name. +- Do not rename fields just to match local style conventions when the external schema is already clear and stable. +- Do not use automatic case-conversion strategies such as `.convertFromSnakeCase` or `.convertToSnakeCase` unless the project explicitly wants that behavior and it clearly improves readability overall. +- When an API, cloud service, or wire format already provides clear names, preserve those names directly in Swift models and nearby code unless the meaning actually changes or a concrete collision must be resolved. +- Preserve raw wire and persistence shapes by default; do not add DTO, domain, or view-model conversion layers unless meaning actually changes or a concrete boundary requires it. +- Treat redundant wrappers, rename-and-copy layers, and duplicated logic as anti-patterns by default. +- This guidance is optimized for an advanced Swift reader and may prefer dense but readable modern Swift over beginner-style explicitness. +- Prefer explicit names that are consistent, unambiguous, and easy to scan at the call site. +- For public Swift APIs, treat streamlined, compact, ergonomic call sites as the only acceptable default; do not grow method families, overload sets, or loosely typed entry points when one clear typed API can express the operation. +- Prefer optional parameters with explicit default values over additional methods or overloads whenever the difference is optional behavior on the same operation. +- When a public function, initializer, or method reaches four or more arguments or parameters, strongly prefer a named typed `struct` request, options, or configuration value so call sites stay readable and future additions do not multiply overloads. +- Prefer enums, enum cases with associated values, and narrow typed values over strings, booleans, sentinel values, or parallel parameters whenever the domain has a closed or meaningful set of choices. +- Prefer compact syntax when it improves local reasoning, including shorthand syntax, ternary expressions, trailing closures, enums, `switch`, `map`, `filter`, `forEach`, async iteration, `AsyncSequence`, `AsyncStream`, and `AsyncAlgorithms`. +- Prefer explicit default values at initialization when they reduce optional-handling clutter and keep the code easier to follow. +- When lines, chains, or expressions get long, prefer chopping them down into a clean vertical, top-down structure with straight visual flow. +- Do not force value types by default, protocols at seams, actors by default, or other pattern slogans when a plainer concrete implementation is easier to reason about. +- Keep code compliant with Swift 6 language mode. +- Keep strict concurrency checking enabled. +- Prefer modern structured concurrency (`async`/`await`, task groups, actors) over legacy async patterns when it keeps the flow clearer and more direct. +- Make async code cancellation-aware and keep actor or task boundaries explicit instead of hiding them behind detached tasks or queue wrappers. +- Prefer clear `Sendable` boundaries for values that cross task or actor isolation, and keep unchecked sendability exceptional and justified locally. +- Prefer Swift Testing (`import Testing`) as the default test framework, and use XCTest only when a dependency or platform constraint requires it. +- Prefer Swift Testing for unit-style and package-style test surfaces in modern Xcode projects, including suites, tags, parameterized tests, and direct async tests. +- Use XCTest when the platform surface, dependency graph, or Apple tooling still expects it, and keep XCTest and Swift Testing responsibilities clearly separated when both coexist. +- Use XCUITest for UI automation, and prefer explicit element wait APIs such as `waitForExistence(timeout:)`, `waitForNonExistence(timeout:)`, and related state waits over fixed sleeps. +- Keep `.xctestplan` files versioned when test configurations, diagnostics, sanitizers, locale coverage, or selective plan execution matter, and inspect or run them explicitly with `xcodebuild -showTestPlans` and `xcodebuild -testPlan ...`. +- 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 first-party and top-tier Swift ecosystem packages from Apple, `swiftlang`, the Swift Server Work Group, and similarly trusted core Swift projects when they simplify the code and make it easier to reason about. +- Commonly approved examples include `swift-configuration` and `swift-async-algorithms` when they reduce bespoke code and improve readability. +- For Apple app projects, prefer Apple-native logging facilities first and allow Swift Logging where it makes the project API clearer. +- Prefer Swift OpenTelemetry for telemetry and instrumentation when telemetry is needed, and prefer existing ecosystem integrations over bespoke wrappers. +- Prefer a checked-in repo-root `.swiftformat` file as the default Swift formatting source of truth, and prefer a pre-commit hook 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. +- Keep automation and CI commands deterministic, non-interactive, and explicit about toolchain, platform, and configuration assumptions. + +## SwiftUI and State Architecture + +- Treat SwiftUI views as component UI: keep them small, composable, reusable, and easy to scan from top to bottom. +- Prefer straight, top-down data flow with small focused controller classes that own matching state for a view or small view cluster. +- Do not build monolithic views, monolithic controllers, or broad shared mutable state when a smaller component boundary would be clearer. +- Keep updates to view-driving state minimal and localized. +- Prefer durable identity for types that drive SwiftUI state and view updates. +- Treat `App` as the application entry and scene composition boundary, `Scene` as the container for scene-specific lifecycle and environment, and `View` as the component rendering layer. +- Use app-level lifecycle concerns at the `App` boundary, scene lifecycle concerns at the `Scene` boundary, and view-local active or presentation behavior inside views. +- Use `@Binding` to pass a focused writable piece of parent-owned state into a child view. +- Use `@Bindable` when working with an observable model that should project bindings to its mutable properties in a view. +- Prefer `@Query` for view-driven SwiftData fetching that should stay in sync with the model context; use explicit fetches only when the view should not be driven by a live query. +- Prefer environment values for shared context that truly belongs to the surrounding hierarchy, not as a dumping ground for unrelated dependencies. +- Prefer key-path-based APIs, predicates, and sort descriptors when they keep data access direct and readable. +- Extract repeated chains of view modifiers into custom view modifiers early when that reduces clutter and clearly matches a view or family of views. + +## Xcode Workspace and Project Baseline + +- Treat the `.xcworkspace` or `.xcodeproj` as the source of truth for Apple platform app integration, schemes, build settings, destinations, and target membership. +- Prefer edits through Xcode-aware project structure and keep project file changes intentional and reviewed closely. +- Use `xcodebuild` for Apple platform integration validation, including scheme, destination or SDK, and configuration-specific build or test runs. +- Keep `xcodebuild` invocations reproducible in automation by passing explicit schemes, destinations or SDKs, and configurations when relevant. +- When scripts or terminal workflows add files on disk, verify that Xcode project membership, target membership, build-phase membership, and resource-bundle inclusion all match the intended result; files appearing in the directory tree alone are not enough. +- Direct filesystem edits outside `.pbxproj` are generally safe when Xcode is closed or when the current project is not open in Xcode, but still verify that the Xcode project picks up the intended files and memberships afterward. +- Prefer Debug builds for everyday edit-build-test loops, but validate Release builds explicitly when optimization, packaging, launch behavior, watchdog timing, or deployment realism matters. +- Treat tagged releases as a signal to validate both the normal Debug path and a Release artifact path, and when shipping apps or deliverables test the Release behavior without relying on an attached debugger. +- Prefer direct filesystem edits in Xcode-managed scope only when the workflow already accounts for project-file and scheme integrity. +- Never edit `.pbxproj` files directly. If a project-file change is needed and no safe project-aware tool is available, stop and ask for an Xcode-mediated project change instead. When `.pbxproj` is tracked and Xcode, XcodeGen, or another project-aware workflow legitimately changes it, treat that diff as critical project state: review it, stage it, and commit it with the branch before any push, merge, release, or cleanup. + +## XcodeGen-Backed Project Guidance + +- If the repo contains `project.yml`, `project.yaml`, or clearly named included XcodeGen spec files, treat the XcodeGen spec set as the source of truth for generated project structure. +- For XcodeGen-backed repos, make target membership, resource membership, build settings, schemes, Swift package declarations, test plans, project references, and generation options in the XcodeGen specs instead of editing the generated `.pbxproj`. +- Before changing generated project structure, inspect the root spec plus any `include` entries so the edit lands in the owning spec rather than duplicating settings in the wrong file. +- After changing XcodeGen specs, run `xcodegen generate` from the spec root, or `xcodegen generate --spec ` when the project uses a non-default spec path. +- If the spec uses environment variables or generation hooks, preserve and document the required environment before regenerating so CI and other contributors can reproduce the project. +- Review both the spec diff and the generated `.xcodeproj` diff after regeneration. Generated `.pbxproj` changes are acceptable output when they come from XcodeGen, but they should still be reviewed for unintended target, scheme, or setting churn. +- Validate regenerated projects with explicit `xcodebuild` commands for the affected scheme, destination or SDK, and configuration. +- Do not introduce XcodeGen into an existing hand-managed Xcode project unless the user explicitly asks for that migration and accepts the extra generator dependency. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md new file mode 100644 index 00000000..285aa84c --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md @@ -0,0 +1,38 @@ +# Testing, Debugging, And Distribution + +## Documented Anchors + +- Running your Safari Web Extension: https://developer.apple.com/documentation/safariservices/running-your-safari-web-extension +- Troubleshooting your Safari Web Extension: https://developer.apple.com/documentation/safariservices/safari_web_extensions/troubleshooting_your_safari_web_extension +- Troubleshooting your Safari App Extension: https://developer.apple.com/documentation/safariservices/troubleshooting-your-safari-app-extension +- Distributing your Safari Web Extension: https://developer.apple.com/documentation/safariservices/distributing-your-safari-web-extension +- Packaging a Web Extension for Safari: https://developer.apple.com/documentation/safariservices/packaging-a-web-extension-for-safari +- Packaging and distributing Safari Web Extensions with App Store Connect: https://developer.apple.com/documentation/safariservices/packaging-and-distributing-safari-web-extensions-with-app-store-connect + +## Debugging Order + +1. Verify the containing app builds and embeds the extension target. +2. Verify signing, entitlements, app groups, and bundle identifiers. +3. Verify Safari sees the extension and the user has enabled it. +4. Verify host permissions or website access permissions. +5. Verify the right Safari profile or Mac web app context is enabled. +6. Inspect Web Inspector logs, injected-script logs, system logs, and extension errors. +7. Only then debug higher-level app or page behavior. + +## macOS Web Extension Development + +- Temporary extension loading is useful for quick macOS Safari checks, but it is not a substitute for an Xcode project when testing iOS, app-extension messaging, native app coordination, or distribution. +- Unsigned extension testing requires Safari developer settings and resets when Safari quits. +- Use the containing macOS app install path when validating real app-extension packaging behavior. + +## Safari App Extension Debugging + +- Use `pluginkit` to verify whether Safari can see the app extension when visibility is in doubt. +- Verify allowed URL patterns and website access permissions before debugging injected-script logic. +- Keep native extension logs clear about which callback, page, profile, and message failed. + +## Distribution Boundaries + +- App Store distribution requires the extension to be packaged with an app and reviewed as part of the app submission path. +- For Safari Web Extensions, decide early whether the source of truth is an existing cross-browser extension, a new Xcode template project, or a temporary macOS Safari folder during early evaluation. +- Do not claim a WebExtension is production-ready until signing, packaging, permission prompts, App Store Connect metadata, and Safari enablement paths have been exercised. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/scripts/customization_config.py b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/scripts/customization_config.py new file mode 100755 index 00000000..27ef917b --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/scripts/customization_config.py @@ -0,0 +1,213 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "PyYAML>=6.0.2,<7", +# ] +# /// +"""Load and persist per-skill customization state.""" + +from __future__ import annotations + +import argparse +import copy +import os +import re +import sys +from pathlib import Path + +import yaml + +SCHEMA_VERSION = 1 +SKILL_NAME = "safari-extension-control-workflow" +CONFIG_HOME_ENV = "APPLE_DEV_SKILLS_CONFIG_HOME" +DEFAULT_CONFIG_ROOT = "~/.config/gaelic-ghost/apple-dev-skills" +ALLOWED_TOP_LEVEL = {"schemaVersion", "isCustomized", "settings"} + + +def fail(message: str) -> None: + print(f"ERROR: {message}", file=sys.stderr) + raise SystemExit(1) + + +def quote_string(value: str) -> str: + escaped = value.replace("\\", "\\\\").replace('"', '\\"') + return f'"{escaped}"' + + +def encode_scalar(value) -> str: + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, int): + return str(value) + if value is None: + return quote_string("") + return quote_string(str(value)) + + +def parse_yaml(path: Path) -> dict: + if not path.exists(): + fail(f"Missing YAML file: {path}") + + try: + loaded = yaml.safe_load(path.read_text(encoding="utf-8")) + except yaml.YAMLError as exc: + fail(f"Invalid YAML in {path}: {exc}") + + if loaded is None: + return {} + if not isinstance(loaded, dict): + fail(f"Top-level YAML document must be a mapping in {path}") + + if isinstance(loaded.get("settings"), dict): + loaded["settings"] = { + key: ("" if value is None else value) for key, value in loaded["settings"].items() + } + + return loaded + + +def validate_config(config: dict, *, allow_partial: bool) -> None: + unknown = set(config.keys()) - ALLOWED_TOP_LEVEL + if unknown: + fail(f"Unknown top-level keys: {', '.join(sorted(unknown))}") + + if not allow_partial: + for required in ("schemaVersion", "isCustomized", "settings"): + if required not in config: + fail(f"Missing required key: {required}") + + if "schemaVersion" in config and config["schemaVersion"] != SCHEMA_VERSION: + fail(f"schemaVersion must be {SCHEMA_VERSION}") + + if "isCustomized" in config and not isinstance(config["isCustomized"], bool): + fail("isCustomized must be boolean") + + if "settings" in config: + if not isinstance(config["settings"], dict): + fail("settings must be a mapping") + for key, value in config["settings"].items(): + if not re.fullmatch(r"[A-Za-z0-9_]+", key): + fail(f"Invalid settings key: {key}") + if isinstance(value, (dict, list)): + fail(f"settings values must be scalar: {key}") + + +def merge_configs(base: dict, overlay: dict) -> dict: + merged = { + "schemaVersion": base.get("schemaVersion", SCHEMA_VERSION), + "isCustomized": base.get("isCustomized", False), + "settings": copy.deepcopy(base.get("settings", {})), + } + + if "schemaVersion" in overlay: + merged["schemaVersion"] = overlay["schemaVersion"] + if "isCustomized" in overlay: + merged["isCustomized"] = overlay["isCustomized"] + if "settings" in overlay: + merged["settings"].update(overlay["settings"]) + + return merged + + +def dump_yaml(config: dict) -> str: + lines = [ + f"schemaVersion: {int(config['schemaVersion'])}", + f"isCustomized: {'true' if config['isCustomized'] else 'false'}", + "settings:", + ] + for key in sorted(config["settings"].keys()): + lines.append(f" {key}: {encode_scalar(config['settings'][key])}") + return "\n".join(lines) + "\n" + + +def template_path() -> Path: + return Path(__file__).resolve().parents[1] / "references" / "customization.template.yaml" + + +def config_root() -> Path: + root = os.environ.get(CONFIG_HOME_ENV, DEFAULT_CONFIG_ROOT) + return Path(root).expanduser() + + +def durable_path() -> Path: + return config_root() / SKILL_NAME / "customization.yaml" + + +def load_template() -> dict: + cfg = parse_yaml(template_path()) + validate_config(cfg, allow_partial=False) + return cfg + + +def load_durable() -> dict: + path = durable_path() + if not path.exists(): + return {} + cfg = parse_yaml(path) + validate_config(cfg, allow_partial=False) + return cfg + + +def cmd_path(_: argparse.Namespace) -> None: + print(durable_path()) + + +def cmd_effective(_: argparse.Namespace) -> None: + effective = merge_configs(load_template(), load_durable()) + validate_config(effective, allow_partial=False) + print(dump_yaml(effective), end="") + + +def cmd_apply(args: argparse.Namespace) -> None: + template = load_template() + current = merge_configs(template, load_durable()) + incoming = parse_yaml(Path(args.input)) + validate_config(incoming, allow_partial=True) + + updated = merge_configs(current, incoming) + updated["schemaVersion"] = SCHEMA_VERSION + updated["isCustomized"] = True + validate_config(updated, allow_partial=False) + + target = durable_path() + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(dump_yaml(updated), encoding="utf-8") + print(target) + + +def cmd_reset(_: argparse.Namespace) -> None: + target = durable_path() + if target.exists(): + target.unlink() + print(target) + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Manage per-skill customization config") + subparsers = parser.add_subparsers(dest="command", required=True) + + parser_path = subparsers.add_parser("path", help="Print durable config path") + parser_path.set_defaults(func=cmd_path) + + parser_effective = subparsers.add_parser("effective", help="Print merged effective config") + parser_effective.set_defaults(func=cmd_effective) + + parser_apply = subparsers.add_parser("apply", help="Apply and persist config overrides") + parser_apply.add_argument("--input", required=True, help="Path to YAML overrides") + parser_apply.set_defaults(func=cmd_apply) + + parser_reset = subparsers.add_parser("reset", help="Delete durable config for this skill") + parser_reset.set_defaults(func=cmd_reset) + + return parser + + +def main() -> None: + parser = build_parser() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py b/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py index d789dc60..591e9035 100644 --- a/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py +++ b/plugins/apple-dev-skills/tests/test_customization_consolidation_review.py @@ -66,8 +66,8 @@ def test_review_doc_counts_match_live_customization_surface(self) -> None: knob_count = _count_template_knobs() runtime_enforced, policy_only = _count_statuses() - self.assertEqual(template_count, 16) - self.assertEqual(script_count, 16) + self.assertEqual(template_count, 17) + self.assertEqual(script_count, 17) self.assertEqual(knob_count, 21) self.assertEqual(runtime_enforced, 20) self.assertEqual(policy_only, 1) diff --git a/plugins/apple-dev-skills/tests/test_customization_template_paths.py b/plugins/apple-dev-skills/tests/test_customization_template_paths.py index 77c52c6c..f2444cbe 100644 --- a/plugins/apple-dev-skills/tests/test_customization_template_paths.py +++ b/plugins/apple-dev-skills/tests/test_customization_template_paths.py @@ -14,6 +14,7 @@ "xcode-build-run-workflow": ROOT / "skills/xcode-build-run-workflow/scripts/customization_config.py", "xcode-testing-workflow": ROOT / "skills/xcode-testing-workflow/scripts/customization_config.py", "author-swift-docc-docs": ROOT / "skills/author-swift-docc-docs/scripts/customization_config.py", + "safari-extension-control-workflow": ROOT / "skills/safari-extension-control-workflow/scripts/customization_config.py", "swiftui-app-architecture-workflow": ROOT / "skills/swiftui-app-architecture-workflow/scripts/customization_config.py", "explore-apple-swift-docs": ROOT / "skills/explore-apple-swift-docs/scripts/customization_config.py", "format-swift-sources": ROOT / "skills/format-swift-sources/scripts/customization_config.py", diff --git a/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py b/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py new file mode 100644 index 00000000..e2e0595d --- /dev/null +++ b/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +class SafariExtensionControlWorkflowTests(unittest.TestCase): + def read(self, relative_path: str) -> str: + return (ROOT / relative_path).read_text(encoding="utf-8") + + def test_skill_separates_safari_extension_shapes(self) -> None: + skill_text = self.read("skills/safari-extension-control-workflow/SKILL.md") + decision_text = self.read("skills/safari-extension-control-workflow/references/extension-shape-decision.md") + + self.assertIn("Safari Web Extension", skill_text) + self.assertIn("Safari App Extension", skill_text) + self.assertIn("Content blocker", skill_text) + self.assertIn("ASWebAuthenticationSession", decision_text) + self.assertIn("Safari App Extensions are macOS-only", decision_text) + + def test_skill_keeps_control_surfaces_bounded(self) -> None: + skill_text = self.read("skills/safari-extension-control-workflow/SKILL.md") + control_text = self.read("skills/safari-extension-control-workflow/references/safari-services-control-surfaces.md") + + self.assertIn("Do not claim a Mac app can freely inspect or control arbitrary Safari", skill_text) + self.assertIn("SFSafariApplication.openWindow", control_text) + self.assertIn("SFSafariExtensionManager", control_text) + self.assertIn("external automation", control_text) + + def test_messaging_reference_names_contexts_and_privacy(self) -> None: + messaging_text = self.read("skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md") + + self.assertIn("containing macOS app", messaging_text) + self.assertIn("native app extension", messaging_text) + self.assertIn("WebExtension JavaScript", messaging_text) + self.assertIn("app groups", messaging_text) + self.assertIn("browsing history, cookies, tokens", messaging_text) + + def test_skill_handoffs_stay_explicit(self) -> None: + skill_text = self.read("skills/safari-extension-control-workflow/SKILL.md") + prompt_text = self.read("skills/safari-extension-control-workflow/agents/openai.yaml") + + self.assertIn("Recommend `explore-apple-swift-docs`", skill_text) + self.assertIn("Recommend `xcode-build-run-workflow`", skill_text) + self.assertIn("Recommend `xcode-testing-workflow`", skill_text) + self.assertIn("Recommend `swiftui-app-architecture-workflow`", skill_text) + self.assertIn("$explore-apple-swift-docs", prompt_text) + self.assertIn("$xcode-build-run-workflow", prompt_text) + self.assertIn("$xcode-testing-workflow", prompt_text) + self.assertIn("$swiftui-app-architecture-workflow", prompt_text) + + +if __name__ == "__main__": + unittest.main() From ba14c078c03bc50bf5cd8e3ac4d4fa577f689cc5 Mon Sep 17 00:00:00 2001 From: Gale W Date: Tue, 12 May 2026 19:27:28 -0400 Subject: [PATCH 2/4] plugin: refine Safari extension guidance --- .../.codex-plugin/plugin.json | 6 +-- plugins/apple-dev-skills/ROADMAP.md | 8 ++-- .../SKILL.md | 15 ++++--- .../agents/openai.yaml | 2 +- .../references/extension-shape-decision.md | 16 +++++++ .../testing-debugging-and-distribution.md | 8 ++++ .../references/web-inspector-extensions.md | 42 +++++++++++++++++++ .../test_safari_extension_control_workflow.py | 14 +++++++ 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/web-inspector-extensions.md diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index 8594ac2b..dff416c0 100644 --- a/plugins/apple-dev-skills/.codex-plugin/plugin.json +++ b/plugins/apple-dev-skills/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "apple-dev-skills", "version": "6.7.26", - "description": "Apple development workflows for Codex, including SwiftUI architecture, Safari integration, and DocC authoring guidance.", + "description": "Apple development workflows for Codex, including SwiftUI architecture, Safari extensions, and DocC authoring guidance.", "author": { "name": "Gale", "email": "mail@galewilliams.com", @@ -27,7 +27,7 @@ "interface": { "displayName": "Apple Dev Skills", "shortDescription": "Apple, Swift, Xcode, SwiftUI, Safari, and DocC workflows for Codex.", - "longDescription": "Bundle Apple-platform development skills for Swift, SwiftUI architecture, Safari extension and SafariServices integration, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", + "longDescription": "Bundle Apple-platform development skills for Swift, SwiftUI architecture, Safari extension, Safari Web Inspector, and SafariServices integration, Xcode, SwiftPM, DocC authoring and review, testing, formatting, and repository guidance work across iOS, macOS, and related Apple tooling. Most workflows work standalone; bootstrap and guidance-sync workflows that install or refresh repo-maintenance files require the companion Productivity Skills plugin, or the socket marketplace that installs both.", "developerName": "Gale", "category": "Developer Tools", "capabilities": [ @@ -37,7 +37,7 @@ "websiteURL": "https://github.com/gaelic-ghost/apple-dev-skills", "defaultPrompt": [ "Explore the relevant Apple docs first, then explain the right SwiftUI or Xcode path for this repository.", - "Choose the right Safari extension, SafariServices, messaging, content blocker, or automation fallback path for this Mac app.", + "Choose the right Safari extension, Safari Web Inspector, SafariServices, messaging, content blocker, or automation fallback path for this Mac app.", "Help me build, test, or debug this Swift or Xcode project using the repo's Apple workflows.", "Write or review DocC symbol comments, articles, extension files, and landing-page structure for this Swift repository.", "Sync the Apple project guidance in this repo without hand-editing Xcode project files, using Productivity Skills when repo-maintenance files must be installed or refreshed." diff --git a/plugins/apple-dev-skills/ROADMAP.md b/plugins/apple-dev-skills/ROADMAP.md index dd7f7f6d..8bacc8d0 100644 --- a/plugins/apple-dev-skills/ROADMAP.md +++ b/plugins/apple-dev-skills/ROADMAP.md @@ -401,7 +401,7 @@ Completed ### Scope -- [x] Add a dedicated Safari workflow for choosing between Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, authentication surfaces, and external automation fallbacks. +- [x] Add a dedicated Safari workflow for choosing between Safari Web Extensions, Safari Web Inspector Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, authentication surfaces, and external automation fallbacks. - [x] Keep the workflow docs-first and explicit about Apple-documented Safari behavior before implementation choices. - [x] Teach agents to treat "control Safari from a macOS app" as a scoped integration question rather than assuming unrestricted browser control. - [x] Keep Xcode target, signing, entitlement, build, run, and testing work routed into the existing Xcode skills. @@ -409,14 +409,14 @@ Completed ### Tickets - [x] Add `safari-extension-control-workflow` with repo-standard skill metadata, OpenAI interface metadata, customization contract files, and shared Xcode policy snippet coverage. -- [x] Add references for extension-shape choice, SafariServices control surfaces, messaging and shared data, permissions, testing, debugging, and distribution. +- [x] Add references for extension-shape choice, Safari Web Inspector Extensions, SafariServices control surfaces, messaging and shared data, permissions, testing, debugging, and distribution. - [x] Add targeted pytest coverage for extension-shape boundaries, supported control surfaces, messaging contexts, privacy posture, and explicit handoffs. - [x] Update the active skill inventory, repo validator, shared-snippet sync script, README, and customization review counts. ### Exit Criteria - [x] The repository ships `safari-extension-control-workflow` as the explicit owner for Safari extension and SafariServices integration-shape guidance. -- [x] The workflow keeps WebExtension, Safari App Extension, content blocker, authentication, and external automation paths distinct. +- [x] The workflow keeps WebExtension, Safari Web Inspector Extension, Safari App Extension, content blocker, authentication, and external automation paths distinct. - [x] The skill is covered by repo validation and targeted tests. ## Backlog Candidates @@ -425,7 +425,7 @@ Completed ## History -- Added `safari-extension-control-workflow` as the explicit owner for Safari Web Extension, Safari App Extension, SafariServices, messaging, content blocker, authentication, and external automation decision guidance. +- Added `safari-extension-control-workflow` as the explicit owner for Safari Web Extension, Safari Web Inspector Extension, Safari App Extension, SafariServices, messaging, content blocker, authentication, and external automation decision guidance. - Tightened Xcode project guidance so tracked `.pbxproj` diffs produced by Xcode, XcodeGen, or other project-aware workflows are treated as critical project state that must be reviewed, staged, and committed before push, merge, release, or cleanup. - Updated standalone install guidance so `apple-dev-skills` defaults to Codex's Git-backed marketplace add/upgrade flow without an explicit ref, documents the optional `socket` marketplace path for Gale's broader plugin set, and keeps manual local clone marketplaces as development and fallback paths. - Tightened the Swift public API guidance across shared snippets, skill-local snippet copies, and generated `AGENTS.md` templates so public call sites default to streamlined typed APIs, optional defaulted parameters over overloads, request/options structs at four or more public parameters, and enum-backed choice modeling. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md index b1069c96..017c96cf 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md @@ -1,6 +1,6 @@ --- name: safari-extension-control-workflow -description: Guide macOS Safari integration decisions across Safari Web Extensions, Safari App Extensions, SafariServices APIs, content blockers, extension messaging, and app-to-Safari control surfaces. Use when the user wants a Mac app to extend, message, open, inspect, or coordinate with Safari without confusing WebExtension, native extension, content blocker, authentication, or AppleScript-style automation paths. +description: Guide macOS Safari integration decisions across Safari Web Extensions, Safari Web Inspector Extensions, Safari App Extensions, SafariServices APIs, content blockers, extension messaging, and app-to-Safari control surfaces. Use when the user wants a Mac app to extend, message, open, inspect, debug, or coordinate with Safari without confusing WebExtension, Web Inspector, native extension, content blocker, authentication, or AppleScript-style automation paths. --- # Safari Extension Control Workflow @@ -9,13 +9,13 @@ description: Guide macOS Safari integration decisions across Safari Web Extensio Guide Safari integration work for macOS apps, with enough platform awareness to choose the right Safari extension or SafariServices surface before implementation starts. -This skill owns the decision between Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, and limited external automation paths. It is not a generic browser-extension guide and it is not a replacement for `xcode-build-run-workflow` or `xcode-testing-workflow`. +This skill owns the decision between Safari Web Extensions, Safari Web Inspector Extensions, Safari App Extensions, content blockers, SafariServices APIs, app-to-extension messaging, and limited external automation paths. It is not a generic browser-extension guide and it is not a replacement for `xcode-build-run-workflow` or `xcode-testing-workflow`. ## When To Use - Use this skill when the user wants a macOS app to extend Safari, communicate with Safari content, or coordinate native app state with a Safari extension. -- Use this skill when choosing between a Safari Web Extension, Safari App Extension, Safari content blocker, `SFSafariApplication`, `SFSafariExtensionManager`, `SFSafariViewController`, `ASWebAuthenticationSession`, AppleScript, Shortcuts, or URL-opening behavior. -- Use this skill when the work involves WebExtension manifests, native messaging, app groups, injected scripts, toolbar items, content blockers, Safari profiles, temporary extension loading, unsigned extension testing, or App Store distribution. +- Use this skill when choosing between a Safari Web Extension, Safari Web Inspector Extension, Safari App Extension, Safari content blocker, `SFSafariApplication`, `SFSafariExtensionManager`, `SFSafariViewController`, `ASWebAuthenticationSession`, AppleScript, Shortcuts, or URL-opening behavior. +- Use this skill when the work involves WebExtension manifests, Web Inspector developer-tool panels, native messaging, app groups, injected scripts, toolbar items, content blockers, Safari profiles, temporary extension loading, unsigned extension testing, or App Store distribution. - Use this skill when a user says they want to "control Safari" from a Mac app and the first job is distinguishing supported SafariServices control from broader GUI or scripting automation. - Recommend `explore-apple-swift-docs` when the user primarily needs direct Apple documentation lookup rather than integration-shape guidance. - Recommend `xcode-build-run-workflow` when the next step is target setup, build settings, entitlements, signing, file membership, running the containing app, or guarded Xcode project mutation. @@ -26,6 +26,7 @@ This skill owns the decision between Safari Web Extensions, Safari App Extension 1. Classify the Safari integration request: - WebExtension-compatible browser feature + - Web Inspector developer-tool feature - macOS-only Safari App Extension feature - declarative content blocking - containing app to extension messaging @@ -40,6 +41,7 @@ This skill owns the decision between Safari Web Extensions, Safari App Extension - if no relevant Apple documentation can be found, say that explicitly before proceeding 3. Choose the supported integration surface: - Safari Web Extension for cross-browser-style JavaScript, HTML, CSS, manifest, browser APIs, iOS, visionOS, Mac web apps, or extension portability + - Safari Web Inspector Extension for developer-facing tools that extend Safari Web Inspector rather than user-facing browsing behavior - Safari App Extension for macOS-only native extension behavior that uses SafariServices classes and can share data with a containing Mac app - Content blocker when the feature is declarative blocking and does not need to inspect page content or run arbitrary page logic - `SFSafariApplication` and related Safari App Extension proxies only for supported Safari extension interactions such as opening windows, sending app-to-extension messages, or working with Safari windows, tabs, pages, and toolbar items from the extension context @@ -74,6 +76,7 @@ This skill owns the decision between Safari Web Extensions, Safari App Extension - Defaults: - docs-first guidance always applies - prefer Safari Web Extensions for portable browser-extension behavior + - prefer Safari Web Inspector Extensions only for developer tools that live inside Safari Web Inspector - prefer Safari App Extensions only when the macOS-only native extension model is the real requirement - prefer SafariServices and AuthenticationServices over GUI scripting when the documented API surface covers the job @@ -84,7 +87,7 @@ This skill owns the decision between Safari Web Extensions, Safari App Extension - `handoff`: the request belongs to another Apple Dev skill after Safari-aware classification - `blocked`: the request lacks enough context or relies on unsupported Safari behavior - `path_type` - - `primary`: the recommendation uses a documented SafariServices, Web Extension, App Extension, content blocker, or authentication path + - `primary`: the recommendation uses a documented SafariServices, Web Extension, Web Inspector Extension, App Extension, content blocker, or authentication path - `fallback`: the recommendation depends on external automation because the documented Safari API surface does not cover the requested behavior - `output` - resolved Safari integration class @@ -102,6 +105,7 @@ This skill owns the decision between Safari Web Extensions, Safari App Extension - Do not collapse Safari Web Extension native messaging, Safari App Extension injected-script messaging, and app-group shared storage into one vague "bridge"; name the exact contexts and transport. - Do not recommend a Safari App Extension for portable WebExtension behavior unless a macOS-only native extension requirement is explicit. - Do not recommend a Safari Web Extension for arbitrary native control of Safari outside the browser-extension permission model. +- Do not recommend a Safari Web Inspector Extension for ordinary end-user browser customization; Web Inspector extensions are developer tools. - Stop with `blocked` when the feature requires user-private Safari data or privileged browser control that Apple does not expose through the documented APIs and the user has not explicitly opted into external automation. ## Fallbacks and Handoffs @@ -126,6 +130,7 @@ Keep the first release focused on the documented Safari surface decision. If fut ### Workflow References - `references/extension-shape-decision.md` +- `references/web-inspector-extensions.md` - `references/safari-services-control-surfaces.md` - `references/messaging-shared-data-and-permissions.md` - `references/testing-debugging-and-distribution.md` diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml index b2c2306b..b3bcea9d 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Safari Extension Control Workflow" short_description: "Choose Safari extension and app-control paths" - default_prompt: "Use $safari-extension-control-workflow to choose the right Safari integration shape for a macOS app across Safari Web Extensions, Safari App Extensions, content blockers, SafariServices APIs, native messaging, app groups, extension state checks, and external automation fallbacks. Start from current Apple docs, state the documented Safari behavior or limit being relied on, then hand off to $xcode-build-run-workflow, $xcode-testing-workflow, $swiftui-app-architecture-workflow, or $explore-apple-swift-docs when the next step belongs there." + default_prompt: "Use $safari-extension-control-workflow to choose the right Safari integration shape for a macOS app across Safari Web Extensions, Safari Web Inspector Extensions, Safari App Extensions, content blockers, SafariServices APIs, native messaging, app groups, extension state checks, and external automation fallbacks. Start from current Apple docs, state the documented Safari behavior or limit being relied on, then hand off to $xcode-build-run-workflow, $xcode-testing-workflow, $swiftui-app-architecture-workflow, or $explore-apple-swift-docs when the next step belongs there." diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md index 8e18ff07..2c381815 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/extension-shape-decision.md @@ -8,10 +8,14 @@ - Safari App Extensions: https://developer.apple.com/documentation/safariservices/safari_app_extensions - Safari app extension Info.plist keys: https://developer.apple.com/documentation/safariservices/using-safari-app-extension-default-keys - Content blockers: https://developer.apple.com/documentation/safariservices/creating-a-content-blocker +- Adding a web development tool to Safari Web Inspector: https://developer.apple.com/documentation/safariservices/adding-a-web-development-tool-to-safari-web-inspector +- Creating Safari Web Inspector extensions: https://developer.apple.com/documentation/safariservices/creating-safari-web-inspector-extensions +- Underpass explanation of Safari extension types: https://underpassapp.com/news/2023-4-24.html ## Decision Rules - Choose a Safari Web Extension when the core behavior is browser-extension-shaped: JavaScript, HTML, CSS, a manifest, browser extension APIs, content scripts, background scripts, toolbar UI, permissions, and portability to or from Chrome, Firefox, or Edge extension formats. +- Choose a Safari Web Inspector Extension when the user is building a developer-facing Web Inspector tool. Keep this separate from ordinary Web Extensions that affect browsing behavior for end users. - Choose a Safari App Extension when the feature is macOS-only and needs native SafariServices app-extension objects such as `SFSafariExtensionHandler`, `SFSafariApplication`, `SFSafariWindow`, `SFSafariTab`, `SFSafariPage`, or toolbar-item callbacks. - Choose a content blocker when the feature can be expressed as declarative blocking rules. Do not upgrade a content blocker to a Web Extension or App Extension unless the feature needs messaging, content scripts, arbitrary JavaScript, app data, or native UI. - Choose `ASWebAuthenticationSession` when the user needs browser-backed authentication or SSO. Do not frame authentication as "controlling Safari" unless Safari extension behavior is actually involved. @@ -22,12 +26,24 @@ - Safari Web Extensions are available beyond macOS, including iOS and visionOS, and can also be used in Mac web apps on supported macOS versions. - Safari App Extensions are macOS-only. - Safari content blockers can be useful on iOS and macOS, but they are intentionally narrower than Web Extensions or App Extensions. +- Safari Web Inspector Extensions are Safari Web Extension-based developer tools for Web Inspector. Treat them as inspection, testing, and debugging tools, not as a general page-customization path. - When a user asks for one codebase across Safari and other browsers, bias toward Safari Web Extensions unless a native macOS-only requirement is central. - When a user asks for tight integration with a Mac app and Safari windows or pages, evaluate Safari App Extensions first, then decide whether a Web Extension with native messaging is enough. +## Practical Differences + +- Safari Web Extensions are the best fit for cross-browser-style extension code, but they still need Apple packaging and distribution. Do not imply they can ship as loose extension archives to Safari users. +- Safari App Extensions can use JavaScript and style sheets, but their SafariServices API is different from the cross-browser WebExtensions API. Code sharing with Chrome, Firefox, or Edge is usually harder. +- Safari App Extensions can provide native Mac UI inside Safari, which is a real reason to choose them when the feature is Mac-only. +- Content blockers have no JavaScript execution path and do not receive page-content or URL-load telemetry from Safari. Their privacy posture is part of the feature, not an implementation inconvenience. +- On Mac, extension types can look similar in Safari Settings. Use capability clues instead of user-facing labels alone: content blockers have no page-permission prompts, Web Extensions use website access permissions, App Extensions can expose native Mac UI, and obsolete `.safariextz` extensions should not be considered for new work. +- Safari 17 and later brought Safari App Extensions into the same per-site permission model family as Safari Web Extensions. Do not assume older "enabled means all websites" behavior when giving current guidance. + ## Anti-Patterns - Do not recommend Safari App Extensions only because the containing app is native. If the browser-facing behavior is portable WebExtension work, use the Web Extension model. +- Do not recommend Safari Web Inspector Extensions for end-user customization, content blocking, or normal toolbar extension features. - Do not recommend a Safari Web Extension when the feature requires native Safari App Extension callback objects that WebExtension APIs do not expose. - Do not treat content blockers as a privacy-invasive inspection surface; their strength is declarative matching, not page introspection. - Do not assume the containing app can silently enable an extension. Users manage extension enablement in Safari. +- Do not propose `.safariextz` for new work. That format is obsolete. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md index 285aa84c..5fe6226a 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/testing-debugging-and-distribution.md @@ -8,6 +8,7 @@ - Distributing your Safari Web Extension: https://developer.apple.com/documentation/safariservices/distributing-your-safari-web-extension - Packaging a Web Extension for Safari: https://developer.apple.com/documentation/safariservices/packaging-a-web-extension-for-safari - Packaging and distributing Safari Web Extensions with App Store Connect: https://developer.apple.com/documentation/safariservices/packaging-and-distributing-safari-web-extensions-with-app-store-connect +- Adding a web development tool to Safari Web Inspector: https://developer.apple.com/documentation/safariservices/adding-a-web-development-tool-to-safari-web-inspector ## Debugging Order @@ -25,6 +26,13 @@ - Unsigned extension testing requires Safari developer settings and resets when Safari quits. - Use the containing macOS app install path when validating real app-extension packaging behavior. +## Web Inspector Extension Development + +- Treat Safari Web Inspector Extensions as developer-tool panels that extend Web Inspector, not as ordinary end-user extension UI. +- Verify Web Inspector developer features before debugging the extension itself. +- Validate the Web Inspector panel loads before testing inspected-page data exchange. +- Keep console and diagnostic output clear about whether a failure is in the Web Inspector extension UI, inspected-page messaging, the containing app, or native messaging. + ## Safari App Extension Debugging - Use `pluginkit` to verify whether Safari can see the app extension when visibility is in doubt. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/web-inspector-extensions.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/web-inspector-extensions.md new file mode 100644 index 00000000..2b8d0ac0 --- /dev/null +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/web-inspector-extensions.md @@ -0,0 +1,42 @@ +# Safari Web Inspector Extensions + +## Documented Anchors + +- Adding a web development tool to Safari Web Inspector: https://developer.apple.com/documentation/safariservices/adding-a-web-development-tool-to-safari-web-inspector +- Creating Safari Web Inspector extensions: https://developer.apple.com/documentation/safariservices/creating-safari-web-inspector-extensions +- WWDC22 Create Safari Web Inspector Extensions: https://developer.apple.com/videos/play/wwdc2022/10100/ +- WWDC22 What's new in Safari and WebKit: https://developer.apple.com/videos/play/wwdc2022/10048/ + +## When To Choose This Path + +Choose a Safari Web Inspector Extension when the product is a developer tools feature that belongs inside Safari Web Inspector. This is different from an ordinary Safari Web Extension that customizes web browsing for end users. + +Good fits include: + +- inspecting page state with custom developer UI +- adding debugging or analysis panels to Web Inspector +- porting an existing browser developer-tools extension to Safari +- augmenting Safari's built-in inspecting, testing, and debugging tools + +Poor fits include: + +- changing normal user-facing webpage behavior +- blocking ads or trackers +- adding an end-user toolbar popup +- automating Safari windows or tabs from a native app +- replacing Xcode, system logs, or native app debugging for the containing app + +## Implementation Shape + +- Treat the Web Inspector tool as part of a Safari Web Extension project. +- Keep the developer-tool UI and inspected-page communication separate from ordinary content scripts or toolbar behavior. +- Verify whether the tool depends on browser developer-tools APIs that Safari supports before assuming a Chrome or Firefox developer-tools extension will port cleanly. +- Keep any inspected-page data handling privacy-aware. Developer tools can expose sensitive page data during debugging, so logs and persisted diagnostics should be deliberate. + +## Validation + +- Enable Safari developer features and unsigned extension support when using Apple's sample or local development flow. +- Confirm the Web Inspector panel appears in Safari Web Inspector before debugging the inspected-page integration. +- Validate inspected-page messaging separately from the containing app or native messaging behavior. +- Use `xcode-build-run-workflow` when Xcode target setup, signing, or extension packaging is the blocker. +- Use `xcode-testing-workflow` when the work needs repeatable verification around Web Inspector UI availability or inspected-page behavior. diff --git a/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py b/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py index e2e0595d..0cd8838d 100644 --- a/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py +++ b/plugins/apple-dev-skills/tests/test_safari_extension_control_workflow.py @@ -16,10 +16,24 @@ def test_skill_separates_safari_extension_shapes(self) -> None: decision_text = self.read("skills/safari-extension-control-workflow/references/extension-shape-decision.md") self.assertIn("Safari Web Extension", skill_text) + self.assertIn("Safari Web Inspector Extension", skill_text) self.assertIn("Safari App Extension", skill_text) self.assertIn("Content blocker", skill_text) self.assertIn("ASWebAuthenticationSession", decision_text) self.assertIn("Safari App Extensions are macOS-only", decision_text) + self.assertIn(".safariextz", decision_text) + self.assertIn("no JavaScript execution path", decision_text) + + def test_web_inspector_extension_path_is_first_class(self) -> None: + skill_text = self.read("skills/safari-extension-control-workflow/SKILL.md") + inspector_text = self.read("skills/safari-extension-control-workflow/references/web-inspector-extensions.md") + prompt_text = self.read("skills/safari-extension-control-workflow/agents/openai.yaml") + + self.assertIn("web-inspector-extensions.md", skill_text) + self.assertIn("developer tools", inspector_text) + self.assertIn("Safari Web Inspector", inspector_text) + self.assertIn("inspected-page", inspector_text) + self.assertIn("Safari Web Inspector Extensions", prompt_text) def test_skill_keeps_control_surfaces_bounded(self) -> None: skill_text = self.read("skills/safari-extension-control-workflow/SKILL.md") From 5c9bf02195d1d015349ef5c31ec169c799bd4a63 Mon Sep 17 00:00:00 2001 From: Gale W Date: Tue, 12 May 2026 20:07:13 -0400 Subject: [PATCH 3/4] release: bump shared version to 6.8.0 --- plugins/agent-plugin-skills/.codex-plugin/plugin.json | 2 +- plugins/agent-plugin-skills/pyproject.toml | 2 +- plugins/agent-plugin-skills/uv.lock | 2 +- plugins/apple-dev-skills/.codex-plugin/plugin.json | 2 +- plugins/apple-dev-skills/pyproject.toml | 2 +- plugins/apple-dev-skills/uv.lock | 2 +- plugins/cardhop-app/.codex-plugin/plugin.json | 2 +- plugins/cardhop-app/mcp/pyproject.toml | 2 +- plugins/cardhop-app/mcp/uv.lock | 2 +- plugins/dotnet-skills/.codex-plugin/plugin.json | 2 +- plugins/productivity-skills/.codex-plugin/plugin.json | 2 +- plugins/productivity-skills/pyproject.toml | 2 +- plugins/productivity-skills/uv.lock | 2 +- plugins/python-skills/.codex-plugin/plugin.json | 2 +- plugins/python-skills/pyproject.toml | 2 +- plugins/python-skills/uv.lock | 2 +- plugins/rust-skills/.codex-plugin/plugin.json | 2 +- plugins/spotify/.codex-plugin/plugin.json | 2 +- plugins/swiftasb-skills/.codex-plugin/plugin.json | 2 +- plugins/things-app/.codex-plugin/plugin.json | 2 +- plugins/things-app/mcp/pyproject.toml | 2 +- plugins/things-app/mcp/uv.lock | 2 +- plugins/things-app/pyproject.toml | 2 +- plugins/things-app/uv.lock | 2 +- plugins/web-dev-skills/.codex-plugin/plugin.json | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/plugins/agent-plugin-skills/.codex-plugin/plugin.json b/plugins/agent-plugin-skills/.codex-plugin/plugin.json index 0de23ade..3d626eba 100644 --- a/plugins/agent-plugin-skills/.codex-plugin/plugin.json +++ b/plugins/agent-plugin-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agent-plugin-skills", - "version": "6.7.26", + "version": "6.8.0", "description": "Installable maintainer skills for skills-export repositories.", "author": { "name": "Gale", diff --git a/plugins/agent-plugin-skills/pyproject.toml b/plugins/agent-plugin-skills/pyproject.toml index 99845828..240cae64 100644 --- a/plugins/agent-plugin-skills/pyproject.toml +++ b/plugins/agent-plugin-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agent-plugin-skills-maintenance" -version = "6.7.26" +version = "6.8.0" description = "Maintainer-only Python tooling baseline for agent-plugin-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/agent-plugin-skills/uv.lock b/plugins/agent-plugin-skills/uv.lock index 921a139a..df572cbb 100644 --- a/plugins/agent-plugin-skills/uv.lock +++ b/plugins/agent-plugin-skills/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.11" [[package]] name = "agent-plugin-skills-maintenance" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/apple-dev-skills/.codex-plugin/plugin.json b/plugins/apple-dev-skills/.codex-plugin/plugin.json index dff416c0..8d664e74 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": "6.7.26", + "version": "6.8.0", "description": "Apple development workflows for Codex, including SwiftUI architecture, Safari extensions, and DocC authoring guidance.", "author": { "name": "Gale", diff --git a/plugins/apple-dev-skills/pyproject.toml b/plugins/apple-dev-skills/pyproject.toml index f59b72ae..3df5b5fd 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 = "6.7.26" +version = "6.8.0" description = "Maintainer tooling for the apple-dev-skills repository" requires-python = ">=3.9" dependencies = [] diff --git a/plugins/apple-dev-skills/uv.lock b/plugins/apple-dev-skills/uv.lock index 0caa809d..b35f7019 100644 --- a/plugins/apple-dev-skills/uv.lock +++ b/plugins/apple-dev-skills/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "apple-dev-skills-maintainer" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/cardhop-app/.codex-plugin/plugin.json b/plugins/cardhop-app/.codex-plugin/plugin.json index 316187a6..1ba02d39 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": "6.7.26", + "version": "6.8.0", "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 8d504f03..3241c899 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 = "6.7.26" +version = "6.8.0" 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 7606a482..e7846e06 100644 --- a/plugins/cardhop-app/mcp/uv.lock +++ b/plugins/cardhop-app/mcp/uv.lock @@ -93,7 +93,7 @@ wheels = [ [[package]] name = "cardhop-app-mcp" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/dotnet-skills/.codex-plugin/plugin.json b/plugins/dotnet-skills/.codex-plugin/plugin.json index 1232a5b2..a90c72e2 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": "6.7.26", + "version": "6.8.0", "description": "Standalone plugin repository for future .NET-focused Codex skills.", "author": { "name": "Gale", diff --git a/plugins/productivity-skills/.codex-plugin/plugin.json b/plugins/productivity-skills/.codex-plugin/plugin.json index 40dc855f..eb910509 100644 --- a/plugins/productivity-skills/.codex-plugin/plugin.json +++ b/plugins/productivity-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "productivity-skills", - "version": "6.7.26", + "version": "6.8.0", "description": "Broadly useful productivity workflows for Codex.", "author": { "name": "Gale", diff --git a/plugins/productivity-skills/pyproject.toml b/plugins/productivity-skills/pyproject.toml index 2d95442a..63a94488 100644 --- a/plugins/productivity-skills/pyproject.toml +++ b/plugins/productivity-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "productivity-skills-maintenance" -version = "6.7.26" +version = "6.8.0" description = "Maintainer-only Python tooling baseline for productivity-skills." requires-python = ">=3.11" dependencies = [] diff --git a/plugins/productivity-skills/uv.lock b/plugins/productivity-skills/uv.lock index 8e097c61..81bb2d91 100644 --- a/plugins/productivity-skills/uv.lock +++ b/plugins/productivity-skills/uv.lock @@ -40,7 +40,7 @@ wheels = [ [[package]] name = "productivity-skills-maintenance" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/python-skills/.codex-plugin/plugin.json b/plugins/python-skills/.codex-plugin/plugin.json index 52f962cd..ca67bbcb 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": "6.7.26", + "version": "6.8.0", "description": "Bundled Python-focused Codex skills for uv bootstrapping, FastAPI and FastMCP scaffolding, FastAPI/FastMCP integration, and pytest workflows.", "author": { "name": "Gale", diff --git a/plugins/python-skills/pyproject.toml b/plugins/python-skills/pyproject.toml index 095facfb..e7f38625 100644 --- a/plugins/python-skills/pyproject.toml +++ b/plugins/python-skills/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "python-skills-maintainer" -version = "6.7.26" +version = "6.8.0" 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 c4c21c06..d9026f58 100644 --- a/plugins/python-skills/uv.lock +++ b/plugins/python-skills/uv.lock @@ -206,7 +206,7 @@ wheels = [ [[package]] name = "python-skills-maintainer" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } [package.dev-dependencies] diff --git a/plugins/rust-skills/.codex-plugin/plugin.json b/plugins/rust-skills/.codex-plugin/plugin.json index 2a525ee6..fa7e4d75 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": "6.7.26", + "version": "6.8.0", "description": "Standalone plugin repository for future Rust-focused Codex skills.", "author": { "name": "Gale", diff --git a/plugins/spotify/.codex-plugin/plugin.json b/plugins/spotify/.codex-plugin/plugin.json index efe2f20e..314d031a 100644 --- a/plugins/spotify/.codex-plugin/plugin.json +++ b/plugins/spotify/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "spotify", - "version": "6.7.26", + "version": "6.8.0", "description": "Placeholder plugin repository for future Spotify-focused Codex workflows.", "author": { "name": "Gale", diff --git a/plugins/swiftasb-skills/.codex-plugin/plugin.json b/plugins/swiftasb-skills/.codex-plugin/plugin.json index 066df995..53bc354c 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": "6.7.26", + "version": "6.8.0", "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 456da7f1..b283a384 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": "6.7.26", + "version": "6.8.0", "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 1859a57c..7f49f4a8 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 = "6.7.26" +version = "6.8.0" 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 419f4642..edb9661c 100644 --- a/plugins/things-app/mcp/uv.lock +++ b/plugins/things-app/mcp/uv.lock @@ -1118,7 +1118,7 @@ wheels = [ [[package]] name = "things-mcp" -version = "6.7.26" +version = "6.8.0" source = { editable = "." } dependencies = [ { name = "fastmcp" }, diff --git a/plugins/things-app/pyproject.toml b/plugins/things-app/pyproject.toml index 756a3817..f72a37e7 100644 --- a/plugins/things-app/pyproject.toml +++ b/plugins/things-app/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "things-app-maintenance" -version = "6.7.26" +version = "6.8.0" 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 4a9abcbf..e6d941bf 100644 --- a/plugins/things-app/uv.lock +++ b/plugins/things-app/uv.lock @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "things-app-maintenance" -version = "6.7.26" +version = "6.8.0" 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 2a5df24c..a1d2a503 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": "6.7.26", + "version": "6.8.0", "description": "Standalone plugin repository for future web-focused Codex skills.", "author": { "name": "Gale", diff --git a/pyproject.toml b/pyproject.toml index 1321cba8..311e9545 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "socket-maintenance" -version = "6.7.26" +version = "6.8.0" description = "Root uv tooling baseline for the socket superproject." requires-python = ">=3.11" dependencies = [] diff --git a/uv.lock b/uv.lock index e5ec2e42..b17b9ab8 100644 --- a/uv.lock +++ b/uv.lock @@ -286,7 +286,7 @@ wheels = [ [[package]] name = "socket-maintenance" -version = "6.7.26" +version = "6.8.0" source = { virtual = "." } [package.dev-dependencies] From 0721e2279ae853b3e64d32807dad6df77bb1b37f Mon Sep 17 00:00:00 2001 From: Gale W Date: Tue, 12 May 2026 20:13:12 -0400 Subject: [PATCH 4/4] plugin: clarify Safari messaging guidance --- .../skills/safari-extension-control-workflow/SKILL.md | 2 +- .../references/messaging-shared-data-and-permissions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md index 017c96cf..59c3aaf1 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/SKILL.md @@ -110,7 +110,7 @@ This skill owns the decision between Safari Web Extensions, Safari Web Inspector ## Fallbacks and Handoffs -- Recommend `explore-apple-swift-docs` when the real need is direct Apple docs lookup for SafariServices, Web Extensions, App Extensions, AuthenticationServices, or App Extensions. +- Recommend `explore-apple-swift-docs` when the real need is direct Apple docs lookup for SafariServices, Web Extensions, App Extensions, Web Inspector Extensions, or AuthenticationServices. - Recommend `xcode-build-run-workflow` when the next step is creating targets, adding entitlements, wiring app groups, signing, running the containing app, or debugging build/install state. - Recommend `xcode-testing-workflow` when the next step is repeatable test design or extension-state verification. - Recommend `swiftui-app-architecture-workflow` when Safari integration shape is settled and the native app shell needs scene, command, focus, settings, or menu ownership guidance. diff --git a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md index aa9d8ac6..f4b9be4e 100644 --- a/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md +++ b/plugins/apple-dev-skills/skills/safari-extension-control-workflow/references/messaging-shared-data-and-permissions.md @@ -40,7 +40,7 @@ Keep the distinction clear: - webpage JavaScript is not the same as the injected script context - injected scripts communicate through the `safari` namespace Apple documents for Safari App Extensions - containing-app messages to the extension use `SFSafariApplication.dispatchMessage` -- page messages back to scripts use `SFSafariPage.dispatchMessageToScript` +- extension-side dispatch to the injected script context uses `SFSafariPage.dispatchMessageToScript` ## Permission And Privacy Rules