@jenga-ai/agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +340 -0
- package/agents/ai_engineer.md +113 -0
- package/agents/developer.md +236 -0
- package/agents/scrum-master.md +349 -0
- package/agents/scrutiny-agent.md +137 -0
- package/agents/solution-assessor.md +185 -0
- package/agents/tester.md +339 -0
- package/bin/jenga.js +70 -0
- package/hooks/copilot_session_end.sh +29 -0
- package/hooks/on_session_end.sh +238 -0
- package/hooks/prompt_router.sh +11 -0
- package/hooks/prompt_router_helper.js +52 -0
- package/hooks/session_end_helper.js +29 -0
- package/hooks/session_end_watcher.sh +24 -0
- package/lib/commands/attach.js +47 -0
- package/lib/commands/init.js +207 -0
- package/lib/commands/start.js +16 -0
- package/lib/commands/status.js +53 -0
- package/lib/config-schema.js +72 -0
- package/lib/inject-settings.js +61 -0
- package/lib/mirror.js +244 -0
- package/lib/resolve-project-dir.sh +47 -0
- package/mcp/execute-ticket/index.js +10 -0
- package/mcp/execute-ticket/package.json +5 -0
- package/mcp/help/index.js +79 -0
- package/mcp/help/package.json +14 -0
- package/mcp/router/README.md +19 -0
- package/mcp/router/embedder.js +23 -0
- package/mcp/router/index.js +204 -0
- package/mcp/router/matcher.js +87 -0
- package/mcp/router/package-lock.json +1048 -0
- package/mcp/router/package.json +11 -0
- package/mcp/router/skill-index.js +104 -0
- package/package.json +47 -0
- package/scripts/board_resolver.sh +46 -0
- package/scripts/e25_s01_extract_board_graph.py +292 -0
- package/scripts/e25_s01_generate_synthetic_board.py +90 -0
- package/scripts/measurement-10x.json +50 -0
- package/scripts/measurement-10x.txt +4 -0
- package/scripts/measurement-real.json +50 -0
- package/scripts/measurement-real.txt +4 -0
- package/scripts/postinstall.js +165 -0
- package/scripts/todo_cleanup.sh +22 -0
- package/scripts/todo_manager.sh +86 -0
- package/scripts/validate-board.sh +190 -0
- package/scripts/validate-story-format.sh +53 -0
- package/skills/brainstorm/SKILL.md +47 -0
- package/skills/btw/SKILL.md +42 -0
- package/skills/commit/SKILL.md +29 -0
- package/skills/commit/assets/user_instructions_template.md +22 -0
- package/skills/continue/SKILL.md +29 -0
- package/skills/convert/SKILL.md +124 -0
- package/skills/convert/convert_cli.py +235 -0
- package/skills/convert/tests/sample.csv +4 -0
- package/skills/convert/tests/sample.json +5 -0
- package/skills/convert/tests/sample.jsonl +3 -0
- package/skills/convert/tests/sample.yaml +18 -0
- package/skills/convert/tests/sample_obj.csv +2 -0
- package/skills/convert/tests/sample_obj.json +9 -0
- package/skills/deep-dive/SKILL.md +167 -0
- package/skills/do/SKILL.md +88 -0
- package/skills/do/assets/sender_template.json +12 -0
- package/skills/doc/SKILL.md +314 -0
- package/skills/doc/assets/path-objectives.yaml +38 -0
- package/skills/doc-sync/SKILL.md +167 -0
- package/skills/doc-sync/assets/default_excludes.txt +21 -0
- package/skills/doc-sync/assets/doc_targets.md +14 -0
- package/skills/dooo/SKILL.md +60 -0
- package/skills/error/SKILL.md +29 -0
- package/skills/evaluate/SKILL.md +45 -0
- package/skills/evaluate/assets/evaluation_invokation_template.yml +3 -0
- package/skills/evaluate/assets/evaluation_rapport_template.md +24 -0
- package/skills/examplify/SKILL.md +42 -0
- package/skills/help/SKILL.md +36 -0
- package/skills/improve/SKILL.md +55 -0
- package/skills/index/scripts/board-index +4 -0
- package/skills/index/scripts/board_index.py +615 -0
- package/skills/index/scripts/smoke_test.sh +86 -0
- package/skills/init/SKILL.md +44 -0
- package/skills/init/assets/.gitignore_template +15 -0
- package/skills/init/assets/PROJECT_SUMMARY_template.md +13 -0
- package/skills/init/assets/directory_structure.txt +13 -0
- package/skills/init/assets/test-config_template.json +4 -0
- package/skills/init/assets/workflow_template.json +30 -0
- package/skills/init/scripts/init.sh +48 -0
- package/skills/jbp/SKILL.md +25 -0
- package/skills/jenga/SKILL.md +68 -0
- package/skills/lgtm/SKILL.md +21 -0
- package/skills/mirror-public/SKILL.md +237 -0
- package/skills/mirror-public/assets/config.json +5 -0
- package/skills/mirror-public/scripts/mirror.sh +374 -0
- package/skills/pi-plan/SKILL.md +62 -0
- package/skills/pi-plan/assets/epic.json +7 -0
- package/skills/pi-plan/assets/story_template.md +18 -0
- package/skills/proceed/SKILL.md +29 -0
- package/skills/publish/SKILL.md +351 -0
- package/skills/publish/adapters/droplet.md +200 -0
- package/skills/publish/adapters/mobile-ios.md +114 -0
- package/skills/publish/adapters/npm-ci.md +223 -0
- package/skills/publish/adapters/npm.md +121 -0
- package/skills/publish/assets/ExportOptions.plist.template +19 -0
- package/skills/publish/assets/ci-contract.md +111 -0
- package/skills/publish/assets/ownership-matrix.md +17 -0
- package/skills/publish/assets/publish.example.json +85 -0
- package/skills/publish/assets/publish.example.npm-ci.json +40 -0
- package/skills/publish/assets/publish.example.npm.json +41 -0
- package/skills/publish/assets/secrets-guide.md +104 -0
- package/skills/publish/schemas/fixtures/npm-ci-minimal.json +17 -0
- package/skills/publish/schemas/fixtures/npm-ci-with-empty-secrets.json +18 -0
- package/skills/publish/schemas/fixtures/npm-ci-with-workflow-path.json +18 -0
- package/skills/publish/schemas/publish.schema.json +428 -0
- package/skills/publish/scripts/check_target_config.sh +96 -0
- package/skills/publish/scripts/droplet_pipeline.sh +208 -0
- package/skills/publish/scripts/generate_release_notes.sh +200 -0
- package/skills/publish/scripts/ios_pipeline.sh +486 -0
- package/skills/publish/scripts/npm_ci_pipeline.sh +225 -0
- package/skills/publish/scripts/npm_pipeline.sh +249 -0
- package/skills/publish/scripts/publish_common.sh +253 -0
- package/skills/publish/scripts/publish_deploy.sh +538 -0
- package/skills/publish/scripts/reconcile_tags.sh +135 -0
- package/skills/publish/scripts/run_gates.sh +616 -0
- package/skills/publish/scripts/setup_wizard.sh +394 -0
- package/skills/publish/scripts/show_history.sh +95 -0
- package/skills/publish/scripts/suggest_semver_bump.sh +105 -0
- package/skills/publish/scripts/validate_config.sh +163 -0
- package/skills/publish/scripts/validate_droplet_env.sh +45 -0
- package/skills/publish/scripts/validate_ios_env.sh +68 -0
- package/skills/publish/scripts/validate_npm_ci_env.sh +71 -0
- package/skills/publish/scripts/validate_npm_env.sh +22 -0
- package/skills/publish/scripts/write_ledger_entry.sh +126 -0
- package/skills/publish/wizards/droplet.md +275 -0
- package/skills/publish/wizards/mobile-ios.md +157 -0
- package/skills/publish/wizards/npm-ci.md +240 -0
- package/skills/publish/wizards/npm.md +224 -0
- package/skills/reconcile/SKILL.md +93 -0
- package/skills/reconcile/assets/report_format.md +44 -0
- package/skills/reconcile-origin/SKILL.md +75 -0
- package/skills/reconcile-origin/scripts/reconcile-origin.sh +372 -0
- package/skills/redo/SKILL.md +70 -0
- package/skills/route/SKILL.md +180 -0
- package/skills/self-sync/SKILL.md +73 -0
- package/skills/self-sync/scripts/run.js +136 -0
- package/skills/skillify/SKILL.md +68 -0
- package/skills/skillify/assets/init-new/SKILL.md +35 -0
- package/skills/skillify/assets/init-new/assets/.gitignore_template +15 -0
- package/skills/skillify/assets/init-new/assets/PROJECT_SUMMARY_template.md +13 -0
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +10 -0
- package/skills/skillify/assets/init-new/assets/test-config_template.json +4 -0
- package/skills/skillify/assets/init-new/assets/workflow_template.json +17 -0
- package/skills/skillify/assets/init-new/scripts/init.sh +48 -0
- package/skills/skillify/assets/init-old/SKILL.md +124 -0
- package/skills/spinoff/SKILL.md +48 -0
- package/skills/status/SKILL.md +33 -0
- package/skills/status/assets/output_format.md +41 -0
- package/skills/todo/SKILL.md +46 -0
- package/skills/todo/assets/todo_handoff_template.md +22 -0
- package/skills/todo/assets/todo_template.md +3 -0
- package/skills/train/SKILL.md +116 -0
- package/skills/train/assets/dashboard-templates/classifiers.html +106 -0
- package/skills/train/assets/dashboard-templates/nlp.html +102 -0
- package/skills/train/assets/dashboard-templates/transformers.html +98 -0
- package/skills/train/assets/results-parsers/__init__.py +9 -0
- package/skills/train/assets/results-parsers/classifiers.py +84 -0
- package/skills/train/assets/results-parsers/nlp.py +88 -0
- package/skills/train/assets/results-parsers/reporter.py +154 -0
- package/skills/train/assets/results-parsers/transformers.py +120 -0
- package/skills/train/train_cli.py +786 -0
- package/templates/EXECUTION_PLAN_TEMPLATE.md +43 -0
- package/templates/EXECUTION_SUMMARY_TEMPLATE.md +50 -0
- package/templates/JENGA_CONFIG_TEMPLATE.json +23 -0
- package/templates/PROBLEM_RAPPORT_TEMPLATE.md +88 -0
- package/templates/SCRUM_BOARD_SCHEMA.md +311 -0
- package/templates/SKILL.md +16 -0
- package/templates/SKILL_TEMPLATE.md +28 -0
- package/templates/USER_INSTRUCTIONS_TEMPLATE.md +22 -0
- package/templates/copilot-instructions.md.tpl +55 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish
|
|
3
|
+
description: Configure, validate, and orchestrate scaffolded release workflows through a single `/publish` entry point with bounded sub-commands.
|
|
4
|
+
keywords:
|
|
5
|
+
- publish
|
|
6
|
+
- deploy
|
|
7
|
+
- release
|
|
8
|
+
- app store
|
|
9
|
+
- npm
|
|
10
|
+
- registry
|
|
11
|
+
- release notes
|
|
12
|
+
examples:
|
|
13
|
+
- "publish setup --target staging-appstore"
|
|
14
|
+
- "publish setup --type mobile-ios"
|
|
15
|
+
- "publish setup --type npm"
|
|
16
|
+
- "publish deploy --target staging-appstore --yes --dry-run"
|
|
17
|
+
- "publish deploy --target npm-registry"
|
|
18
|
+
- "publish deploy --target npm-registry --dry-run"
|
|
19
|
+
- "publish setup --type droplet"
|
|
20
|
+
- "publish deploy --target my-droplet"
|
|
21
|
+
- "publish deploy --target my-droplet --dry-run"
|
|
22
|
+
- "publish history --limit 5"
|
|
23
|
+
- "publish release-notes --target staging-appstore"
|
|
24
|
+
metadata:
|
|
25
|
+
scope: multi-target-v2
|
|
26
|
+
primary_target: multi
|
|
27
|
+
primary_platform: multi
|
|
28
|
+
supported_target_types:
|
|
29
|
+
- mobile-ios
|
|
30
|
+
- npm
|
|
31
|
+
- npm-ci
|
|
32
|
+
- droplet
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Publish — Deployment Pipeline Orchestrator
|
|
36
|
+
|
|
37
|
+
`/publish` is the single entry point for release workflows in this repository. It wires configuration validation, setup, gated deployment, release-note drafting, and ledger history into one end-to-end flow, and dispatches the final publish step to a per-type adapter.
|
|
38
|
+
|
|
39
|
+
Four target types are currently supported:
|
|
40
|
+
|
|
41
|
+
- **`mobile-ios`** — publishes an iOS build to App Store Connect via the iOS adapter. See the [iOS App Store](#ios-app-store) section for iOS-specific configuration.
|
|
42
|
+
- **`npm`** — publishes a package to an npm registry via the npm adapter. See the npm adapter (`skills/publish/adapters/npm.md`) and the npm wizard (`skills/publish/wizards/npm.md`) for npm-specific configuration.
|
|
43
|
+
- **`npm-ci`** — publishes a package to npmjs.com via GitHub Actions OIDC (Trusted Publishers), with no `NPM_TOKEN` stored. The adapter generates a GitHub Actions workflow, commits it to the repository, and triggers it via `gh workflow run`. See the npm-ci adapter (`skills/publish/adapters/npm-ci.md`) and the npm-ci wizard (`skills/publish/wizards/npm-ci.md`) for configuration details.
|
|
44
|
+
- **`droplet`** — deploys a website or app to any SSH-reachable Linux host (including DigitalOcean Droplets) using a generated GitHub Actions workflow. The workflow SSHes into the host, pulls the deploy branch, runs an optional build command, and restarts the service. See [Droplet (GitHub Actions → SSH)](#droplet-github-actions--ssh) for configuration details.
|
|
45
|
+
|
|
46
|
+
Every sub-command validates the config before doing anything else, so behaviour is identical regardless of which target type a project uses.
|
|
47
|
+
|
|
48
|
+
## Invocation Contract
|
|
49
|
+
|
|
50
|
+
Before any sub-command executes, validate the config with:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bash skills/publish/scripts/validate_config.sh <path-to-publish.json>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For deploy-oriented flows, validate the selected target with:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
bash skills/publish/scripts/check_target_config.sh <target-name> <path-to-publish.json>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- Default config resolution: prefer repo-root `publish.json`, fall back to `project/configs/publish.json`
|
|
63
|
+
- Schema: `skills/publish/schemas/publish.schema.json`
|
|
64
|
+
- Example config: `skills/publish/assets/publish.example.json`
|
|
65
|
+
- Secrets guide: `skills/publish/assets/secrets-guide.md`
|
|
66
|
+
- Deploy contract and exit codes: `skills/publish/assets/ci-contract.md`
|
|
67
|
+
- iOS adapter template: `skills/publish/adapters/mobile-ios.md`
|
|
68
|
+
- npm adapter template: `skills/publish/adapters/npm.md`
|
|
69
|
+
- Ownership matrix: `skills/publish/assets/ownership-matrix.md`
|
|
70
|
+
|
|
71
|
+
If config or env validation fails, the skill exits with code `4` and does not continue.
|
|
72
|
+
|
|
73
|
+
## Sub-Commands
|
|
74
|
+
|
|
75
|
+
| Command | Purpose | Implementation script | Notes |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| `/publish setup` | Prepare or refresh target configuration | `skills/publish/scripts/setup_wizard.sh` | Supported types: `mobile-ios`, `npm`, `npm-ci`, `droplet` |
|
|
78
|
+
| `/publish deploy` | Run the full 11-step deploy orchestration | `skills/publish/scripts/publish_deploy.sh` | Dispatches to the adapter for the target's `type` (`mobile-ios`, `npm`, `npm-ci`, or `droplet`); `--dry-run` is honoured end-to-end |
|
|
79
|
+
| `/publish history` | Read the canonical publish ledger | `skills/publish/scripts/show_history.sh` | Target-agnostic; filter by `--target <name>` |
|
|
80
|
+
| `/publish release-notes` | Generate release notes without publishing | `skills/publish/scripts/generate_release_notes.sh` | Target-agnostic |
|
|
81
|
+
|
|
82
|
+
## Quality Gate Policy
|
|
83
|
+
|
|
84
|
+
The deploy flow invokes `skills/publish/scripts/run_gates.sh` at two fixed points:
|
|
85
|
+
|
|
86
|
+
1. **Pre-deploy:** `run_gates.sh pre <target> <publish.json> [--non-interactive]`
|
|
87
|
+
2. **Post-deploy:** `run_gates.sh post <target> <publish.json> [--non-interactive]`
|
|
88
|
+
|
|
89
|
+
- `build` and `test` are **mandatory global** pre-deploy gates — always run, cannot be disabled via config
|
|
90
|
+
- Per-target `checks.pre` and `checks.post` can add optional gates: `lint`, `type-check`, `custom-script`, `smoke-test`, `ping`
|
|
91
|
+
- Any pre-deploy gate failure exits with code `2` and surfaces the full error output
|
|
92
|
+
- Post-deploy gate failure records a `partial` publish result instead of rolling back the adapter upload
|
|
93
|
+
- `--non-interactive` suppresses retry prompts and aborts immediately on failure
|
|
94
|
+
|
|
95
|
+
See `skills/publish/assets/ci-contract.md` for the full quality-gate policy.
|
|
96
|
+
|
|
97
|
+
## Usage Signatures
|
|
98
|
+
|
|
99
|
+
### `/publish setup`
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
/publish setup [<target>] [--type mobile-ios|npm|droplet] [--config <path>]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Implementation: `bash skills/publish/scripts/setup_wizard.sh [<target>] [--type <deployment_type>] [--config <path>]`
|
|
106
|
+
|
|
107
|
+
Wizard flow:
|
|
108
|
+
1. Resolve or prompt for the target name.
|
|
109
|
+
2. Resolve or prompt for the deployment type. Supported values: `mobile-ios`, `npm`, `droplet`.
|
|
110
|
+
3. Print the secrets guide path and the opening warning from `skills/publish/assets/secrets-guide.md`.
|
|
111
|
+
4. Load `skills/publish/wizards/<type>.md` and render each `## Question:` section as a prompt.
|
|
112
|
+
5. Preview the generated target config as JSON.
|
|
113
|
+
6. Save on confirmation by merging or creating `publish.json`.
|
|
114
|
+
7. Validate the saved file with `validate_config.sh`; if validation fails, roll back the write.
|
|
115
|
+
|
|
116
|
+
During setup, env-var reference answers are checked against the current shell. Missing variables only warn; they do not block save.
|
|
117
|
+
|
|
118
|
+
Example invocations:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
/publish setup # interactive, prompts for target and type
|
|
122
|
+
/publish setup --type mobile-ios # scaffold an iOS App Store target
|
|
123
|
+
/publish setup --type npm # scaffold an npm registry target
|
|
124
|
+
/publish setup npm-registry --type npm # scaffold a target named "npm-registry"
|
|
125
|
+
/publish setup --type npm-ci # scaffold an npm CI (Trusted Publisher) target
|
|
126
|
+
/publish setup npm-ci-pkg --type npm-ci # scaffold a target named "npm-ci-pkg"
|
|
127
|
+
/publish setup --type droplet # scaffold a Droplet SSH deploy target
|
|
128
|
+
/publish setup my-droplet --type droplet # scaffold a target named "my-droplet"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `/publish deploy`
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
/publish deploy [--target <name>] [--config <path>] [--yes] [--dry-run] [--minor | --major] [--release-notes <path>]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Implementation: `bash skills/publish/scripts/publish_deploy.sh [flags...]`
|
|
138
|
+
|
|
139
|
+
Deploy flow:
|
|
140
|
+
1. Select the target from config or `--target`
|
|
141
|
+
2. Check target completeness; interactive runs auto-launch the setup wizard on missing fields
|
|
142
|
+
3. Validate target environment variables
|
|
143
|
+
4. Print a best-effort scrum-board summary since the last publish tag
|
|
144
|
+
5. Run pre-deploy gates
|
|
145
|
+
6. Generate a release-note draft and review it unless `--yes` is set
|
|
146
|
+
7. Suggest and confirm the semver bump (`patch` by default in non-interactive mode unless `--minor` or `--major` is passed)
|
|
147
|
+
8. Print final confirmation: `Deploy v<x.y.z> to <target>? [y/N]`
|
|
148
|
+
9. Execute the adapter pipeline for the target's `type` (`ios_pipeline.sh` for `mobile-ios`, `npm_pipeline.sh` for `npm`, `npm_ci_pipeline.sh` for `npm-ci`, `droplet_pipeline.sh` for `droplet`)
|
|
149
|
+
10. Run post-deploy gates and downgrade the ledger state to `partial` on failure
|
|
150
|
+
11. Append the publish ledger entry, create the git tag (unless `--dry-run`), and print post-deploy manual steps
|
|
151
|
+
|
|
152
|
+
Non-interactive rule: when `--yes` is used, deploy must not auto-run setup after a failure. It exits `4` and surfaces the missing fields.
|
|
153
|
+
|
|
154
|
+
#### `--dry-run`
|
|
155
|
+
|
|
156
|
+
`--dry-run` runs the full deploy orchestration end-to-end without producing a real release:
|
|
157
|
+
|
|
158
|
+
- Every step from target selection through gates, release-note generation, and semver bump runs normally.
|
|
159
|
+
- The adapter is invoked with `--dry-run` so it performs its full pipeline but skips the destructive publish step (no App Store upload for `mobile-ios`, no `npm publish` for `npm`).
|
|
160
|
+
- The real git tag is **not** created.
|
|
161
|
+
- A ledger entry is still appended with `platform_state: "dry-run"` so the run is auditable.
|
|
162
|
+
|
|
163
|
+
Example invocations:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
/publish deploy --target staging-appstore --dry-run
|
|
167
|
+
/publish deploy --target npm-registry --dry-run
|
|
168
|
+
/publish deploy --target npm-ci-pkg --dry-run
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use `--dry-run` to rehearse a release, validate that gates pass, and confirm the generated release notes without publishing.
|
|
172
|
+
|
|
173
|
+
### `/publish history`
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
/publish history [--config <path>] [--limit <count>] [--target <name>] [--json]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Implementation: `bash skills/publish/scripts/show_history.sh [--limit <count>] [--target <name>] [--json] [--config <path>]`
|
|
180
|
+
|
|
181
|
+
### `/publish release-notes`
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
/publish release-notes --target <name> [--config <path>] [--from-tag <tag>] [--to-ref <git-ref>] [--output <path>]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Implementation: `bash skills/publish/scripts/generate_release_notes.sh [--target <name>] [--from-tag <tag>] [--to-ref <git-ref>] [--output <path>] [<publish_json_path>]`
|
|
188
|
+
|
|
189
|
+
Release-note rules:
|
|
190
|
+
- The last publish tag is the highest semver tag on the current branch that also has a matching ledger entry in `project/logs/publish-history.json`.
|
|
191
|
+
- If no prior ledger-backed tag exists, the draft includes `> First release — full history included`.
|
|
192
|
+
- Scrum-board enrichment is best-effort only; missing or unreadable board data never fails the command.
|
|
193
|
+
|
|
194
|
+
## Ledger & Tagging
|
|
195
|
+
|
|
196
|
+
- `project/logs/publish-history.json` is append-only. New publishes add new rows; existing rows are never edited in-place.
|
|
197
|
+
- `bash skills/publish/scripts/suggest_semver_bump.sh` suggests `major`, `minor`, or `patch` based on git history since the last ledger-backed publish tag.
|
|
198
|
+
- `bash skills/publish/scripts/write_ledger_entry.sh <target> <adapter> <platform_state> <notes_path> [--yes] [--dry-run] [--version <vX.Y.Z>] [--config <path>]` appends the canonical publish entry and creates the matching annotated git tag.
|
|
199
|
+
- `bash skills/publish/scripts/reconcile_tags.sh [--dry-run] [--config <path>]` repairs drift:
|
|
200
|
+
- git tag without ledger entry → append `partial` ledger row with note `Manually tagged without /publish`
|
|
201
|
+
- ledger entry without git tag → create the missing tag retroactively
|
|
202
|
+
|
|
203
|
+
## Agent Roles
|
|
204
|
+
|
|
205
|
+
See `skills/publish/assets/ownership-matrix.md` for the action-by-action ownership matrix.
|
|
206
|
+
|
|
207
|
+
Summary:
|
|
208
|
+
- **Developer** initiates `/publish setup`, `/publish deploy`, and release-note review
|
|
209
|
+
- **Tester** may run staging deploys as part of validation and uses publish history as test context
|
|
210
|
+
- **Scrum Master** never deploys directly and only reviews publish context through workflow status surfaces
|
|
211
|
+
|
|
212
|
+
## Configuration Model
|
|
213
|
+
|
|
214
|
+
The canonical config must validate against `skills/publish/schemas/publish.schema.json`.
|
|
215
|
+
|
|
216
|
+
### Required top-level structure
|
|
217
|
+
|
|
218
|
+
- `version` — schema version for the publish contract
|
|
219
|
+
- `defaults` — global defaults, including the canonical publish ledger path and mandatory checks
|
|
220
|
+
- `targets[]` — named deployment targets
|
|
221
|
+
|
|
222
|
+
### Common target structure
|
|
223
|
+
|
|
224
|
+
Every target — regardless of `type` — must define:
|
|
225
|
+
- `name`
|
|
226
|
+
- `type` — one of `mobile-ios`, `npm`, `droplet`
|
|
227
|
+
- `checks.pre[]` / `checks.post[]`
|
|
228
|
+
- `secrets` — env-var references only, never credential values
|
|
229
|
+
|
|
230
|
+
Type-specific fields are documented below.
|
|
231
|
+
|
|
232
|
+
## iOS App Store
|
|
233
|
+
|
|
234
|
+
The `mobile-ios` adapter publishes iOS builds to App Store Connect.
|
|
235
|
+
|
|
236
|
+
### Required target fields for `mobile-ios`
|
|
237
|
+
|
|
238
|
+
- `type: mobile-ios`
|
|
239
|
+
- `platform: ios-app-store`
|
|
240
|
+
- `ios` — scheme/build/export/upload metadata used by the adapter
|
|
241
|
+
|
|
242
|
+
### Required iOS env references
|
|
243
|
+
|
|
244
|
+
The `mobile-ios` target must provide env-var references for:
|
|
245
|
+
- `APP_STORE_CONNECT_API_KEY_ID`
|
|
246
|
+
- `APP_STORE_CONNECT_ISSUER_ID`
|
|
247
|
+
- `APP_STORE_CONNECT_PRIVATE_KEY_PATH`
|
|
248
|
+
- `CODE_SIGN_IDENTITY`
|
|
249
|
+
- `PROVISIONING_PROFILE_UUID`
|
|
250
|
+
|
|
251
|
+
### iOS scope guardrails
|
|
252
|
+
|
|
253
|
+
This story set intentionally does **not** implement automated App Store review submission.
|
|
254
|
+
|
|
255
|
+
The iOS adapter trust boundary is explicit: publish-side external commands are limited to direct `xcodebuild` and `xcrun` invocations.
|
|
256
|
+
|
|
257
|
+
## npm Registry
|
|
258
|
+
|
|
259
|
+
The `npm` adapter publishes a Node package to an npm-compatible registry.
|
|
260
|
+
|
|
261
|
+
- Adapter template: `skills/publish/adapters/npm.md`
|
|
262
|
+
- Wizard template: `skills/publish/wizards/npm.md`
|
|
263
|
+
|
|
264
|
+
See those files for the required target fields (registry URL, access, tag, `--dry-run` behaviour) and env references. Additional npm-specific schema details are owned by the npm settings block in `skills/publish/schemas/publish.schema.json`.
|
|
265
|
+
|
|
266
|
+
## npm CI (OIDC Trusted Publisher)
|
|
267
|
+
|
|
268
|
+
The `npm-ci` adapter publishes a Node package to npmjs.com via **GitHub Actions OIDC (Trusted Publishers)** — no `NPM_TOKEN` is stored anywhere.
|
|
269
|
+
|
|
270
|
+
> Use `npm` for local publishes with a token; use `npm-ci` for CI-only publishing with OIDC (no token required).
|
|
271
|
+
|
|
272
|
+
- Adapter template: `skills/publish/adapters/npm-ci.md`
|
|
273
|
+
- Wizard template: `skills/publish/wizards/npm-ci.md`
|
|
274
|
+
- Example config: `skills/publish/assets/publish.example.npm-ci.json`
|
|
275
|
+
|
|
276
|
+
### Required target fields for `npm-ci`
|
|
277
|
+
|
|
278
|
+
- `type: npm-ci`
|
|
279
|
+
- `github_repo` — repository in `owner/name` format (e.g. `acme-org/my-package`)
|
|
280
|
+
- `workflow_path` — path to the workflow file to generate and trigger (default: `.github/workflows/npm-publish.yml`)
|
|
281
|
+
- `npm.package_name`, `npm.access`, `npm.registry`, `npm.dist_tag` — same as the `npm` adapter
|
|
282
|
+
|
|
283
|
+
No `secrets` block is required. Any `secrets` block present is ignored by this adapter.
|
|
284
|
+
|
|
285
|
+
### One-time prerequisite (manual)
|
|
286
|
+
|
|
287
|
+
Before the first deploy, link the package to the repository on npmjs.com:
|
|
288
|
+
|
|
289
|
+
1. Sign in to npmjs.com → navigate to the package page
|
|
290
|
+
2. Settings → Publishing → Trusted Publishers → Add publisher
|
|
291
|
+
3. Select GitHub Actions; enter `owner/repo` and the workflow file path
|
|
292
|
+
4. Save
|
|
293
|
+
|
|
294
|
+
Once configured, only the linked workflow can publish this package — local `npm publish` with a token will be rejected by npmjs.com for that package.
|
|
295
|
+
|
|
296
|
+
### Usage examples
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
/publish setup --type npm-ci
|
|
300
|
+
/publish deploy --target npm-ci-pkg --dry-run
|
|
301
|
+
/publish deploy --target npm-ci-pkg
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Droplet (GitHub Actions → SSH)
|
|
305
|
+
|
|
306
|
+
The `droplet` adapter deploys a project to any SSH-reachable Linux host by generating a GitHub Actions workflow that SSHes into the host on each trigger.
|
|
307
|
+
|
|
308
|
+
**Trust boundary**: `publish.json` holds only *references* to GitHub Actions secret names — never the actual SSH key or host credentials. Real secrets live in GitHub Actions secrets.
|
|
309
|
+
|
|
310
|
+
### Required target fields for `droplet`
|
|
311
|
+
|
|
312
|
+
- `type: droplet`
|
|
313
|
+
- `platform: droplet-ssh`
|
|
314
|
+
- `droplet.host` — IP address or FQDN of the target host
|
|
315
|
+
- `droplet.ssh_user` — SSH login username
|
|
316
|
+
- `droplet.ssh_port` — SSH port (default 22)
|
|
317
|
+
- `droplet.deploy_path` — absolute path to the app directory on the host
|
|
318
|
+
- `droplet.github_repo` — repository in `owner/name` format
|
|
319
|
+
- `droplet.deploy_branch` — branch to pull on each deploy
|
|
320
|
+
- `droplet.start_cmd` — command to (re)start the service (e.g. `pm2 reload ecosystem.config.js`, `sudo systemctl restart myapp`)
|
|
321
|
+
- `droplet.build_cmd` — optional build step run after `git pull`
|
|
322
|
+
- `secrets.ssh_key_secret` — name of the GH Actions secret holding the SSH private key
|
|
323
|
+
- `secrets.known_hosts_secret` — name of the GH Actions secret holding `ssh-keyscan` output
|
|
324
|
+
|
|
325
|
+
### Required GitHub Actions secrets
|
|
326
|
+
|
|
327
|
+
The generated workflow reads these from GitHub Actions secrets:
|
|
328
|
+
- `DROPLET_SSH_HOST` — host IP or FQDN
|
|
329
|
+
- `DROPLET_SSH_USER` — SSH username
|
|
330
|
+
- `DROPLET_SSH_PORT` — SSH port
|
|
331
|
+
- `DROPLET_SSH_KEY` (or value of `ssh_key_secret`) — private key contents
|
|
332
|
+
- `DROPLET_KNOWN_HOSTS` (or value of `known_hosts_secret`) — `ssh-keyscan` output
|
|
333
|
+
|
|
334
|
+
See `skills/publish/assets/secrets-guide.md` for setup instructions.
|
|
335
|
+
|
|
336
|
+
### First-run prerequisites (manual)
|
|
337
|
+
|
|
338
|
+
Before the first deploy, the target host must already have:
|
|
339
|
+
- The deploy path created (`mkdir -p /var/www/myapp`)
|
|
340
|
+
- An initial `git clone` of the repo at the deploy path
|
|
341
|
+
- Any runtime dependencies installed (Node, PM2, etc.)
|
|
342
|
+
|
|
343
|
+
The adapter does not bootstrap the host — it only drives the continuous-deploy loop.
|
|
344
|
+
|
|
345
|
+
### Usage examples
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
/publish setup --type droplet
|
|
349
|
+
/publish deploy --target my-droplet --dry-run
|
|
350
|
+
/publish deploy --target my-droplet
|
|
351
|
+
```
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# `droplet` Adapter
|
|
2
|
+
|
|
3
|
+
The `droplet` adapter drives the `/publish deploy` flow for SSH-reachable Linux
|
|
4
|
+
host targets. Despite the name, nothing in the flow is DigitalOcean-specific — it
|
|
5
|
+
works against any Linux host reachable via SSH. The adapter generates a GitHub
|
|
6
|
+
Actions workflow that performs all deploy orchestration remotely; the local machine
|
|
7
|
+
never SSHes directly into the host.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Deploy a web application or service from a GitHub repository to a Linux host
|
|
12
|
+
(DigitalOcean Droplet, VPS, bare-metal server, or any SSH-reachable machine) by:
|
|
13
|
+
|
|
14
|
+
1. Generating a GitHub Actions workflow that SSHes into the host using
|
|
15
|
+
`appleboy/ssh-action`.
|
|
16
|
+
2. Committing the workflow file (`.github/workflows/publish-droplet.yml`) to the
|
|
17
|
+
repository.
|
|
18
|
+
3. Triggering the workflow via `gh workflow run`.
|
|
19
|
+
|
|
20
|
+
The host stays passive — it does not poll; all orchestration originates from
|
|
21
|
+
GitHub Actions. The user supplies `build_cmd` and `start_cmd`; the adapter makes
|
|
22
|
+
no assumptions about the runtime stack (no PM2 templates, no nginx config, no
|
|
23
|
+
systemd unit generation in v1).
|
|
24
|
+
|
|
25
|
+
## Trust Boundary
|
|
26
|
+
|
|
27
|
+
`publish.json` holds **only** configuration values and secret name references —
|
|
28
|
+
never actual secrets. The five secret values (SSH private key, host, user, port,
|
|
29
|
+
known_hosts) live exclusively in GitHub Actions secrets.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
publish.json GitHub Actions secrets
|
|
33
|
+
────────────── ──────────────────────────────
|
|
34
|
+
ssh_key_secret: "DROPLET_SSH_KEY" → ${{ secrets.DROPLET_SSH_KEY }} ← private key
|
|
35
|
+
known_hosts_secret: "DROPLET_KNOWN_HOSTS" → ${{ secrets.DROPLET_KNOWN_HOSTS }}
|
|
36
|
+
host: "192.168.1.10" (baked into workflow — not a secret)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`host`, `ssh_user`, `ssh_port`, `deploy_path`, `deploy_branch`, `build_cmd`, and
|
|
40
|
+
`start_cmd` are non-sensitive configuration values stored in `publish.json` and
|
|
41
|
+
expanded into the generated workflow YAML. If you prefer to keep the host address
|
|
42
|
+
private too, supply it via a GitHub Actions secret and reference it in `start_cmd`.
|
|
43
|
+
|
|
44
|
+
## Invocation Contract
|
|
45
|
+
|
|
46
|
+
### Inputs from `publish.json`
|
|
47
|
+
|
|
48
|
+
A `droplet` target must define:
|
|
49
|
+
|
|
50
|
+
- `name`
|
|
51
|
+
- `type: droplet`
|
|
52
|
+
- `platform: droplet-ssh`
|
|
53
|
+
- `checks.pre[]` / `checks.post[]`
|
|
54
|
+
- `secrets.ssh_key_secret` — GitHub Actions secret name for the SSH private key
|
|
55
|
+
- `secrets.known_hosts_secret` — GitHub Actions secret name for known_hosts
|
|
56
|
+
- `droplet.host` — IP or FQDN of the target host
|
|
57
|
+
- `droplet.ssh_user` — SSH username
|
|
58
|
+
- `droplet.ssh_port` — SSH port (default: 22)
|
|
59
|
+
- `droplet.deploy_path` — absolute path on the remote host
|
|
60
|
+
- `droplet.github_repo` — `owner/name` format
|
|
61
|
+
- `droplet.deploy_branch` — branch to pull during deploy
|
|
62
|
+
- `droplet.start_cmd` — required; command to (re)start the service
|
|
63
|
+
- `droplet.build_cmd` — optional; build command to run before starting
|
|
64
|
+
|
|
65
|
+
### Required environment and tools
|
|
66
|
+
|
|
67
|
+
The adapter requires the following tools at invocation time:
|
|
68
|
+
|
|
69
|
+
- `jq` — to read `publish.json` target config
|
|
70
|
+
- `git` — to commit the generated workflow file
|
|
71
|
+
- `gh` — GitHub CLI, to trigger the workflow via `gh workflow run`
|
|
72
|
+
|
|
73
|
+
The `gh` CLI must be authenticated (`gh auth login`) before running
|
|
74
|
+
`/publish deploy` against a droplet target.
|
|
75
|
+
|
|
76
|
+
### Pipeline entrypoint
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bash skills/publish/scripts/droplet_pipeline.sh \
|
|
80
|
+
--target <name> \
|
|
81
|
+
--config <path-to-publish.json> \
|
|
82
|
+
[--dry-run]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Execution Phases
|
|
86
|
+
|
|
87
|
+
Run the adapter phases in this exact order:
|
|
88
|
+
|
|
89
|
+
1. **`validate`** — call `validate_droplet_env.sh`; abort with exit 4 if any
|
|
90
|
+
required field in the target config is missing or empty.
|
|
91
|
+
|
|
92
|
+
2. **`generate-workflow`** — produce the GitHub Actions YAML in memory using a
|
|
93
|
+
here-doc. The `appleboy/ssh-action` step is pinned to a specific commit SHA
|
|
94
|
+
(not a floating tag) to prevent supply-chain surprises. In `--dry-run` mode,
|
|
95
|
+
print the YAML to stdout and exit 0 without writing any file.
|
|
96
|
+
|
|
97
|
+
3. **`commit-workflow`** — write the YAML to
|
|
98
|
+
`.github/workflows/publish-droplet.yml` (creating the directory if needed)
|
|
99
|
+
and commit it with:
|
|
100
|
+
```
|
|
101
|
+
git add .github/workflows/publish-droplet.yml
|
|
102
|
+
git commit -m "chore(publish): update droplet workflow for target <name>"
|
|
103
|
+
```
|
|
104
|
+
If the file already exists and the content is unchanged (`git diff --quiet`),
|
|
105
|
+
skip the commit — the operation is idempotent.
|
|
106
|
+
|
|
107
|
+
4. **`trigger`** — invoke `gh workflow run publish-droplet.yml --repo <github_repo>`
|
|
108
|
+
to start the workflow. After dispatching, retrieve the run URL via
|
|
109
|
+
`gh run list --workflow publish-droplet.yml --limit 1 --json url`.
|
|
110
|
+
|
|
111
|
+
5. **`triggered`** — print the workflow run URL to stdout. The caller
|
|
112
|
+
(`publish_deploy.sh`) writes the ledger entry with `platform_state: "triggered"`.
|
|
113
|
+
|
|
114
|
+
## Dry-run Mode
|
|
115
|
+
|
|
116
|
+
`--dry-run` is supported for safe end-to-end rehearsals without triggering a
|
|
117
|
+
real deploy.
|
|
118
|
+
|
|
119
|
+
Behavior in dry-run mode:
|
|
120
|
+
|
|
121
|
+
- The `validate` phase runs normally; config errors still surface.
|
|
122
|
+
- The `generate-workflow` phase runs normally; the YAML is printed to stdout.
|
|
123
|
+
- The `commit-workflow` phase is **skipped** — no file is written, no git commit
|
|
124
|
+
is made.
|
|
125
|
+
- The `trigger` phase is **skipped** — `gh workflow run` is not called.
|
|
126
|
+
- The adapter exits 0 after printing the YAML.
|
|
127
|
+
- The ledger entry written by `publish_deploy.sh` will have
|
|
128
|
+
`platform_state: "dry-run"`.
|
|
129
|
+
|
|
130
|
+
## Exit Codes
|
|
131
|
+
|
|
132
|
+
| Code | Meaning |
|
|
133
|
+
|------|-------------------------------------------------------------------|
|
|
134
|
+
| `0` | Pipeline completed successfully, or `--dry-run` finished cleanly |
|
|
135
|
+
| `4` | Config or env invalid — required field missing or `jq`/`gh` absent|
|
|
136
|
+
| `3` | Workflow trigger failure (`gh workflow run` exited non-zero) |
|
|
137
|
+
|
|
138
|
+
## Output Artefacts
|
|
139
|
+
|
|
140
|
+
A successful non-dry-run produces:
|
|
141
|
+
|
|
142
|
+
- `.github/workflows/publish-droplet.yml` committed to the repository
|
|
143
|
+
- A `gh workflow run` dispatch recorded in GitHub Actions history
|
|
144
|
+
- A workflow run URL printed to stdout
|
|
145
|
+
- A history entry in `project/logs/publish-history.json` written by
|
|
146
|
+
`publish_deploy.sh` with `platform_state: "triggered"`
|
|
147
|
+
|
|
148
|
+
## Post-deploy manual steps
|
|
149
|
+
|
|
150
|
+
After a successful deploy trigger, the deploy flow must print:
|
|
151
|
+
|
|
152
|
+
Deploy triggered. Next manual steps:
|
|
153
|
+
1. Monitor the workflow run at the URL printed above.
|
|
154
|
+
2. If the run fails, check the GitHub Actions logs for SSH or script errors.
|
|
155
|
+
3. Push a commit to `<deploy_branch>` to auto-trigger future deploys once the
|
|
156
|
+
generated workflow has been merged into the branch.
|
|
157
|
+
|
|
158
|
+
Print the same block regardless of interactive/non-interactive mode so CI logs
|
|
159
|
+
capture it.
|
|
160
|
+
|
|
161
|
+
## First-run bootstrap caveat
|
|
162
|
+
|
|
163
|
+
Creating the deploy path and performing the initial `git clone` on the remote
|
|
164
|
+
host is **out of scope for v1** and must be done manually before the first
|
|
165
|
+
`/publish deploy` invocation.
|
|
166
|
+
|
|
167
|
+
Minimum bootstrap on the host:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# SSH into the host
|
|
171
|
+
ssh <ssh_user>@<host>
|
|
172
|
+
|
|
173
|
+
# Clone the repository into deploy_path
|
|
174
|
+
git clone https://github.com/<github_repo>.git <deploy_path>
|
|
175
|
+
cd <deploy_path>
|
|
176
|
+
|
|
177
|
+
# Install runtime dependencies (example for Node.js)
|
|
178
|
+
npm install
|
|
179
|
+
|
|
180
|
+
# Verify start_cmd works
|
|
181
|
+
# e.g.: pm2 reload ecosystem.config.js
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Document these steps for your team. The wizard emits a post-setup instructions
|
|
185
|
+
file at `project/instructions/E22_S07_INSTRUCTIONS.md` with a bootstrap checklist.
|
|
186
|
+
|
|
187
|
+
## Runtime agnosticism
|
|
188
|
+
|
|
189
|
+
The adapter does not generate PM2 configs, nginx virtual-host files, or systemd
|
|
190
|
+
unit files. Users embed runtime-specific commands directly in `build_cmd` and
|
|
191
|
+
`start_cmd`. Examples:
|
|
192
|
+
|
|
193
|
+
| Runtime | start_cmd example |
|
|
194
|
+
|-----------|-----------------------------------------------------|
|
|
195
|
+
| PM2 | `pm2 reload ecosystem.config.js` |
|
|
196
|
+
| systemd | `sudo systemctl restart myapp` |
|
|
197
|
+
| Docker | `docker compose up -d --build` |
|
|
198
|
+
| Custom | `./scripts/restart.sh` |
|
|
199
|
+
|
|
200
|
+
Opinionated runtime templates are deferred to future adapter versions.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# `mobile-ios` Adapter
|
|
2
|
+
|
|
3
|
+
The `mobile-ios` adapter drives the `/publish deploy` flow for iOS App Store targets.
|
|
4
|
+
It is a prompt/template contract for the agent layer and delegates concrete execution to
|
|
5
|
+
`skills/publish/scripts/ios_pipeline.sh`.
|
|
6
|
+
|
|
7
|
+
## Invocation Contract
|
|
8
|
+
|
|
9
|
+
### Inputs from `publish.json`
|
|
10
|
+
|
|
11
|
+
A `mobile-ios` target must define:
|
|
12
|
+
|
|
13
|
+
- `name`
|
|
14
|
+
- `type: mobile-ios`
|
|
15
|
+
- `platform: ios-app-store`
|
|
16
|
+
- `checks.pre[]` / `checks.post[]`
|
|
17
|
+
- `secrets.app_store_connect_api_key_id`
|
|
18
|
+
- `secrets.app_store_connect_issuer_id`
|
|
19
|
+
- `secrets.app_store_connect_private_key_path`
|
|
20
|
+
- `secrets.code_sign_identity`
|
|
21
|
+
- `secrets.provisioning_profile_uuid`
|
|
22
|
+
- `ios.scheme`
|
|
23
|
+
- `ios.configuration`
|
|
24
|
+
- `ios.archive_path`
|
|
25
|
+
- `ios.export_path`
|
|
26
|
+
- `ios.export_method` (`ad-hoc` or `app-store`)
|
|
27
|
+
- `ios.bundle_id`
|
|
28
|
+
- `ios.team_id`
|
|
29
|
+
- `ios.app_store_app_id`
|
|
30
|
+
- exactly one of `ios.project_path` or `ios.workspace_path`
|
|
31
|
+
|
|
32
|
+
### Required environment variables
|
|
33
|
+
|
|
34
|
+
The adapter uses env-var references only and never stores secret values in repo files.
|
|
35
|
+
The required env vars are:
|
|
36
|
+
|
|
37
|
+
- `APP_STORE_CONNECT_API_KEY_ID`
|
|
38
|
+
- `APP_STORE_CONNECT_ISSUER_ID`
|
|
39
|
+
- `APP_STORE_CONNECT_PRIVATE_KEY_PATH`
|
|
40
|
+
- `CODE_SIGN_IDENTITY`
|
|
41
|
+
- `PROVISIONING_PROFILE_UUID`
|
|
42
|
+
|
|
43
|
+
Validate them before execution with:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
bash skills/publish/scripts/validate_ios_env.sh <path-to-publish.json>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Pipeline entrypoint
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
bash skills/publish/scripts/ios_pipeline.sh <target> <path-to-publish.json> [--dry-run] [--non-interactive]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Execution Phases
|
|
56
|
+
|
|
57
|
+
Run the adapter phases in this exact order:
|
|
58
|
+
|
|
59
|
+
1. `validate`
|
|
60
|
+
2. `build`
|
|
61
|
+
3. `sign`
|
|
62
|
+
4. `export`
|
|
63
|
+
5. `upload`
|
|
64
|
+
|
|
65
|
+
Quality gates run outside this adapter. Once control enters the adapter, external publish-side commands are restricted to direct `xcodebuild` and `xcrun` invocations.
|
|
66
|
+
|
|
67
|
+
## State Machine
|
|
68
|
+
|
|
69
|
+
The adapter records these transitions in `project/logs/publish-history.json`:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
idle → building → signing → exporting → uploading → uploaded
|
|
73
|
+
└──────────────────────→ failed
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### State meanings
|
|
77
|
+
|
|
78
|
+
- `idle` — conceptual pre-start state before a history row is appended
|
|
79
|
+
- `building` — archive command is about to run or is running
|
|
80
|
+
- `signing` — export options are being generated using env refs and config
|
|
81
|
+
- `exporting` — `xcodebuild -exportArchive` is running
|
|
82
|
+
- `uploading` — the IPA is being uploaded with `xcrun`
|
|
83
|
+
- `uploaded` — upload finished successfully
|
|
84
|
+
- `failed` — any build/export/upload failure; `completed_at` must be set
|
|
85
|
+
|
|
86
|
+
## Dry-run Mode
|
|
87
|
+
|
|
88
|
+
`--dry-run` is mandatory for safe CI validation without live Apple credentials.
|
|
89
|
+
|
|
90
|
+
Behavior:
|
|
91
|
+
|
|
92
|
+
- All `xcodebuild` / `xcrun` commands are printed with a `[DRY RUN]` prefix.
|
|
93
|
+
- Commands are **not** executed.
|
|
94
|
+
- State-machine writes still happen so reviewers can inspect the planned flow.
|
|
95
|
+
- The adapter exits `0` after simulating a successful upload.
|
|
96
|
+
|
|
97
|
+
## Exit Codes
|
|
98
|
+
|
|
99
|
+
| Code | Meaning |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `0` | Pipeline completed successfully or dry-run finished successfully |
|
|
102
|
+
| `3` | Build, sign, export, upload, or history-update failure |
|
|
103
|
+
| `4` | Config or env validation failure |
|
|
104
|
+
|
|
105
|
+
## Post-deploy manual steps
|
|
106
|
+
|
|
107
|
+
After a successful upload, the deploy flow must print:
|
|
108
|
+
|
|
109
|
+
✅ Upload complete. Next manual steps:
|
|
110
|
+
1. Go to App Store Connect → Apps → [Your App] → TestFlight (or App Store)
|
|
111
|
+
2. Find the new build and submit for review / release
|
|
112
|
+
3. Set release notes if required
|
|
113
|
+
|
|
114
|
+
Print the same block in `--non-interactive` mode so CI logs capture it.
|