aiblueprint-cli 1.4.82 → 1.4.84
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/README.md +4 -1
- package/agents-config/skills/apex/SKILL.md +61 -0
- package/agents-config/skills/app-icon/SKILL.md +161 -0
- package/agents-config/skills/appstore-connect/SKILL.md +2 -2
- package/agents-config/skills/{appstore-connect-setup/SKILL.md → appstore-connect/references/setup.md} +3 -6
- package/agents-config/skills/ios-testflight/SKILL.md +2 -2
- package/dist/cli.js +39 -38
- package/package.json +1 -1
- package/agents-config/skills/create-vitejs-app/SKILL.md +0 -273
- package/agents-config/skills/nextjs-add-prisma-db/SKILL.md +0 -137
- package/agents-config/skills/nextjs-setup-better-auth/SKILL.md +0 -174
- package/agents-config/skills/nextjs-setup-project/SKILL.md +0 -201
- package/agents-config/skills/saas-challenge-idea/SKILL.md +0 -136
- package/agents-config/skills/saas-create-architecture/SKILL.md +0 -243
- package/agents-config/skills/saas-create-headline/SKILL.md +0 -133
- package/agents-config/skills/saas-create-landing-copywritting/SKILL.md +0 -268
- package/agents-config/skills/saas-create-legals-docs/SKILL.md +0 -177
- package/agents-config/skills/saas-create-logos/SKILL.md +0 -241
- package/agents-config/skills/saas-create-prd/SKILL.md +0 -196
- package/agents-config/skills/saas-create-tasks/SKILL.md +0 -241
- package/agents-config/skills/saas-define-pricing/SKILL.md +0 -294
- package/agents-config/skills/saas-find-domain-name/SKILL.md +0 -191
- package/agents-config/skills/saas-implement-landing-page/SKILL.md +0 -258
- package/agents-config/skills/setup-tmux/SKILL.md +0 -165
- /package/agents-config/skills/{agents-managers → agents-manager}/SKILL.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/agents.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/context-management.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/debugging-agents.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/error-handling-and-recovery.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/evaluation-and-testing.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/orchestration-patterns.md +0 -0
- /package/agents-config/skills/{agents-managers → agents-manager}/references/writing-agent-prompts.md +0 -0
package/README.md
CHANGED
|
@@ -136,9 +136,12 @@ npx aiblueprint-cli@latest agents config unify sessions
|
|
|
136
136
|
|
|
137
137
|
### Skills
|
|
138
138
|
|
|
139
|
-
Install
|
|
139
|
+
Install skills directly into `~/.claude/skills/`:
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
|
+
# Install all skills
|
|
143
|
+
npx skills@latest add melvynx/aiblueprint
|
|
144
|
+
|
|
142
145
|
# Install a single skill
|
|
143
146
|
npx skills add Melvynx/aiblueprint --skill ultrathink
|
|
144
147
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apex
|
|
3
|
+
description: Structured implementation using the APEX method (Analyze → Plan → Execute → eXamine). Use when implementing a feature or fixing a bug that benefits from a clear, deliberate workflow instead of jumping straight to code.
|
|
4
|
+
argument-hint: "[-x] <task-description>"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# APEX
|
|
8
|
+
|
|
9
|
+
Implement `$ARGUMENTS` with a deliberate, four-phase workflow. Think before each phase.
|
|
10
|
+
|
|
11
|
+
Add `-x` to the request for an extra adversarial review pass after validation.
|
|
12
|
+
|
|
13
|
+
## A — Analyze
|
|
14
|
+
|
|
15
|
+
Gather just enough context to act with confidence:
|
|
16
|
+
|
|
17
|
+
- Use `Glob`/`Grep` to find the files and patterns you'll touch
|
|
18
|
+
- Read the closest existing example and follow its conventions
|
|
19
|
+
- Restate the task as 2-4 concrete acceptance criteria
|
|
20
|
+
- Note open questions; ask only if a wrong assumption would be costly
|
|
21
|
+
|
|
22
|
+
## P — Plan
|
|
23
|
+
|
|
24
|
+
Write a short, file-by-file plan before editing:
|
|
25
|
+
|
|
26
|
+
- List each file to create or change and what changes in it
|
|
27
|
+
- Pick the simplest approach that satisfies the criteria
|
|
28
|
+
- Order the steps so the code stays runnable along the way
|
|
29
|
+
|
|
30
|
+
## E — Execute
|
|
31
|
+
|
|
32
|
+
Implement the plan:
|
|
33
|
+
|
|
34
|
+
- Match the surrounding code's naming, structure, and idioms
|
|
35
|
+
- Stay strictly in scope — no "while I'm here" refactors
|
|
36
|
+
- Comments only where intent is genuinely non-obvious
|
|
37
|
+
- Run the formatter if the project has one
|
|
38
|
+
|
|
39
|
+
## X — eXamine
|
|
40
|
+
|
|
41
|
+
Validate, then optionally review:
|
|
42
|
+
|
|
43
|
+
1. **Validate**: run `lint`, `typecheck`, and relevant tests. Fix only what you broke; re-run until clean.
|
|
44
|
+
2. **Review** (only if `-x`): re-read the diff as a skeptic — check for bugs, security holes, missed edge cases, and overcomplication. Fix what you find.
|
|
45
|
+
|
|
46
|
+
## Output
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
## APEX complete
|
|
50
|
+
|
|
51
|
+
**Task:** {what was implemented}
|
|
52
|
+
**Criteria:** {✓ per acceptance criterion}
|
|
53
|
+
**Files changed:** {list}
|
|
54
|
+
**Validation:** ✓ lint ✓ typecheck ✓ tests
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
|
|
59
|
+
- One step at a time — finish each phase before the next
|
|
60
|
+
- Stay in scope; ship the smallest change that meets the criteria
|
|
61
|
+
- If blocked after 2 attempts, report the blocker and stop
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: app-icon
|
|
3
|
+
description: Generate a polished iOS + Android app icon for an Expo / React Native app with AI image generation, then post-process it to App Store / Play specs. Use for "create my app icon", "generate the iOS icon", "redo the app logo", "make the launcher icon". Requires an image-generation tool (Codex imagegen / gpt-image); without one it builds the prompt for you to run, then resumes at post-processing.
|
|
4
|
+
argument-hint: "[app concept or brand]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# App Icon
|
|
8
|
+
|
|
9
|
+
Generate a store-quality launcher icon (iOS App Store icon + Android adaptive icon + web favicon) for an Expo / React Native app, then post-process it to meet store requirements.
|
|
10
|
+
|
|
11
|
+
<capability_gate>
|
|
12
|
+
**This workflow requires an image-generation tool** (Codex's `imagegen` skill backed by gpt-image, or any model/agent that can generate raster images).
|
|
13
|
+
|
|
14
|
+
- **Codex**: invoke the `imagegen` skill with the prompt below. Generated files land in `~/.codex/generated_images/<session-id>/ig_*.png` — copy them into the repo.
|
|
15
|
+
- **Agent WITHOUT image generation (e.g. Claude Code without an image tool)**: do NOT fake it (no SVG-to-PNG pipelines — that produces flat, amateur results). Instead: build the final prompt from the recipe below, give it to the user to run in their image tool of choice, then resume at the Post-Processing phase with the file they provide.
|
|
16
|
+
</capability_gate>
|
|
17
|
+
|
|
18
|
+
<locate_assets>
|
|
19
|
+
Find where this app's icon actually lives before writing anything. Read the Expo config (`app.json`, `app.config.js`, or `app.config.ts`) and use the real paths:
|
|
20
|
+
|
|
21
|
+
- iOS icon → `expo.icon` (commonly `./assets/icon.png` or `./assets/images/icon.png`)
|
|
22
|
+
- Android adaptive icon foreground → `expo.android.adaptiveIcon.foregroundImage` (commonly `./assets/adaptive-icon.png`)
|
|
23
|
+
- Android adaptive background color → `expo.android.adaptiveIcon.backgroundColor`
|
|
24
|
+
- Web favicon → `expo.web.favicon` (commonly `./assets/favicon.png`)
|
|
25
|
+
|
|
26
|
+
In a monorepo the app may live under `mobile-app/` or `apps/<name>/` — resolve paths relative to the Expo project root, not the repo root. Below, `<ASSETS>` means that app's resolved assets directory.
|
|
27
|
+
|
|
28
|
+
Pull the **brand colors** and **app concept/name** from the project (a brand/site config, the README, or just ask the user). Use color *names* in the prompt, never hex.
|
|
29
|
+
</locate_assets>
|
|
30
|
+
|
|
31
|
+
<objective>
|
|
32
|
+
| Asset | Target file (typical) | Spec |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| iOS app icon | `<ASSETS>/icon.png` | 1024x1024, square, **NO transparency**, **no baked rounded mask** (iOS applies its own) |
|
|
35
|
+
| Android adaptive icon | `<ASSETS>/adaptive-icon.png` | foreground layer, subject inside the central ~66% safe circle, padded |
|
|
36
|
+
| Web favicon | `<ASSETS>/favicon.png` | 192x192 derived from the icon |
|
|
37
|
+
</objective>
|
|
38
|
+
|
|
39
|
+
<icon_recipe>
|
|
40
|
+
A layered prompt that avoids the common app-icon failure modes (baked rounded tiles, logo plates, accidental text, drop-shadow "floating card" look, unwanted mascots). Fill the two project blanks — **Subject** (the product's core concept/mascot/symbol) and the **Color palette** (named brand colors, never hex) — then send the entire block as one prompt to the image model.
|
|
41
|
+
|
|
42
|
+
Counter-intuitive but critical: tell the model it is **NOT** making an app-icon tile. Models bake in rounded-square plates, outer margins, and drop shadows the moment they hear "app icon". You want a full-bleed square subject filling 92-98% of the canvas; iOS applies its own mask afterward.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Create a 1024x1024 square symbol illustration.
|
|
46
|
+
|
|
47
|
+
Subject: <single centered mark for <AppName> — the product's core concept/mascot/symbol, highly readable at small sizes>
|
|
48
|
+
|
|
49
|
+
Context: standalone symbol/illustration for general use, not an app launcher icon or UI mockup.
|
|
50
|
+
Do not design or imply an app icon, logo plate, badge, or rounded-square container, even if the words "app icon" or "logo" appear.
|
|
51
|
+
Do not draw an icon inside a larger canvas. No outer margins, padding, or separate card background.
|
|
52
|
+
Do not draw any rounded-square tile, card, or container behind the subject.
|
|
53
|
+
The canvas itself is a perfect square with sharp 90° corners; do not simulate rounded-corner app icon masks or device-rounded corners.
|
|
54
|
+
No global drop shadows, long cast shadows, outer glows, or halos around the subject or canvas.
|
|
55
|
+
No UI mockups. No borders, frames, stickers, app plates, or device chrome.
|
|
56
|
+
No text/typography (letters, numbers, monograms). No watermark.
|
|
57
|
+
Not a full photo/portrait/real-world scene. No realistic human faces as the main subject.
|
|
58
|
+
Do not copy or imitate real brand logos, trademarked shapes, or recognizable brand marks.
|
|
59
|
+
|
|
60
|
+
Archetype (internal decision, do not mention in the output):
|
|
61
|
+
Choose exactly ONE archetype: object_icon, abstract_form_icon, hybrid_icon, or character_icon. Characters are optional and must only be used when clearly appropriate; never the default.
|
|
62
|
+
- object_icon: a single physical/symbolic object without a face (finance, productivity, utilities, dev tools, dashboards, system apps).
|
|
63
|
+
- abstract_form_icon: pure form/metaphor without literal objects or faces (AI tools, design tools, analytics, experimental products).
|
|
64
|
+
- hybrid_icon: an object with subtle life cues (no face), friendly but restrained (health, lifestyle).
|
|
65
|
+
- character_icon: a friendly expressive character with a face (kids, games, beginner education, wellness, fun social).
|
|
66
|
+
|
|
67
|
+
Concept:
|
|
68
|
+
Design a single, intentional visual element that represents the app. Avoid generic logos and the most literal/obvious metaphor; choose a clear but slightly unexpected metaphor.
|
|
69
|
+
Creativity means unusual material choices, unexpected-but-clear metaphors, expressive lighting, playful proportions, premium texture decisions. It does NOT mean always adding eyes/faces or always making it cute.
|
|
70
|
+
|
|
71
|
+
Material:
|
|
72
|
+
Default to an illustration-friendly matte finish (painted polymer, ceramic, paper, or flat vector). Avoid glass/chrome/neon unless explicitly requested. Material choice should communicate the product category.
|
|
73
|
+
|
|
74
|
+
Composition:
|
|
75
|
+
Main subject fills 92-98% of the canvas. Strong silhouette. No unnecessary elements.
|
|
76
|
+
|
|
77
|
+
Lighting:
|
|
78
|
+
Soft, controlled lighting. Minimal specular highlights. No bloom/glow/lens flares. No "3D glass icon" look.
|
|
79
|
+
|
|
80
|
+
Overall feel:
|
|
81
|
+
Modern, bold, subject-first illustration (not an app icon layout). Creative without being childish. Readable at small sizes. Clean illustration / 2D or 2.5D, matte finish, subtle shading only.
|
|
82
|
+
|
|
83
|
+
Color palette: <brand colors as names — e.g. "warm peach background, deep ink subject">. Clean contrast on both light and dark backgrounds.
|
|
84
|
+
|
|
85
|
+
Technical constraints:
|
|
86
|
+
Square 1:1 aspect ratio.
|
|
87
|
+
Main subject fills 92-98% of the canvas (zoom in; avoid excessive empty space).
|
|
88
|
+
Center/balance the silhouette. Keep critical details within ~5-8% safe area.
|
|
89
|
+
Android-safe: keep critical details within the central ~70% (silhouette may extend).
|
|
90
|
+
Background extends to all four edges of the square canvas with straight (non-rounded) corners; keep it clean (low-detail, low-noise).
|
|
91
|
+
Default-look guardrail: avoid inflated glass/chrome/neon/glow/sparkles/lens flare/exaggerated shine unless explicitly requested.
|
|
92
|
+
|
|
93
|
+
Quality filters (internal):
|
|
94
|
+
Reject if: it reads like a photo/portrait/full scene; it becomes a mascot by default; too many elements hurt clarity; a face appears without choosing character_icon; any rounded-square/card/tile background or app-icon container appears behind the subject.
|
|
95
|
+
Accept if: instant read at small size; strong silhouette; intentional material; clean contrast on both light and dark backgrounds.
|
|
96
|
+
|
|
97
|
+
Icon QA (internal): blur test (~64px), small-size readability, wallpaper contrast, one focal point.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Optional style preset.** Lock a look as a HARD constraint (it wins any conflict) by appending a dominant style block before the technical constraints. Useful named looks: `minimalism`, `glassy`, `geometric`, `gradient`, `flat`, `material`, `clay`, `kawaii`. Example for `minimalism`:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
STYLE SYSTEM: MINIMALISM (dominant — if anything conflicts, the style wins)
|
|
104
|
+
Cultural DNA: Swiss design, Apple, Braun, Dieter Rams, Functionalism.
|
|
105
|
+
Visual traits: max 3 colors; simple primary silhouettes; large negative space; no textures; no effects.
|
|
106
|
+
Mandatory: readable at very small sizes; works in monochrome; single dominant symbol.
|
|
107
|
+
Forbidden: gradients, shadows, 3D effects, decorative details, textures.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Non-negotiable for iOS (enforced in Post-Processing, not the prompt): the saved `icon.png` must have **no baked rounded corners** (iOS applies the mask), **no transparency** (App Store rejects alpha in the marketing icon), and stay **readable at 60px**.
|
|
111
|
+
</icon_recipe>
|
|
112
|
+
|
|
113
|
+
<generation_loop>
|
|
114
|
+
1. Generate the icon (1-3 candidates if the concept is open).
|
|
115
|
+
2. **Visually inspect every output** (open/read the images): strong silhouette? readable at small size? no baked rounded-square tile / no drop-shadow card? no accidental text or watermark? no transparency artifacts?
|
|
116
|
+
3. Reject and regenerate what fails — refine the prompt, don't accept "almost".
|
|
117
|
+
4. **Safety-filter gotcha**: a prompt can be rejected for ambiguous wording with harmless content. Reword to simple, neutral, single-paragraph phrasing and retry.
|
|
118
|
+
5. **Blur test:** shrink to ~64px — if the mark turns to mush, the concept is too detailed; simplify the silhouette.
|
|
119
|
+
</generation_loop>
|
|
120
|
+
|
|
121
|
+
<post_processing>
|
|
122
|
+
macOS uses `sips` (built in) + ImageMagick (`magick`, `brew install imagemagick`). Replace `<ASSETS>` and `<brand-bg-color>` with the values from `<locate_assets>`.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# 1. iOS icon: enforce 1024x1024 and strip alpha (App Store requirement)
|
|
126
|
+
sips -z 1024 1024 icon-raw.png --out /tmp/icon-1024.png
|
|
127
|
+
magick /tmp/icon-1024.png -background "<brand-bg-color>" -alpha remove -alpha off <ASSETS>/icon.png
|
|
128
|
+
# (no ImageMagick? `sips -s format jpeg /tmp/icon-1024.png --out /tmp/icon.jpg` then back to png also strips alpha)
|
|
129
|
+
|
|
130
|
+
# 2. Android adaptive icon: pad the subject into the central ~66% safe circle on a brand background.
|
|
131
|
+
# Scaling the full-bleed icon to ~66% places the SUBJECT inside the safe zone; the brand-bg extent fills the rest.
|
|
132
|
+
magick <ASSETS>/icon.png -resize 66% -background "<brand-bg-color>" -gravity center -extent 1024x1024 <ASSETS>/adaptive-icon.png
|
|
133
|
+
# Then make sure app config matches: expo.android.adaptiveIcon.backgroundColor == <brand-bg-color>.
|
|
134
|
+
# (For a cleaner result you can instead re-run the recipe with "leave ~20% padding for Android adaptive safe zone".)
|
|
135
|
+
|
|
136
|
+
# 3. Favicon + verification
|
|
137
|
+
sips -z 192 192 <ASSETS>/icon.png --out <ASSETS>/favicon.png
|
|
138
|
+
sips -g pixelWidth -g pixelHeight -g hasAlpha <ASSETS>/icon.png <ASSETS>/adaptive-icon.png <ASSETS>/favicon.png
|
|
139
|
+
# icon.png MUST report hasAlpha: no
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Remember: **icon and adaptive-icon changes require a native rebuild** (`npx expo run:ios` / `npx expo run:android`, or a new EAS build) — they will NOT appear on hot reload. The favicon is a web asset and reloads normally.
|
|
143
|
+
</post_processing>
|
|
144
|
+
|
|
145
|
+
<render_verification>
|
|
146
|
+
File inspection is not enough for the launcher icon — confirm it on a device/simulator after a native rebuild.
|
|
147
|
+
|
|
148
|
+
1. Rebuild the dev client so the new icon is bundled (`npx expo run:ios` or `npx expo run:android`).
|
|
149
|
+
2. On the home screen, confirm: the icon shows the new art (not the old/default), iOS applies a clean rounded mask with no double-rounding or visible alpha edge, and the mark is readable at home-screen size.
|
|
150
|
+
3. Fail the run if the icon still shows the previous art or a transparent/white corner halo. Fix before reporting completion.
|
|
151
|
+
</render_verification>
|
|
152
|
+
|
|
153
|
+
<failure_modes>
|
|
154
|
+
- Generated icon has transparency or baked rounded corners → App Store rejection; strip alpha (`-alpha remove`), regenerate without any tile/mask.
|
|
155
|
+
- iOS shows a white/transparent corner halo → alpha was not stripped; re-run the `magick ... -alpha remove -alpha off` step and rebuild.
|
|
156
|
+
- Android adaptive icon looks cropped at the edges → subject sat outside the central 66% safe circle; increase padding (lower the `-resize` percentage) or regenerate with explicit padding.
|
|
157
|
+
- Icon unchanged after editing the PNG → no native rebuild; hot reload never updates the launcher icon.
|
|
158
|
+
- Flat/amateur output → prompt missed the "subject-first illustration, not an app icon layout" + matte/material anchors, or fell back to a generic logo.
|
|
159
|
+
- Prompt rejected by safety filter → reword neutrally, simplify to one plain paragraph; content was almost certainly fine.
|
|
160
|
+
- Mark turns to mush at small size → too detailed; simplify to a single strong silhouette (blur/64px test).
|
|
161
|
+
</failure_modes>
|
|
@@ -8,7 +8,7 @@ description: Interact with App Store Connect via the asc CLI - apps, builds, Tes
|
|
|
8
8
|
Read, manage, and ship any of the user's App Store apps through the **`asc`** CLI (App Store Connect CLI by Rork). `asc` covers nearly the entire ASC surface; reach for the raw API only for the rare gap.
|
|
9
9
|
|
|
10
10
|
<auth>
|
|
11
|
-
`asc` is already authenticated on this machine (a default keychain profile). Verify before doing real work:
|
|
11
|
+
`asc` is usually already authenticated on this machine (a default keychain profile). Verify before doing real work:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
asc auth status # shows stored credential profiles + which is default
|
|
@@ -17,7 +17,7 @@ asc doctor # diagnose auth/config issues
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
- Multiple accounts/teams: `asc --profile <name> <command>` selects a profile.
|
|
20
|
-
-
|
|
20
|
+
- **Not authenticated / no working credential / a NEW account with no stored key:** read [references/setup.md](references/setup.md) and follow it — a battle-tested workflow to locate the `.p8`, key id, and issuer id, then `asc auth login`. Never print or commit `.p8` keys, key ids, or issuer ids.
|
|
21
21
|
</auth>
|
|
22
22
|
|
|
23
23
|
<how_to_drive>
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
name: appstore-connect-setup
|
|
3
|
-
description: Find and configure App Store Connect API credentials for asc auth. Use when asc auth is missing, credentials are unknown, the user says login to App Store Connect, or before TestFlight/App Store release work.
|
|
4
|
-
---
|
|
1
|
+
# App Store Connect Setup (asc auth)
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
Read this when `asc` is **not yet authenticated** — `asc auth status --validate` reports no working credential, the user asks to "log in to App Store Connect", or credentials are unknown before TestFlight/App Store release work.
|
|
7
4
|
|
|
8
5
|
<objective>
|
|
9
|
-
`asc auth login` needs three things: a **key ID**, an **issuer ID**, and a **.p8 private key file**. Users rarely remember where these are. This
|
|
6
|
+
`asc auth login` needs three things: a **key ID**, an **issuer ID**, and a **.p8 private key file**. Users rarely remember where these are. This is a battle-tested workflow for finding all three without asking the user to dig through App Store Connect manually.
|
|
10
7
|
|
|
11
8
|
Key insight from a real session: the `.p8` files and key IDs live on disk, but the **issuer ID is almost never stored locally** — it only exists in the App Store Connect web UI. The trick is to read it from the user's already-signed-in browser session via CDP, since Apple login requires 2FA and cannot be automated.
|
|
12
9
|
</objective>
|
|
@@ -34,7 +34,7 @@ The key insight: interactive `eas build` credential setup requires Apple ID 2FA
|
|
|
34
34
|
The user must have (ask once, as a group — these cannot be created by the agent):
|
|
35
35
|
|
|
36
36
|
1. **Apple Developer Program membership** (paid, enrolled).
|
|
37
|
-
2. **App Store Connect API key**: the `AuthKey_<KEY_ID>.p8` file, its key ID, and the team issuer ID. If unknown,
|
|
37
|
+
2. **App Store Connect API key**: the `AuthKey_<KEY_ID>.p8` file, its key ID, and the team issuer ID. If unknown, follow the `appstore-connect` skill's setup workflow (`references/setup.md`), or point the user to App Store Connect > Users and Access > Integrations > App Store Connect API (key must have Admin or App Manager role).
|
|
38
38
|
3. **Expo account** logged in: `npx eas-cli@latest whoami` (else `npx eas-cli@latest login`).
|
|
39
39
|
4. **App record in App Store Connect** for the bundle ID. The public API cannot create app records — if missing, the user creates it once at appstoreconnect.apple.com (My Apps > + > New App, selecting the bundle ID). Verify with Phase D step 1 and stop with clear instructions if absent.
|
|
40
40
|
5. `asc` CLI installed (`brew install asc`) — used only for the final upload; everything else goes through `scripts/asc-api.mjs`.
|
|
@@ -47,7 +47,7 @@ The user must have (ask once, as a group — these cannot be created by the agen
|
|
|
47
47
|
| `{bundle_id}` | `SiteConfig.bundleId` |
|
|
48
48
|
| `{apple_team_id}` | `SiteConfig.appleTeamId` |
|
|
49
49
|
| `{eas_project_id}` | output of `eas project:init`, then written to `site-config.ts` |
|
|
50
|
-
| `{asc_key_id}` / `{asc_issuer_id}` / `{asc_p8_path}` | from the user / `appstore-connect
|
|
50
|
+
| `{asc_key_id}` / `{asc_issuer_id}` / `{asc_p8_path}` | from the user / the `appstore-connect` skill's `references/setup.md`. Never commit, never print. |
|
|
51
51
|
| `{convex_prod_url}` / `{convex_prod_site_url}` | from `npx convex deploy` output / Convex dashboard |
|
|
52
52
|
| `{asc_app_id}` | numeric app ID resolved from the bundle ID (Phase D) |
|
|
53
53
|
| `{build_mode}` | default `local`; `expo` only when the user passes `--expo` |
|
package/dist/cli.js
CHANGED
|
@@ -32265,7 +32265,7 @@ var lib_default = inquirer;
|
|
|
32265
32265
|
// src/commands/setup.ts
|
|
32266
32266
|
var import_fs_extra9 = __toESM(require_lib4(), 1);
|
|
32267
32267
|
import path13 from "path";
|
|
32268
|
-
import
|
|
32268
|
+
import os11 from "os";
|
|
32269
32269
|
|
|
32270
32270
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
32271
32271
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -33686,6 +33686,7 @@ async function mergeCodexConfigFile(sourceConfigPath, codexDir) {
|
|
|
33686
33686
|
|
|
33687
33687
|
// src/lib/configs-store.ts
|
|
33688
33688
|
var import_fs_extra7 = __toESM(require_lib4(), 1);
|
|
33689
|
+
import os10 from "os";
|
|
33689
33690
|
import path11 from "path";
|
|
33690
33691
|
var RETENTION_MANAGED_BACKUP_TRIGGERS = new Set(["setup", "sync", "load", "backup-load"]);
|
|
33691
33692
|
var DEFAULT_BACKUP_RETENTION_DAYS = 30;
|
|
@@ -33738,7 +33739,7 @@ async function hasContent(folderPath) {
|
|
|
33738
33739
|
async function copyManagedFolder(source, destination) {
|
|
33739
33740
|
await import_fs_extra7.default.copy(source, destination, {
|
|
33740
33741
|
overwrite: true,
|
|
33741
|
-
dereference:
|
|
33742
|
+
dereference: os10.platform() === "win32"
|
|
33742
33743
|
});
|
|
33743
33744
|
}
|
|
33744
33745
|
async function writeMetadata(snapshotPath, metadata) {
|
|
@@ -34491,7 +34492,7 @@ async function setupCommand(params = {}) {
|
|
|
34491
34492
|
console.log(source_default.gray(`
|
|
34492
34493
|
Next steps:`));
|
|
34493
34494
|
if (options.shellShortcuts) {
|
|
34494
|
-
const platform =
|
|
34495
|
+
const platform = os11.platform();
|
|
34495
34496
|
if (platform === "win32") {
|
|
34496
34497
|
console.log(source_default.gray(" • Restart PowerShell to load the new functions"));
|
|
34497
34498
|
} else {
|
|
@@ -34521,7 +34522,7 @@ Next steps:`));
|
|
|
34521
34522
|
// src/commands/setup-terminal.ts
|
|
34522
34523
|
var import_fs_extra10 = __toESM(require_lib4(), 1);
|
|
34523
34524
|
import path14 from "path";
|
|
34524
|
-
import
|
|
34525
|
+
import os12 from "os";
|
|
34525
34526
|
import { execSync as execSync3, exec as exec2 } from "child_process";
|
|
34526
34527
|
var OHMYZSH_INSTALL_URL = "https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh";
|
|
34527
34528
|
var INSTALL_TIMEOUT = 120000;
|
|
@@ -34688,7 +34689,7 @@ plugins=(${pluginsString})`;
|
|
|
34688
34689
|
}
|
|
34689
34690
|
async function setupTerminalCommand(options = {}) {
|
|
34690
34691
|
const { skipInteractive, homeDir: customHomeDir } = options;
|
|
34691
|
-
const homeDir = customHomeDir ||
|
|
34692
|
+
const homeDir = customHomeDir || os12.homedir();
|
|
34692
34693
|
try {
|
|
34693
34694
|
console.log(source_default.blue.bold(`
|
|
34694
34695
|
\uD83D\uDDA5️ AIBlueprint Terminal Setup ${source_default.gray(`v${getVersion()}`)}
|
|
@@ -34838,24 +34839,24 @@ Next steps:`));
|
|
|
34838
34839
|
// src/commands/setup/symlinks.ts
|
|
34839
34840
|
var import_fs_extra11 = __toESM(require_lib4(), 1);
|
|
34840
34841
|
import path15 from "path";
|
|
34841
|
-
import
|
|
34842
|
+
import os13 from "os";
|
|
34842
34843
|
async function getToolPaths(tool, customFolder) {
|
|
34843
34844
|
let baseDir;
|
|
34844
34845
|
switch (tool) {
|
|
34845
34846
|
case "claude-code":
|
|
34846
|
-
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(
|
|
34847
|
+
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(os13.homedir(), ".claude");
|
|
34847
34848
|
return {
|
|
34848
34849
|
baseDir,
|
|
34849
34850
|
agentsPath: path15.join(baseDir, "agents")
|
|
34850
34851
|
};
|
|
34851
34852
|
case "codex":
|
|
34852
|
-
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(
|
|
34853
|
+
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(os13.homedir(), ".codex");
|
|
34853
34854
|
return {
|
|
34854
34855
|
baseDir,
|
|
34855
34856
|
agentsPath: path15.join(baseDir, "agents")
|
|
34856
34857
|
};
|
|
34857
34858
|
case "factoryai":
|
|
34858
|
-
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(
|
|
34859
|
+
baseDir = customFolder ? path15.resolve(customFolder) : path15.join(os13.homedir(), ".factory");
|
|
34859
34860
|
return {
|
|
34860
34861
|
baseDir,
|
|
34861
34862
|
agentsPath: path15.join(baseDir, "droids")
|
|
@@ -34883,7 +34884,7 @@ async function createSymlink(sourcePath, targetPath, options = {}) {
|
|
|
34883
34884
|
return false;
|
|
34884
34885
|
}
|
|
34885
34886
|
}
|
|
34886
|
-
const isWindows2 =
|
|
34887
|
+
const isWindows2 = os13.platform() === "win32";
|
|
34887
34888
|
if (isWindows2) {
|
|
34888
34889
|
await import_fs_extra11.default.symlink(sourcePath, targetPath, "junction");
|
|
34889
34890
|
} else {
|
|
@@ -35727,14 +35728,14 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
35727
35728
|
// src/lib/agents-unifier.ts
|
|
35728
35729
|
var import_fs_extra13 = __toESM(require_lib4(), 1);
|
|
35729
35730
|
import crypto from "crypto";
|
|
35730
|
-
import
|
|
35731
|
+
import os15 from "os";
|
|
35731
35732
|
import path17 from "path";
|
|
35732
35733
|
|
|
35733
35734
|
// src/lib/backup-utils.ts
|
|
35734
35735
|
var import_fs_extra12 = __toESM(require_lib4(), 1);
|
|
35735
35736
|
import path16 from "path";
|
|
35736
|
-
import
|
|
35737
|
-
var BACKUP_BASE_DIR = path16.join(
|
|
35737
|
+
import os14 from "os";
|
|
35738
|
+
var BACKUP_BASE_DIR = path16.join(os14.homedir(), ".config", "aiblueprint", "backup");
|
|
35738
35739
|
function getBackupDir() {
|
|
35739
35740
|
return process.env.AIBLUEPRINT_BACKUP_DIR || BACKUP_BASE_DIR;
|
|
35740
35741
|
}
|
|
@@ -35781,7 +35782,7 @@ var MANAGED_FOLDERS = [".claude", ".codex", ".agents"];
|
|
|
35781
35782
|
async function copyForBackup(sourcePath, destPath) {
|
|
35782
35783
|
await import_fs_extra12.default.copy(sourcePath, destPath, {
|
|
35783
35784
|
overwrite: true,
|
|
35784
|
-
dereference:
|
|
35785
|
+
dereference: os14.platform() === "win32"
|
|
35785
35786
|
});
|
|
35786
35787
|
}
|
|
35787
35788
|
async function hasMeaningfulContent(dir) {
|
|
@@ -36507,7 +36508,7 @@ async function ensureBackupPath(result, dryRun = false) {
|
|
|
36507
36508
|
}
|
|
36508
36509
|
async function createDirectorySymlink(source, target) {
|
|
36509
36510
|
await import_fs_extra13.default.ensureDir(path17.dirname(target));
|
|
36510
|
-
if (
|
|
36511
|
+
if (os15.platform() === "win32") {
|
|
36511
36512
|
await import_fs_extra13.default.symlink(source, target, "junction");
|
|
36512
36513
|
return;
|
|
36513
36514
|
}
|
|
@@ -36515,7 +36516,7 @@ async function createDirectorySymlink(source, target) {
|
|
|
36515
36516
|
}
|
|
36516
36517
|
async function createFileSymlink(source, target) {
|
|
36517
36518
|
await import_fs_extra13.default.ensureDir(path17.dirname(target));
|
|
36518
|
-
if (
|
|
36519
|
+
if (os15.platform() === "win32") {
|
|
36519
36520
|
await import_fs_extra13.default.symlink(source, target, "file");
|
|
36520
36521
|
return;
|
|
36521
36522
|
}
|
|
@@ -37221,7 +37222,7 @@ Codex agents render failed:`), error);
|
|
|
37221
37222
|
// src/lib/session-unifier.ts
|
|
37222
37223
|
var import_fs_extra14 = __toESM(require_lib4(), 1);
|
|
37223
37224
|
import crypto2 from "crypto";
|
|
37224
|
-
import
|
|
37225
|
+
import os16 from "os";
|
|
37225
37226
|
import path18 from "path";
|
|
37226
37227
|
var MANAGED_FOLDERS2 = [".claude", ".codex", ".agents"];
|
|
37227
37228
|
var SESSION_PATHS = {
|
|
@@ -37245,7 +37246,7 @@ async function collectSnapshotSources(folders) {
|
|
|
37245
37246
|
...await listSnapshotSources(storePaths.configsDir, "config"),
|
|
37246
37247
|
...await listSnapshotSources(storePaths.backupsDir, "backup")
|
|
37247
37248
|
];
|
|
37248
|
-
if (path18.resolve(folders.rootDir) ===
|
|
37249
|
+
if (path18.resolve(folders.rootDir) === os16.homedir()) {
|
|
37249
37250
|
sources.push(...await listSnapshotSources(getBackupDir(), "legacy-backup"));
|
|
37250
37251
|
}
|
|
37251
37252
|
return sources.sort((a, b3) => a.name.localeCompare(b3.name));
|
|
@@ -37518,7 +37519,7 @@ import path21 from "path";
|
|
|
37518
37519
|
|
|
37519
37520
|
// src/lib/pro-installer.ts
|
|
37520
37521
|
var import_fs_extra15 = __toESM(require_lib4(), 1);
|
|
37521
|
-
import
|
|
37522
|
+
import os17 from "os";
|
|
37522
37523
|
import path19 from "path";
|
|
37523
37524
|
import { exec as exec3 } from "child_process";
|
|
37524
37525
|
import { promisify as promisify2 } from "util";
|
|
@@ -37548,7 +37549,7 @@ function routePath(relativePath) {
|
|
|
37548
37549
|
return { kind: "claude", relativePath };
|
|
37549
37550
|
}
|
|
37550
37551
|
function getCacheRepoDir() {
|
|
37551
|
-
return path19.join(
|
|
37552
|
+
return path19.join(os17.homedir(), ".config", "aiblueprint", "pro-repos", "aiblueprint-cli-premium");
|
|
37552
37553
|
}
|
|
37553
37554
|
async function execGitWithAuth(command, token, repoUrl, cwd) {
|
|
37554
37555
|
const authenticatedUrl = `https://x-access-token:${token}@${repoUrl.replace(/^https?:\/\//, "")}`;
|
|
@@ -37719,7 +37720,7 @@ async function installProConfigs(options) {
|
|
|
37719
37720
|
} catch (error) {
|
|
37720
37721
|
console.warn("Git caching failed, falling back to API download");
|
|
37721
37722
|
}
|
|
37722
|
-
const tempDir = path19.join(
|
|
37723
|
+
const tempDir = path19.join(os17.tmpdir(), `aiblueprint-premium-${Date.now()}`);
|
|
37723
37724
|
try {
|
|
37724
37725
|
let success = false;
|
|
37725
37726
|
for (const candidate of CONFIG_FOLDER_CANDIDATES2) {
|
|
@@ -37755,15 +37756,15 @@ async function syncAllAgentSymlinks(agentsDir, claudeDir) {
|
|
|
37755
37756
|
|
|
37756
37757
|
// src/lib/token-storage.ts
|
|
37757
37758
|
var import_fs_extra16 = __toESM(require_lib4(), 1);
|
|
37758
|
-
import
|
|
37759
|
+
import os18 from "os";
|
|
37759
37760
|
import path20 from "path";
|
|
37760
37761
|
function getConfigDir() {
|
|
37761
|
-
const platform =
|
|
37762
|
+
const platform = os18.platform();
|
|
37762
37763
|
if (platform === "win32") {
|
|
37763
|
-
const appData = process.env.APPDATA || path20.join(
|
|
37764
|
+
const appData = process.env.APPDATA || path20.join(os18.homedir(), "AppData", "Roaming");
|
|
37764
37765
|
return path20.join(appData, "aiblueprint");
|
|
37765
37766
|
} else {
|
|
37766
|
-
const configHome = process.env.XDG_CONFIG_HOME || path20.join(
|
|
37767
|
+
const configHome = process.env.XDG_CONFIG_HOME || path20.join(os18.homedir(), ".config");
|
|
37767
37768
|
return path20.join(configHome, "aiblueprint");
|
|
37768
37769
|
}
|
|
37769
37770
|
}
|
|
@@ -37799,7 +37800,7 @@ async function getToken() {
|
|
|
37799
37800
|
function getTokenInfo() {
|
|
37800
37801
|
return {
|
|
37801
37802
|
path: getTokenFilePath2(),
|
|
37802
|
-
platform:
|
|
37803
|
+
platform: os18.platform()
|
|
37803
37804
|
};
|
|
37804
37805
|
}
|
|
37805
37806
|
|
|
@@ -38919,19 +38920,19 @@ async function configsBackupsCleanCommand(options = {}) {
|
|
|
38919
38920
|
}
|
|
38920
38921
|
|
|
38921
38922
|
// src/commands/openclaw-pro.ts
|
|
38922
|
-
import
|
|
38923
|
+
import os21 from "os";
|
|
38923
38924
|
import path25 from "path";
|
|
38924
38925
|
|
|
38925
38926
|
// src/lib/openclaw-installer.ts
|
|
38926
38927
|
var import_fs_extra19 = __toESM(require_lib4(), 1);
|
|
38927
|
-
import
|
|
38928
|
+
import os19 from "os";
|
|
38928
38929
|
import path23 from "path";
|
|
38929
38930
|
import { exec as exec4 } from "child_process";
|
|
38930
38931
|
import { promisify as promisify3 } from "util";
|
|
38931
38932
|
var execAsync3 = promisify3(exec4);
|
|
38932
38933
|
var OPENCLAW_PRO_REPO = "Melvynx/openclawpro";
|
|
38933
38934
|
function getCacheRepoDir2() {
|
|
38934
|
-
return path23.join(
|
|
38935
|
+
return path23.join(os19.homedir(), ".config", "openclaw", "pro-repos", "openclawpro");
|
|
38935
38936
|
}
|
|
38936
38937
|
async function execGitWithAuth2(command, token, repoUrl, cwd) {
|
|
38937
38938
|
const authenticatedUrl = `https://x-access-token:${token}@${repoUrl.replace(/^https?:\/\//, "")}`;
|
|
@@ -38980,7 +38981,7 @@ async function copyConfigFromCache2(cacheConfigDir, targetDir, onProgress) {
|
|
|
38980
38981
|
}
|
|
38981
38982
|
async function installOpenclawProConfigs(options) {
|
|
38982
38983
|
const { githubToken, openclawFolder, onProgress } = options;
|
|
38983
|
-
const targetFolder = openclawFolder || path23.join(
|
|
38984
|
+
const targetFolder = openclawFolder || path23.join(os19.homedir(), ".openclaw");
|
|
38984
38985
|
try {
|
|
38985
38986
|
const cacheConfigDir = await cloneOrUpdateRepo2(githubToken);
|
|
38986
38987
|
await copyConfigFromCache2(cacheConfigDir, targetFolder, onProgress);
|
|
@@ -38992,14 +38993,14 @@ async function installOpenclawProConfigs(options) {
|
|
|
38992
38993
|
|
|
38993
38994
|
// src/lib/openclaw-token-storage.ts
|
|
38994
38995
|
var import_fs_extra20 = __toESM(require_lib4(), 1);
|
|
38995
|
-
import
|
|
38996
|
+
import os20 from "os";
|
|
38996
38997
|
import path24 from "path";
|
|
38997
38998
|
function getConfigDir2() {
|
|
38998
|
-
const platform =
|
|
38999
|
+
const platform = os20.platform();
|
|
38999
39000
|
if (platform === "win32") {
|
|
39000
|
-
return path24.join(process.env.APPDATA ||
|
|
39001
|
+
return path24.join(process.env.APPDATA || os20.homedir(), "openclaw");
|
|
39001
39002
|
}
|
|
39002
|
-
return path24.join(
|
|
39003
|
+
return path24.join(os20.homedir(), ".config", "openclaw");
|
|
39003
39004
|
}
|
|
39004
39005
|
function getTokenPath() {
|
|
39005
39006
|
return path24.join(getConfigDir2(), "token.txt");
|
|
@@ -39020,7 +39021,7 @@ async function getOpenclawToken() {
|
|
|
39020
39021
|
function getOpenclawTokenInfo() {
|
|
39021
39022
|
return {
|
|
39022
39023
|
path: getTokenPath(),
|
|
39023
|
-
platform:
|
|
39024
|
+
platform: os20.platform()
|
|
39024
39025
|
};
|
|
39025
39026
|
}
|
|
39026
39027
|
|
|
@@ -39132,7 +39133,7 @@ async function openclawProSetupCommand(options = {}) {
|
|
|
39132
39133
|
Se(source_default.red("❌ Not activated"));
|
|
39133
39134
|
process.exit(1);
|
|
39134
39135
|
}
|
|
39135
|
-
const openclawDir = options.folder ? path25.resolve(options.folder) : path25.join(
|
|
39136
|
+
const openclawDir = options.folder ? path25.resolve(options.folder) : path25.join(os21.homedir(), ".openclaw");
|
|
39136
39137
|
const spinner = Y2();
|
|
39137
39138
|
const onProgress = (file, type) => {
|
|
39138
39139
|
spinner.message(`Installing: ${source_default.cyan(file)} ${source_default.gray(`(${type})`)}`);
|
|
@@ -39306,10 +39307,10 @@ var import_fs_extra23 = __toESM(require_lib4(), 1);
|
|
|
39306
39307
|
import { spawn as spawn2 } from "child_process";
|
|
39307
39308
|
import { execSync as execSync4 } from "child_process";
|
|
39308
39309
|
import path27 from "path";
|
|
39309
|
-
import
|
|
39310
|
+
import os22 from "os";
|
|
39310
39311
|
function checkCommand2(cmd) {
|
|
39311
39312
|
try {
|
|
39312
|
-
const isWindows2 =
|
|
39313
|
+
const isWindows2 = os22.platform() === "win32";
|
|
39313
39314
|
const whichCmd = isWindows2 ? `where ${cmd}` : `which ${cmd}`;
|
|
39314
39315
|
execSync4(whichCmd, { stdio: "ignore" });
|
|
39315
39316
|
return true;
|