diff --git a/.github/assets/logo/logo-dark.png b/.github/assets/logo/logo-dark.png new file mode 100644 index 0000000..233bbad Binary files /dev/null and b/.github/assets/logo/logo-dark.png differ diff --git a/.github/assets/logo/logo-light.png b/.github/assets/logo/logo-light.png new file mode 100644 index 0000000..cf4c6be Binary files /dev/null and b/.github/assets/logo/logo-light.png differ diff --git a/.github/assets/social-preview/social-preview.png b/.github/assets/social-preview/social-preview.png new file mode 100644 index 0000000..8713437 Binary files /dev/null and b/.github/assets/social-preview/social-preview.png differ diff --git a/.github/assets/terminal/recording.json b/.github/assets/terminal/recording.json new file mode 100644 index 0000000..fb873d4 --- /dev/null +++ b/.github/assets/terminal/recording.json @@ -0,0 +1,13 @@ +{ + "title": "Preview a notification with apple-cli", + "steps": [ + { + "command": "apple --version", + "output": "0.1.0" + }, + { + "command": "apple notifications preview --title Build --body Done --json --pretty", + "output": "{\n \"data\" : {\n \"externalAction\" : false,\n \"notification\" : {\n \"body\" : \"Done\",\n \"title\" : \"Build\"\n }\n },\n \"meta\" : {\n \"target\" : \"notifications\"\n },\n \"ok\" : true,\n \"warnings\" : [\n\n ]\n}" + } + ] +} diff --git a/.github/assets/terminal/script.yml b/.github/assets/terminal/script.yml new file mode 100644 index 0000000..cccef38 --- /dev/null +++ b/.github/assets/terminal/script.yml @@ -0,0 +1,5 @@ +title: Preview a notification with apple-cli +executable: apple +steps: + - run: apple --version + - run: apple notifications preview --title Build --body Done --json --pretty diff --git a/.github/assets/terminal/terminal-dark.svg b/.github/assets/terminal/terminal-dark.svg new file mode 100644 index 0000000..270f645 --- /dev/null +++ b/.github/assets/terminal/terminal-dark.svg @@ -0,0 +1,91 @@ + +Preview a notification with apple-cli +$ apple --version +0.1.0 + +$ apple notifications preview --title Build --body Done --json --pretty +{ + "data" : { + "externalAction" : false, + "notification" : { + "body" : "Done", + "title" : "Build" + } + }, + "meta" : { + "target" : "notifications" + }, + "ok" : true, + "warnings" : [ + + ] +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/terminal/terminal-light.svg b/.github/assets/terminal/terminal-light.svg new file mode 100644 index 0000000..eb764b2 --- /dev/null +++ b/.github/assets/terminal/terminal-light.svg @@ -0,0 +1,91 @@ + +Preview a notification with apple-cli +$ apple --version +0.1.0 + +$ apple notifications preview --title Build --body Done --json --pretty +{ + "data" : { + "externalAction" : false, + "notification" : { + "body" : "Done", + "title" : "Build" + } + }, + "meta" : { + "target" : "notifications" + }, + "ok" : true, + "warnings" : [ + + ] +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/brand/brand.lock.json b/.github/brand/brand.lock.json deleted file mode 100644 index 66074da..0000000 --- a/.github/brand/brand.lock.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schema_version": 2, - "authority": "https://github.com/computer-mcp/.github", - "revision": "2d9913a442afcb22faca90f5272d3988eb961be6e858b71c5067303cf7c627d6", - "consumer": "apple-cli", - "files": { - "Documentation/Brand/header-light.png": "eb39f3783529e1d74d1f5d7ed95fd008014b8a6af27369aa2cffbd5976935edb", - "Documentation/Brand/header-dark.png": "ad3fcc36c67496bf610c918fceb171f95f268f42f6dfefccea7991b6a1a0fee6", - ".github/brand/social.png": "159a4e33130225d3feab7a6a7560ad932d4046c3d2c301e38d5cb9532b9bd5a1" - }, - "entries": { - "README.md": [ - "Apple CLI", - "Documentation/Brand/header-light.png", - "Documentation/Brand/header-dark.png" - ] - } -} diff --git a/.github/brand/social.png b/.github/brand/social.png deleted file mode 100644 index a693aee..0000000 Binary files a/.github/brand/social.png and /dev/null differ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6421fc5..83e79f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,13 +4,14 @@ on: push: branches: [master] pull_request: + types: [opened, synchronize, reopened] workflow_dispatch: permissions: contents: read concurrency: - group: ci-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: @@ -31,10 +32,10 @@ jobs: key: dependencies-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Package.resolved') }} - name: Build, test and stage the release candidate run: | - Scripts/validate-public-content + scripts/validate-public-content python3 -B -m unittest discover -s Tests/ReleaseTools - Scripts/package-release --jobs 2 - Scripts/verify-release --run-tests + scripts/package-release --jobs 2 + scripts/verify-release --run-tests - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: apple-cli-macos-arm64-candidate-${{ github.run_id }}-${{ github.run_attempt }} @@ -47,5 +48,17 @@ jobs: name: validation-logs-${{ github.run_id }}-${{ github.run_attempt }} path: .build/release-validation if-no-files-found: ignore - brand: - uses: computer-mcp/.github/.github/workflows/brand-check.yml@f402911abcdfb87ef0c41a2759e8c51387b18935 # master + demo: + needs: package + uses: computer-mcp/github-workflows/.github/workflows/terminal-demo.yml@53ecce59bf7ed184528b2f7894c864f338932d37 + with: + artifact: apple-cli-macos-arm64-candidate-${{ github.run_id }}-${{ github.run_attempt }} + archive: apple-cli-*-macos-arm64.tar.gz + executable: apple-cli-*-macos-arm64/bin/apple + runner: xcode-27 + validate: + if: always() + needs: [package, demo] + uses: computer-mcp/github-workflows/.github/workflows/result.yml@53ecce59bf7ed184528b2f7894c864f338932d37 + with: + needs-json: ${{ toJSON(needs) }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e21125..0609f78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,10 +13,6 @@ on: permissions: contents: read -concurrency: - group: release-${{ inputs.tag || github.ref_name }} - cancel-in-progress: false - jobs: build: runs-on: xcode-27 @@ -34,21 +30,15 @@ jobs: ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 persist-credentials: false - - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: | - .build/repositories - .build/checkouts - key: dependencies-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Package.resolved') }} - name: Build and accept the tagged archive id: candidate env: RELEASE_TAG: ${{ inputs.tag || github.ref_name }} run: | - Scripts/validate-public-content + scripts/validate-public-content python3 -B -m unittest discover -s Tests/ReleaseTools - Scripts/package-release --tag "$RELEASE_TAG" --jobs 2 - Scripts/verify-release --tag "$RELEASE_TAG" --run-tests --github-output + scripts/package-release --tag "$RELEASE_TAG" --jobs 2 + scripts/verify-release --tag "$RELEASE_TAG" --run-tests --github-output printf 'artifact_name=%s\n' "$CANDIDATE_ARTIFACT" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: @@ -85,4 +75,4 @@ jobs: GH_TOKEN: ${{ github.token }} RELEASE_TAG: ${{ needs.build.outputs.tag }} RELEASE_SOURCE_COMMIT: ${{ needs.build.outputs.source_commit }} - run: Scripts/publish-release + run: scripts/publish-release diff --git a/.github/workflows/source-policy.yml b/.github/workflows/source-policy.yml new file mode 100644 index 0000000..c15b4b9 --- /dev/null +++ b/.github/workflows/source-policy.yml @@ -0,0 +1,19 @@ +name: Source policy checks +on: + pull_request: + types: [opened, synchronize, reopened, edited] + push: + branches: [master] + merge_group: +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true +jobs: + policy: + uses: computer-mcp/github-workflows/.github/workflows/policy.yml@53ecce59bf7ed184528b2f7894c864f338932d37 + with: + declaration-revision: 5c54a40cb7953db7472ebbefd3db608036b7b3ab + path-exceptions: | + Tests/ReleaseTools/test_public_content.py diff --git a/AGENTS.md b/AGENTS.md index ef1893b..7a68f0c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -178,12 +178,6 @@ Current architecture truth lives in `Documentation/Architecture/`: facts into architecture truth. External sources are inputs for target-local reuse decisions, not the source of this repository's architecture. -## Brand Delivery - -README headers and the social preview come from the Computer MCP organization -`.github` repository through `.github/brand/brand.lock.json`. Update them only -with that repository's `python3 Brand/brand.py sync`; CI verifies the lock. - ## Implementation Boundary Keep target ownership independent. The package declares exactly two executable diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 658cd04..db5ebdf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,10 +50,10 @@ changes that touch scripts, tests, package manifests, or generated package contents, also run the repository package validation commands. ```bash -Scripts/validate-public-content -Scripts/validate-version +scripts/validate-public-content +scripts/validate-version python3 -B -m unittest discover -s Tests/ReleaseTools -Scripts/bootstrap +scripts/bootstrap xcrun swift build --force-resolved-versions xcrun swift test --force-resolved-versions ``` @@ -69,3 +69,10 @@ texts and `THIRD_PARTY_NOTICES.md` together. Version selection follows [VERSIONING](VERSIONING.md). See the [release reference](Documentation/Reference/Release.md) for candidate packaging, compatibility evidence and publishing boundaries. + +## Source Policy Exceptions + +`Tests/ReleaseTools/test_public_content.py` contains synthetic home-directory +paths to verify that public-content validation rejects machine-local paths in +documents and release artifacts while allowing test fixtures. The source policy +exempts this file from path checks; attribution checks still apply. diff --git a/Documentation/Brand/header-dark.png b/Documentation/Brand/header-dark.png deleted file mode 100644 index de8a2f4..0000000 Binary files a/Documentation/Brand/header-dark.png and /dev/null differ diff --git a/Documentation/Brand/header-light.png b/Documentation/Brand/header-light.png deleted file mode 100644 index 05a5858..0000000 Binary files a/Documentation/Brand/header-light.png and /dev/null differ diff --git a/Documentation/Reference/AppleCLIUserGuide.md b/Documentation/Reference/AppleCLIUserGuide.md index b87a814..efd9a97 100644 --- a/Documentation/Reference/AppleCLIUserGuide.md +++ b/Documentation/Reference/AppleCLIUserGuide.md @@ -19,7 +19,7 @@ apple --help When running from a development checkout, use: ```bash -Scripts/bootstrap +scripts/bootstrap swift run apple --help swift run apple --help ``` diff --git a/Documentation/Reference/FrameworkGeneration.md b/Documentation/Reference/FrameworkGeneration.md index a24caee..81a37ac 100644 --- a/Documentation/Reference/FrameworkGeneration.md +++ b/Documentation/Reference/FrameworkGeneration.md @@ -5,8 +5,8 @@ names. Their generation commands share an Objective-C declaration merger and retain separate module configurations: ```bash -Scripts/notes-private-framework-normalize-full-dump --dump-root --sources-root -Scripts/reminderkit-normalize-full-dump --dump-root --sources-root +scripts/notes-private-framework-normalize-full-dump --dump-root --sources-root +scripts/reminderkit-normalize-full-dump --dump-root --sources-root ``` Notes generates `NotesSupport`, `NotesHTML`, `NotesShared`, `NotesUI`, @@ -20,7 +20,7 @@ Use exactly one of `--dump-root` and `--input-manifest`. A versioned manifest follows [FrameworkInputManifest.schema.json](FrameworkInputManifest.schema.json): ```bash -Scripts/notes-private-framework-normalize-full-dump \ +scripts/notes-private-framework-normalize-full-dump \ --input-manifest \ --sources-root \ --report diff --git a/Documentation/Reference/Notes/DeveloperGuide.md b/Documentation/Reference/Notes/DeveloperGuide.md index 96abe41..91a0cb8 100644 --- a/Documentation/Reference/Notes/DeveloperGuide.md +++ b/Documentation/Reference/Notes/DeveloperGuide.md @@ -34,7 +34,7 @@ checks, and post-write verification. Direct Notes SQLite writes are rejected. The current intake path follows the Reminders pattern: ```bash -Scripts/notes-private-framework-normalize-full-dump \ +scripts/notes-private-framework-normalize-full-dump \ --dump-root \ --sources-root Sources ``` @@ -58,7 +58,7 @@ when direct linking needs SDK allowed-client metadata removed. The overlays must preserve system framework install names and should be audited before production code relies on direct typed private class references. -From the repository root, run `Scripts/bootstrap` before the first build. +From the repository root, run `scripts/bootstrap` before the first build. The default Notes target links the generated framework stub overlay at `.build/notes-private-framework-link-stubs/current`. Bootstrap uses the selected Xcode SDK, preserves system install names, and records SDK/toolchain and input diff --git a/Documentation/Reference/Photos/DeveloperGuide.md b/Documentation/Reference/Photos/DeveloperGuide.md index 4c4fcd6..3cf4dc6 100644 --- a/Documentation/Reference/Photos/DeveloperGuide.md +++ b/Documentation/Reference/Photos/DeveloperGuide.md @@ -11,7 +11,7 @@ The current command surface and safety gates are documented in From the repository root, run: ```bash -Scripts/bootstrap +scripts/bootstrap xcrun swift test --filter Photos --force-resolved-versions ``` diff --git a/Documentation/Reference/Release.md b/Documentation/Reference/Release.md index 0598d2f..60136e5 100644 --- a/Documentation/Reference/Release.md +++ b/Documentation/Reference/Release.md @@ -1,9 +1,9 @@ # Release Release status: packaging, archive acceptance and GitHub publication are -implemented by [package-release](https://github.com/computer-mcp/apple-cli/blob/master/Scripts/package-release), -[verify-release](https://github.com/computer-mcp/apple-cli/blob/master/Scripts/verify-release), -[publish-release](https://github.com/computer-mcp/apple-cli/blob/master/Scripts/publish-release) +implemented by [package-release](https://github.com/computer-mcp/apple-cli/blob/master/scripts/package-release), +[verify-release](https://github.com/computer-mcp/apple-cli/blob/master/scripts/verify-release), +[publish-release](https://github.com/computer-mcp/apple-cli/blob/master/scripts/publish-release) and the [release workflow](https://github.com/computer-mcp/apple-cli/blob/master/.github/workflows/release.yml). Version selection, compatibility review and tag signature verification are manual. @@ -19,7 +19,7 @@ dependencies and target-specific validation limits. | Shipped component | Version meaning | Version source | Mirrors and derived fields | Update and read-only check | | --- | --- | --- | --- | --- | -| `apple` and its target commands | Shared product version | `CLIVersion.current` in `Sources/Utility/CLIVersion.swift` | `apple --version`, archive identity and provenance | Edit the declaration manually; `Scripts/validate-version`; `CLIExecutableTests` | +| `apple` and its target commands | Shared product version | `CLIVersion.current` in `Sources/Utility/CLIVersion.swift` | `apple --version`, archive identity and provenance | Edit the declaration manually; `scripts/validate-version`; `CLIExecutableTests` | | `apple-cli-mcp` | Same product version | The same `CLIVersion.current` | `apple-cli-mcp --version`, MCP initialization `serverInfo.version` | Same declaration; `CLIExecutableTests`, `AppleMCPAdapterTests` and `MCPExecutableTests` | Both executable products release together. Target modules and source skills @@ -100,17 +100,17 @@ and need compatibility, lockfile and dependency-notice review. | Field or artifact | Authority and production | Read-only verification | | --- | --- | --- | | Executable version and MCP `serverInfo.version` | Compiled from `CLIVersion.current` | Executable and MCP initialization tests; packager checks both staged `--version` results | -| Release notes | Matching entry in `CHANGELOG.md`; publisher renders that entry and source/Actions links | `Scripts/validate-version [--tag TAG]` and publisher input validation | -| Archive basename | `apple-cli-VERSION-macos-arm64`, derived by `Scripts/package-release` | `Scripts/verify-release` compares names, source version, tag and architecture | +| Release notes | Matching entry in `CHANGELOG.md`; publisher renders that entry and source/Actions links | `scripts/validate-version [--tag TAG]` and publisher input validation | +| Archive basename | `apple-cli-VERSION-macos-arm64`, derived by `scripts/package-release` | `scripts/verify-release` compares names, source version, tag and architecture | | `.provenance.json` and embedded `provenance.json` | Packager records source commit/tree, lock digest and dependencies, environment, link inputs, linked libraries, run paths, binary/runtime hashes and successful validation-log hashes | Verifier checks source identity, lock digest, required checks, archive contents and embedded/adjacent manifest equality, apart from the adjacent archive digest | | `.tar.gz.sha256` | Packager hashes the archive bytes | Verifier recomputes the archive digest and exact checksum contents | -| `.verification.json` | `Scripts/verify-release --run-tests` records archive/provenance/checksum hashes, checker hash, tested environment, successful checks and test-log digest; Actions adds run identity | `Scripts/verify-release --require-verification` checks identity, hashes, required checks and positive test/suite counts | +| `.verification.json` | `scripts/verify-release --run-tests` records archive/provenance/checksum hashes, checker hash, tested environment, successful checks and test-log digest; Actions adds run identity | `scripts/verify-release --require-verification` checks identity, hashes, required checks and positive test/suite counts | Provenance and verification receipts use `schema_version: 1`. Provenance also records a build timestamp. Build timestamps and compiler output can vary; the packager does not claim bit-for-bit rebuilds. -[Scripts/validate-version](https://github.com/computer-mcp/apple-cli/blob/master/Scripts/validate-version) +[scripts/validate-version](https://github.com/computer-mcp/apple-cli/blob/master/scripts/validate-version) requires exactly one canonical declaration in the supported version format. For untagged validation, a changelog whose sole section is `Unreleased` may be empty. Otherwise it requires exactly one nonempty entry for the product @@ -131,8 +131,8 @@ repository, source, artifact or receipt identity fails validation. then run the source gates: ```bash - Scripts/validate-version --json - Scripts/validate-public-content + scripts/validate-version --json + scripts/validate-public-content python3 -B -m unittest discover -s Tests/ReleaseTools ``` @@ -140,8 +140,8 @@ repository, source, artifact or receipt identity fails validation. dependency notices. From its clean checkout, build and accept the archive: ```bash - Scripts/package-release --jobs 2 - Scripts/verify-release --run-tests + scripts/package-release --jobs 2 + scripts/verify-release --run-tests ``` The packager bootstraps SDK link inputs, builds tests, runs default @@ -168,8 +168,8 @@ repository, source, artifact or receipt identity fails validation. to both shared steps: ```bash - Scripts/package-release --tag vVERSION --jobs 2 - Scripts/verify-release --tag vVERSION --run-tests + scripts/package-release --tag vVERSION --jobs 2 + scripts/verify-release --tag vVERSION --run-tests ``` Packaging creates no tag, remote push or GitHub release. CI runs the source @@ -190,7 +190,7 @@ repository, source, artifact or receipt identity fails validation. prerelease flag. The publication step does not rebuild or re-sign. The release scripts require Python 3.12 or newer for archive validation. -`Scripts/verify-release --require-verification` checks accepted files and the +`scripts/verify-release --require-verification` checks accepted files and the receipt without executing macOS programs, as used by the Linux publisher. Local candidate acceptance is development evidence; formal publication requires the release workflow's accepted files and run identity. Installation and @@ -243,12 +243,12 @@ values. | Operation | Existing command or explicit manual procedure | Required access | | --- | --- | --- | -| Version update and check | Manually edit `CLIVersion.current` and changelog; `Scripts/validate-version [--tag TAG] [--json]`. Automated version selection/update is not established. | Source write for edits; read for validation | -| Source/documentation checks | `Scripts/validate-public-content`; `python3 -B -m unittest discover -s Tests/ReleaseTools` | Source read; temporary fixture writes; Swift toolchain | -| Candidate validation and build | `Scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT]`, then `Scripts/verify-release [--directory DIRECTORY] [--tag TAG] --run-tests` | Clean source; native macOS arm64, Xcode/SDK and writable build output | -| Existing accepted-file check | `Scripts/verify-release [--directory DIRECTORY] [--tag TAG] --require-verification` | Clean matching source and artifact read; Python 3.12+ | +| Version update and check | Manually edit `CLIVersion.current` and changelog; `scripts/validate-version [--tag TAG] [--json]`. Automated version selection/update is not established. | Source write for edits; read for validation | +| Source/documentation checks | `scripts/validate-public-content`; `python3 -B -m unittest discover -s Tests/ReleaseTools` | Source read; temporary fixture writes; Swift toolchain | +| Candidate validation and build | `scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT]`, then `scripts/verify-release [--directory DIRECTORY] [--tag TAG] --run-tests` | Clean source; native macOS arm64, Xcode/SDK and writable build output | +| Existing accepted-file check | `scripts/verify-release [--directory DIRECTORY] [--tag TAG] --require-verification` | Clean matching source and artifact read; Python 3.12+ | | Status and interrupted-run recovery | Inspect the Actions run and artifact manually; rerun its failed publication job with the original accepted files. A standalone status/recovery command is not established. | Actions read; workflow rerun permission | -| Acceptance and publication | Existing-tag release workflow; its publish job invokes `Scripts/publish-release [--directory DIRECTORY]` | Workflow environment, accepted artifact and scoped GitHub release write | +| Acceptance and publication | Existing-tag release workflow; its publish job invokes `scripts/publish-release [--directory DIRECTORY]` | Workflow environment, accepted artifact and scoped GitHub release write | | Cleanup | Manually inventory and remove owned reproducible output; no cleanup command is established. | Write access to the owned output | Output defaults to `.build/releases`. One verification directory contains just diff --git a/Documentation/Reference/ReleaseGuide.md b/Documentation/Reference/ReleaseGuide.md index 934040c..4fcd6b3 100644 --- a/Documentation/Reference/ReleaseGuide.md +++ b/Documentation/Reference/ReleaseGuide.md @@ -58,7 +58,7 @@ Keep the same selected Xcode for bootstrap and build. `DEVELOPER_DIR`, when set, selects it for both scripts and `xcrun` commands. ```bash -Scripts/bootstrap +scripts/bootstrap xcrun swift build --force-resolved-versions xcrun swift test --force-resolved-versions xcrun swift build -c release --force-resolved-versions diff --git a/Documentation/Reference/Reminders/DeveloperGuide.md b/Documentation/Reference/Reminders/DeveloperGuide.md index b0902fc..ed2509e 100644 --- a/Documentation/Reference/Reminders/DeveloperGuide.md +++ b/Documentation/Reference/Reminders/DeveloperGuide.md @@ -8,7 +8,7 @@ Ordinary usage lives in `UserGuide.md`. ## Framework Header Generation -`Scripts/reminderkit-normalize-full-dump` generates the official `ReminderKit` +`scripts/reminderkit-normalize-full-dump` generates the official `ReminderKit` and `ReminderKitInternal` module surfaces from one dump or a digest-checked versioned input manifest. It shares declaration merging and complete output publication with the Notes generation command. See [Framework Header Generation](../FrameworkGeneration.md) diff --git a/Documentation/Reference/Safari/DeveloperGuide.md b/Documentation/Reference/Safari/DeveloperGuide.md index 355d87f..104a01c 100644 --- a/Documentation/Reference/Safari/DeveloperGuide.md +++ b/Documentation/Reference/Safari/DeveloperGuide.md @@ -7,7 +7,7 @@ listed in [Capability List](../../Architecture/Safari/CapabilityList.md). ## Package-Local Tests ```bash -Scripts/bootstrap +scripts/bootstrap xcrun swift test --filter Safari --force-resolved-versions ``` diff --git a/README.md b/README.md index d7da6eb..fd453a6 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,54 @@ - - - Computer MCP — Apple CLI: local Apple app automation through CLI and MCP - +

+ + + + +

+ +

Apple CLI

+ +

A local macOS CLI and MCP server for Apple apps.

+ +

+ CI + Swift 6.3 or newer + Platform: macOS arm64 + License: Apache-2.0 +

+ +

+ Install · + Usage · + Targets · + MCP · + Documentation +

+ +## Overview + +Apple apps, from your terminal. `apple` brings Notes, Reminders, Calendar, Mail, Photos and other +Apple app and system targets to one macOS command, with structured JSON output and an optional MCP +server for local agents. -# apple-cli +- **Script everyday workflows.** Search Notes, organize Reminders, inspect calendars, query + Photos and work with local files. +- **Use predictable output.** JSON results, stable error codes and bounded reads make commands + usable in scripts. +- **Connect your agent.** The MCP server exposes the same CLI capabilities through stdio or + Streamable HTTP. -Apple apps, from your terminal. `apple-cli` brings 19 Apple app and system -targets to one macOS command, with structured JSON output and an optional MCP -server for local agents. +> **Alpha preview · macOS arm64.** Feature availability depends on the target, OS, account and +> permissions. See the [Release Guide](Documentation/Reference/ReleaseGuide.md) for the tested +> build environment and installation details. -[Install](#install) · [Quick start](#quick-start) · [Targets](#targets) · -[MCP](#mcp) · [Documentation](#documentation) +## Quick look -> **Alpha preview · macOS arm64.** Feature availability depends on the target, -> OS, account and permissions. See the [Release Guide](Documentation/Reference/ReleaseGuide.md) -> for the tested build environment and installation details. + + + apple --version prints the version, and apple notifications preview returns the notification it would show as JSON without sending it. + -- **Script everyday workflows.** Search Notes, organize Reminders, inspect - calendars, query Photos and work with local files. -- **Use predictable output.** JSON results, stable error codes and bounded - reads make commands usable in scripts. -- **Connect your agent.** The MCP server exposes the same CLI capabilities - through stdio or Streamable HTTP. +Every command follows one shape: ~~~text apple [options] @@ -29,55 +56,49 @@ apple [options] ## Install -### Homebrew +### Build from source -On macOS arm64, install from the organization tap: +Use macOS with an Xcode toolchain providing Swift 6.3 or newer and the Notes private frameworks +required by the package. From the repository root: ~~~bash -brew install computer-mcp/tap/apple-cli -apple --version +scripts/bootstrap +xcrun swift build --force-resolved-versions +.build/debug/apple --help ~~~ -The [Homebrew tap](https://github.com/computer-mcp/homebrew-tap) installs both -executables and their runtime libraries from the accepted GitHub release. -Its formula declares the tested macOS requirement. +Rerun `scripts/bootstrap` after changing Xcode or the SDK. The declared macOS 13 deployment floor +is a build setting; runtime support requires validation on the intended OS and architecture. -### Release archive +### Releases -Download the macOS arm64 archive and its checksum from -[GitHub Releases](https://github.com/computer-mcp/apple-cli/releases). -Release archives are built, tested and published by GitHub Actions. +No release has been published yet. From the first release, two channels install it on macOS +arm64. -Run these commands in the download directory, replacing `VERSION` with the -version you downloaded: +**Homebrew**, from the organization tap, which installs both executables and their runtime +libraries from the accepted GitHub release and declares the tested macOS requirement: ~~~bash -shasum -a 256 -c apple-cli-VERSION-macos-arm64.tar.gz.sha256 -tar -xzf apple-cli-VERSION-macos-arm64.tar.gz -export PATH="$PWD/apple-cli-VERSION-macos-arm64/bin:$PATH" +brew install computer-mcp/tap/apple-cli apple --version ~~~ -Keep the complete `bin` directory together: `apple`, `apple-cli-mcp` and any -bundled Swift runtime libraries. The [Release Guide](Documentation/Reference/ReleaseGuide.md#install-the-archive) -covers relocation, signatures and compatibility. - -### Build from source - -Use macOS with an Xcode toolchain providing Swift 6.3 or newer and the Notes -private frameworks required by the package. From the repository root: +**Release archive**, built, tested and published by GitHub Actions on +[GitHub Releases](https://github.com/computer-mcp/apple-cli/releases). In the download directory, +replacing `VERSION`: ~~~bash -Scripts/bootstrap -xcrun swift build --force-resolved-versions -.build/debug/apple --help +shasum -a 256 -c apple-cli-VERSION-macos-arm64.tar.gz.sha256 +tar -xzf apple-cli-VERSION-macos-arm64.tar.gz +export PATH="$PWD/apple-cli-VERSION-macos-arm64/bin:$PATH" +apple --version ~~~ -Rerun `Scripts/bootstrap` after changing Xcode or the SDK. The declared -macOS 13 deployment floor is a build setting; runtime support requires -validation on the intended OS and architecture. +Keep the complete `bin` directory together: `apple`, `apple-cli-mcp` and any bundled Swift runtime +libraries. The [Release Guide](Documentation/Reference/ReleaseGuide.md#install-the-archive) covers +relocation, signatures and compatibility. -## Quick start +## Usage Discover a target and check its readiness: @@ -114,31 +135,19 @@ apple reminders create --list Today --title "Follow up" --json ### Structured output -`--json` returns an envelope with `ok` and `data`. Errors use `ok: false` and a -stable `error.code`. Add `--pretty` for readable formatting. +`--json` returns an envelope with `ok` and `data`. Errors use `ok: false` and a stable +`error.code`. Add `--pretty` for readable formatting. The Quick look's notification preview works +without accessing app data or sending a notification. -This preview works without accessing app data or sending a notification: +### Permissions and writes -~~~bash -apple notifications preview --title Build --body Done --json --pretty -~~~ +Start with `apple doctor --json` when a target cannot access an app or its data. Some +workflows need macOS permissions or app automation approval. -~~~json -{ - "data": { - "externalAction": false, - "notification": { - "body": "Done", - "title": "Build" - } - }, - "meta": { - "target": "notifications" - }, - "ok": true, - "warnings": [] -} -~~~ +Use `--dry-run` to inspect a proposed mutation. External dispatch, destructive selections and +system operations require the specific `--allow-*` flag named by the command. `--json` controls +output; authorization comes from the requested operation and its gates. See +[Safety Gates](Documentation/Reference/SafetyGates.md) for the full contract. ## Targets @@ -152,36 +161,32 @@ Choose a target to open its user guide: | Documents | [`pages`](Documentation/Reference/Pages/UserGuide.md) · [`numbers`](Documentation/Reference/Numbers/UserGuide.md) · [`keynote`](Documentation/Reference/Keynote/UserGuide.md) | | System utilities | [`print`](Documentation/Reference/Print/UserGuide.md) · [`clipboard`](Documentation/Reference/Clipboard/UserGuide.md) · [`notifications`](Documentation/Reference/Notifications/UserGuide.md) · [`intelligence`](Documentation/Reference/Intelligence/UserGuide.md) · [`tcc`](Documentation/Reference/TCC/UserGuide.md) | -Coverage varies by target. Pages focuses on metadata and export; Keynote -supports native slide reads and PDF export alongside cached previews. Numbers -supports reads, exports and single-cell writes. Safari Tab Group -mutations and some Notes media workflows return an explicit unsupported result. -Read the [Capability List](Documentation/Architecture/CapabilityList.md) for -the supported scope of each target. +Coverage varies by target. Pages focuses on metadata and export; Keynote supports native slide +reads and PDF export alongside cached previews. Numbers supports reads, exports and single-cell +writes. Safari Tab Group mutations and some Notes media workflows return an explicit unsupported +result. Read the [Capability List](Documentation/Architecture/CapabilityList.md) for the supported +scope of each target. ## MCP -`apple-cli-mcp` connects local MCP clients to the `apple` CLI. Configure your -client with the full path to the installed executable and `stdio` as its -argument: +`apple-cli-mcp` connects local MCP clients to the `apple` CLI. Configure your client with the full +path to the executable and `stdio` as its argument: | Client setting | Value | | --- | --- | | Command | `/path/to/extracted-release/bin/apple-cli-mcp` | | Arguments | `stdio` | -For Homebrew, get the full command path with -`echo "$(brew --prefix)/bin/apple-cli-mcp"`. - -To start the server directly: +For Homebrew, get the full command path with `echo "$(brew --prefix)/bin/apple-cli-mcp"`. To start +the server directly: ~~~bash apple-cli-mcp stdio ~~~ -The adapter finds `apple` beside its own executable. Keep both programs and -the bundled runtime libraries together. For a separate CLI directory, set -`APPLE_CLI_BIN_DIR` to the directory containing `apple`. +The adapter finds `apple` beside its own executable. Keep both programs and the bundled runtime +libraries together. For a separate CLI directory, set `APPLE_CLI_BIN_DIR` to the directory +containing `apple`. Streamable HTTP is also available on loopback: @@ -190,53 +195,46 @@ apple-cli-mcp serve http --host 127.0.0.1 --port 8765 --path /mcp ~~~ The same target permissions and mutation gates apply through MCP. See -[MCP setup](Documentation/Reference/AppleCLIUserGuide.md#mcp-setup) for discovery, -remote access and authentication. - -The source tree also includes a [Reminder Creator skill](skills/reminder-creator/SKILL.md) -for modeling reminder content, lists, sections and shopping workflows. -See its [shopping reference](skills/reminder-creator/references/shopping-list.md) -for scenario guidance. - -## Permissions and writes - -Start with `apple doctor --json` when a target cannot access an app -or its data. Some workflows need macOS permissions or app automation approval. +[MCP setup](Documentation/Reference/AppleCLIUserGuide.md#mcp-setup) for discovery, remote access and +authentication. -Use `--dry-run` to inspect a proposed mutation. External dispatch, destructive -selections and system operations require the specific `--allow-*` flag named -by the command. `--json` controls output; authorization comes from the requested -operation and its gates. See [Safety Gates](Documentation/Reference/SafetyGates.md) -for the full contract. +The source tree also includes a [Reminder Creator skill](skills/reminder-creator/SKILL.md) for +modeling reminder content, lists, sections and shopping workflows. See its +[shopping reference](skills/reminder-creator/references/shopping-list.md) for scenario guidance. -## Development +## Requirements -~~~bash -Scripts/bootstrap -xcrun swift test --force-resolved-versions -Scripts/validate-public-content -~~~ - -The default suite uses fixtures and controlled backends. Real app behavior, -accounts and OS compatibility need separate validation; the -[Release Guide](Documentation/Reference/ReleaseGuide.md#build-from-source) -describes the available integration checks. +- macOS on arm64, the tested runtime; see the [Release Guide](Documentation/Reference/ReleaseGuide.md). +- To build: an Xcode toolchain with Swift 6.3 or newer and the Notes private frameworks the + package requires. +- Per target: the macOS permissions or app automation approval its workflows need. ## Documentation | Start here | What it covers | | --- | --- | | [User guide](Documentation/Reference/AppleCLIUserGuide.md) | Discovery, output, permissions, MCP and workflow safety | -| [Target guides](Documentation/README.md#target-guides) | User and developer documentation for all 19 targets | +| [Target guides](Documentation/README.md#target-guides) | User and developer documentation for every target | | [Release guide](Documentation/Reference/ReleaseGuide.md) | Installation, source builds and runtime requirements | | [Release reference](Documentation/Reference/Release.md) | Version sources, candidate acceptance, CI publication and evidence | | [Version rules](VERSIONING.md) | Organization version rules and repository acceptance requirements | | [Architecture](Documentation/Architecture/README.md) | CLI ownership, implementation mechanisms and MCP boundaries | -| [Contributing](CONTRIBUTING.md) | Repository conventions and validation | | [Security](SECURITY.md) | Vulnerability reporting | +## Contributing + +~~~bash +scripts/bootstrap +xcrun swift test --force-resolved-versions +scripts/validate-public-content +~~~ + +The default suite uses fixtures and controlled backends. Real app behavior, accounts and OS +compatibility need separate validation; the +[Release Guide](Documentation/Reference/ReleaseGuide.md#build-from-source) describes the available +integration checks. See the [contributor guide](CONTRIBUTING.md) for repository conventions. + ## License -Copyright (c) 2026 Xudong Xu. Licensed under the [Apache License 2.0](LICENSE). -Third-party components retain their own licenses; see -[Third-Party Notices](THIRD_PARTY_NOTICES.md). +Copyright (c) 2026 Xudong Xu. Licensed under the [Apache License 2.0](LICENSE). Third-party +components retain their own licenses; see [Third-Party Notices](THIRD_PARTY_NOTICES.md). diff --git a/Tests/AppleCLITests/FrameworkNormalizationTests.swift b/Tests/AppleCLITests/FrameworkNormalizationTests.swift index 4f41fd7..5c022c8 100644 --- a/Tests/AppleCLITests/FrameworkNormalizationTests.swift +++ b/Tests/AppleCLITests/FrameworkNormalizationTests.swift @@ -450,7 +450,7 @@ struct NormalizationFixture { .deletingLastPathComponent().deletingLastPathComponent() return try CLISubprocess.run( .path("/usr/bin/xcrun"), - arguments: ["swift", repository.appendingPathComponent("Scripts/\(profile.script)").path, + arguments: ["swift", repository.appendingPathComponent("scripts/\(profile.script)").path, "--sources-root", (sourcesRoot ?? output).path] + (inputManifest.map { ["--input-manifest", $0.path] } ?? ["--dump-root", dump.path]) + extra, timeoutSeconds: 90) } diff --git a/Tests/ReleaseTools/test_archive_documents.py b/Tests/ReleaseTools/test_archive_documents.py index d65d5c8..22af13e 100644 --- a/Tests/ReleaseTools/test_archive_documents.py +++ b/Tests/ReleaseTools/test_archive_documents.py @@ -11,7 +11,7 @@ SOURCE = Path(__file__).resolve().parents[2] -checker = runpy.run_path(str(SOURCE / "Scripts/verify-release")) +checker = runpy.run_path(str(SOURCE / "scripts/verify-release")) VALIDATION_DOCUMENTS = [ "Documentation/Reference/Release.md", "VERSIONING.md", diff --git a/Tests/ReleaseTools/test_public_content.py b/Tests/ReleaseTools/test_public_content.py index 9211102..9e33d2f 100644 --- a/Tests/ReleaseTools/test_public_content.py +++ b/Tests/ReleaseTools/test_public_content.py @@ -17,9 +17,9 @@ def setUp(self): self.root = Path(temporary.name) / "repository" self.outside = Path(temporary.name) / "artifacts" self.outside.mkdir() - script = self.root / "Scripts/validate-public-content" + script = self.root / "scripts/validate-public-content" script.parent.mkdir(parents=True) - shutil.copy2(SOURCE / "Scripts/validate-public-content", script) + shutil.copy2(SOURCE / "scripts/validate-public-content", script) self.write("README.md", "[Guide](Documentation/Guide.md)\n") self.write("Documentation/Guide.md", "Run `apple --help`.\n") subprocess.run(["git", "init", "--quiet"], cwd=self.root, check=True) @@ -31,7 +31,7 @@ def write(self, name, text): def scan(self, *arguments): return subprocess.run( - ["swift", str(self.root / "Scripts/validate-public-content"), *arguments], + ["swift", str(self.root / "scripts/validate-public-content"), *arguments], cwd=self.root, capture_output=True, text=True, timeout=600, ) @@ -45,7 +45,7 @@ def test_reports_every_finding(self): # Assembled at runtime so this file does not match the credential scan. token = "gh" + "p_" + "A" * 36 self.write("Documentation/Setup.md", "Run from /Users/jane/project.\n\n[Missing](Missing.md)\n") - self.write("Scripts/configure", "TOKEN=" + token + "\n") + self.write("scripts/configure", "TOKEN=" + token + "\n") self.write("Sources/Version.swift", 'let version = "0.0.0-dev"\n') artifact = self.outside / "release-notes.txt" artifact.write_text("Built in /Users/jane/build.\n") @@ -54,8 +54,8 @@ def test_reports_every_finding(self): self.assertEqual(result.stderr.splitlines(), [ "Documentation/Setup.md: machine-local absolute path", "Documentation/Setup.md: missing local link Missing.md", - "Scripts/configure: credential pattern requires review", "Sources/Version.swift: development version bypasses the canonical version", + "scripts/configure: credential pattern requires review", "release-notes.txt: release artifact contains a machine-local path", ]) diff --git a/Tests/ReleaseTools/test_publication.py b/Tests/ReleaseTools/test_publication.py index 4f088d4..10ff151 100644 --- a/Tests/ReleaseTools/test_publication.py +++ b/Tests/ReleaseTools/test_publication.py @@ -9,7 +9,7 @@ ROOT = Path(__file__).resolve().parents[2] -LOADER = importlib.machinery.SourceFileLoader("release_publication", str(ROOT / "Scripts/publish-release")) +LOADER = importlib.machinery.SourceFileLoader("release_publication", str(ROOT / "scripts/publish-release")) SPEC = importlib.util.spec_from_loader(LOADER.name, LOADER) publisher = importlib.util.module_from_spec(SPEC) LOADER.exec_module(publisher) diff --git a/Tests/ReleaseTools/test_version_inputs.py b/Tests/ReleaseTools/test_version_inputs.py index 6ff0031..0c3fcee 100644 --- a/Tests/ReleaseTools/test_version_inputs.py +++ b/Tests/ReleaseTools/test_version_inputs.py @@ -10,7 +10,7 @@ SOURCE = Path(__file__).resolve().parents[2] -checker = runpy.run_path(str(SOURCE / "Scripts/verify-release")) +checker = runpy.run_path(str(SOURCE / "scripts/verify-release")) validate = checker["validate_version_inputs"] @@ -162,7 +162,7 @@ def test_rejects_tag_on_another_commit(self): def test_cli_returns_metadata_without_modifying_source(self): before = {path: path.read_bytes() for path in [self.version_file, self.changelog]} result = subprocess.run( - [sys.executable, str(SOURCE / "Scripts/validate-version"), "--source", str(self.source), "--json"], + [sys.executable, str(SOURCE / "scripts/validate-version"), "--source", str(self.source), "--json"], check=True, text=True, capture_output=True, ) self.assertEqual(json.loads(result.stdout), { @@ -175,7 +175,7 @@ def test_cli_fails_without_repairing_invalid_inputs(self): self.write_source("0.1.0-alpha.01") before = self.version_file.read_bytes() result = subprocess.run( - [sys.executable, str(SOURCE / "Scripts/validate-version"), "--source", str(self.source)], + [sys.executable, str(SOURCE / "scripts/validate-version"), "--source", str(self.source)], text=True, capture_output=True, ) self.assertEqual(result.returncode, 1) @@ -189,7 +189,7 @@ def test_publisher_uses_the_same_notes_entry_as_preflight(self): "[Guide](Documentation/Reference/ReleaseGuide.md)\n\n## 0.0.1\n\nOld changes.\n", ) self.assertEqual(validate(self.source), "0.1.0-alpha.1") - publisher = runpy.run_path(str(SOURCE / "Scripts/publish-release")) + publisher = runpy.run_path(str(SOURCE / "scripts/publish-release")) notes = publisher["release_notes"] notes.__globals__["SOURCE"] = self.source body = notes({ diff --git a/Scripts/bootstrap b/scripts/bootstrap similarity index 91% rename from Scripts/bootstrap rename to scripts/bootstrap index 3c9b25f..d90ca35 100755 --- a/Scripts/bootstrap +++ b/scripts/bootstrap @@ -12,5 +12,5 @@ fi task_sdk=$(/usr/bin/xcrun --sdk macosx --show-sdk-path) task_output=${APPLE_CLI_NOTES_PRIVATE_FRAMEWORK_STUBS:-"$task_root/.build/notes-private-framework-link-stubs/current"} cd "$task_root" -/usr/bin/xcrun swift Scripts/notes-private-framework-generate-link-stubs \ +/usr/bin/xcrun swift scripts/notes-private-framework-generate-link-stubs \ --sdk-root "$task_sdk" --output-root "$task_output" diff --git a/Scripts/framework-normalize-full-dump b/scripts/framework-normalize-full-dump similarity index 100% rename from Scripts/framework-normalize-full-dump rename to scripts/framework-normalize-full-dump diff --git a/Scripts/notes-private-framework-generate-link-stubs b/scripts/notes-private-framework-generate-link-stubs similarity index 98% rename from Scripts/notes-private-framework-generate-link-stubs rename to scripts/notes-private-framework-generate-link-stubs index 6f193e9..975e840 100755 --- a/Scripts/notes-private-framework-generate-link-stubs +++ b/scripts/notes-private-framework-generate-link-stubs @@ -18,7 +18,7 @@ struct StubError: LocalizedError { func usage() { print(""" Usage: - Scripts/notes-private-framework-generate-link-stubs [--sdk-root ] [--output-root ] [--framework ]... + scripts/notes-private-framework-generate-link-stubs [--sdk-root ] [--output-root ] [--framework ]... Generates local Notes link inputs from the selected macOS SDK, preserving system install names and removing allowed/allowable-client restrictions. @@ -76,7 +76,7 @@ func sourceTBD(_ framework: String, sdk: URL) throws -> URL { let candidate = root.appendingPathComponent(suffix) if FileManager.default.fileExists(atPath: candidate.path) { return candidate } } - throw StubError("Selected SDK \(sdk.path) is missing \(framework).tbd. Select an SDK containing all six Notes frameworks, then rerun Scripts/bootstrap.") + throw StubError("Selected SDK \(sdk.path) is missing \(framework).tbd. Select an SDK containing all six Notes frameworks, then rerun scripts/bootstrap.") } func removingAllowedClients(_ text: String) -> (text: String, removed: Int) { diff --git a/Scripts/notes-private-framework-normalize-full-dump b/scripts/notes-private-framework-normalize-full-dump similarity index 100% rename from Scripts/notes-private-framework-normalize-full-dump rename to scripts/notes-private-framework-normalize-full-dump diff --git a/Scripts/package-release b/scripts/package-release similarity index 98% rename from Scripts/package-release rename to scripts/package-release index f74f35a..577f1c4 100755 --- a/Scripts/package-release +++ b/scripts/package-release @@ -138,7 +138,7 @@ func main() throws { if option == "--help" || option == "-h" { message( """ - Usage: Scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT] + Usage: scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT] Build and test a clean, committed source candidate and create a macOS arm64 archive, SHA-256 checksum, and provenance manifest. --tag verifies an existing tag at HEAD against the source version. @@ -174,7 +174,7 @@ func main() throws { throw ReleaseError.invalid("Missing release input: \(file).") } } - var versionArguments = ["python3", root.appendingPathComponent("Scripts/validate-version").path] + var versionArguments = ["python3", root.appendingPathComponent("scripts/validate-version").path] if let tag { versionArguments += ["--tag", tag] } let version = try run("/usr/bin/env", versionArguments) let architecture = try run("/usr/bin/uname", ["-m"]) @@ -213,7 +213,7 @@ func main() throws { validation.append(["check": label, "result": "passed", "log_sha256": try digest(log)]) } message("Bootstrap selected SDK inputs") - try run(root.appendingPathComponent("Scripts/bootstrap").path, []) + try run(root.appendingPathComponent("scripts/bootstrap").path, []) var testEnvironment = ProcessInfo.processInfo.environment testEnvironment.removeValue(forKey: "APPLE_CLI_RUN_NOTES_INTEGRATION_TESTS") testEnvironment.removeValue(forKey: "APPLE_CLI_BIN") @@ -310,7 +310,7 @@ func main() throws { } try validate( "installed-release-content", - ["swift", root.appendingPathComponent("Scripts/validate-public-content").path] + ["swift", root.appendingPathComponent("scripts/validate-public-content").path] + (["apple", "apple-cli-mcp"] + runtimeNames.sorted()).flatMap { ["--artifact", bin.appendingPathComponent($0).path] }, environment: testEnvironment) diff --git a/Scripts/publish-release b/scripts/publish-release similarity index 99% rename from Scripts/publish-release rename to scripts/publish-release index 69e97fe..e581267 100755 --- a/Scripts/publish-release +++ b/scripts/publish-release @@ -14,7 +14,7 @@ from urllib.parse import quote SOURCE = Path(__file__).resolve().parents[1] -checker = runpy.run_path(str(SOURCE / "Scripts/verify-release")) +checker = runpy.run_path(str(SOURCE / "scripts/verify-release")) require = checker["require"] digest = checker["digest"] diff --git a/Scripts/reminderkit-normalize-full-dump b/scripts/reminderkit-normalize-full-dump similarity index 100% rename from Scripts/reminderkit-normalize-full-dump rename to scripts/reminderkit-normalize-full-dump diff --git a/Scripts/validate-public-content b/scripts/validate-public-content similarity index 98% rename from Scripts/validate-public-content rename to scripts/validate-public-content index bf2560b..7b7782c 100755 --- a/Scripts/validate-public-content +++ b/scripts/validate-public-content @@ -10,7 +10,7 @@ do { var arguments = CommandLine.arguments.dropFirst().makeIterator() while let option = arguments.next() { if option == "--help" || option == "-h" { - print("Usage: Scripts/validate-public-content [--artifact FILE ...]") + print("Usage: scripts/validate-public-content [--artifact FILE ...]") print("Check public source files for credential/path patterns and local links; scan optional release artifacts for machine-local paths.") exit(0) } diff --git a/Scripts/validate-version b/scripts/validate-version similarity index 94% rename from Scripts/validate-version rename to scripts/validate-version index 6ee7d80..99c2329 100755 --- a/Scripts/validate-version +++ b/scripts/validate-version @@ -10,7 +10,7 @@ import sys SOURCE = Path(__file__).resolve().parents[1] -checker = runpy.run_path(str(SOURCE / "Scripts/verify-release")) +checker = runpy.run_path(str(SOURCE / "scripts/verify-release")) def main(): diff --git a/Scripts/verify-release b/scripts/verify-release similarity index 99% rename from Scripts/verify-release rename to scripts/verify-release index 7780792..b35c880 100755 --- a/Scripts/verify-release +++ b/scripts/verify-release @@ -172,7 +172,7 @@ def verify(directory, source, tag=None, require_verification=False): require(receipt["archive"] == {"filename": archive.name, "sha256": archive_hash}, "Verification archive digest mismatch") require(receipt["provenance"] == {"filename": manifest_path.name, "sha256": digest(manifest_path)}, "Verification provenance digest mismatch") require(receipt["checksum"] == {"filename": checksum.name, "sha256": digest(checksum)}, "Verification checksum digest mismatch") - require(receipt["checker"] == {"path": "Scripts/verify-release", "sha256": digest(Path(__file__))}, "Archive checker identity mismatch") + require(receipt["checker"] == {"path": "scripts/verify-release", "sha256": digest(Path(__file__))}, "Archive checker identity mismatch") checks_passed(receipt["validation"], ARCHIVE_CHECKS) require(receipt["artifact_content"] == {"files_scanned": files_scanned, "machine_local_path_matches": 0}, "Archive content receipt mismatch") test = next(item for item in receipt["validation"] if item["check"] == "unpacked-cli-and-mcp") @@ -217,7 +217,7 @@ def accept_executables(source, manifest, archive, manifest_path, checksum, verif "archive": {"filename": archive.name, "sha256": digest(archive)}, "provenance": {"filename": manifest_path.name, "sha256": digest(manifest_path)}, "checksum": {"filename": checksum.name, "sha256": digest(checksum)}, - "checker": {"path": "Scripts/verify-release", "sha256": digest(Path(__file__))}, + "checker": {"path": "scripts/verify-release", "sha256": digest(Path(__file__))}, "artifact_content": {"files_scanned": files_scanned, "machine_local_path_matches": 0}, "tested_macos": subprocess.check_output(["sw_vers", "-productVersion"], text=True).strip(), "architecture": platform.machine(),