claude-toolkit 0.16.0 → 0.17.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/CHANGELOG.md +20 -0
- package/README.md +54 -13
- package/bin/cli.ts +75 -19
- package/package.json +6 -7
- package/src/generator.ts +64 -26
- package/src/refresh-hint.ts +95 -0
- package/bin/postinstall.mjs +0 -69
- package/docs/README.md +0 -59
- package/docs/agents/code-reviewer.md +0 -76
- package/docs/agents/github-workflow.md +0 -98
- package/docs/best-practices/capacitor/README.md +0 -64
- package/docs/best-practices/capacitor/capacitor-8.md +0 -60
- package/docs/best-practices/capacitor/capgo-setup.md +0 -151
- package/docs/best-practices/capacitor/channels-and-rollouts.md +0 -101
- package/docs/best-practices/capacitor/live-updates-ota.md +0 -75
- package/docs/best-practices/capacitor/security-encryption.md +0 -68
- package/docs/best-practices/solidjs/README.md +0 -43
- package/docs/best-practices/solidjs/anti-patterns.md +0 -166
- package/docs/best-practices/solidjs/component-patterns.md +0 -131
- package/docs/best-practices/solidjs/context-and-global-state.md +0 -131
- package/docs/best-practices/solidjs/control-flow.md +0 -124
- package/docs/best-practices/solidjs/data-fetching.md +0 -205
- package/docs/best-practices/solidjs/effects-and-lifecycle.md +0 -113
- package/docs/best-practices/solidjs/performance.md +0 -100
- package/docs/best-practices/solidjs/props-patterns.md +0 -100
- package/docs/best-practices/solidjs/reactivity-model.md +0 -104
- package/docs/best-practices/solidjs/signals-and-state.md +0 -78
- package/docs/best-practices/solidjs/stores-and-nested-state.md +0 -111
- package/docs/best-practices/solidjs/typescript-integration.md +0 -186
- package/docs/best-practices/testing/README.md +0 -84
- package/docs/best-practices/testing/playwright-e2e.md +0 -649
- package/docs/best-practices/testing/storybook-interaction.md +0 -455
- package/docs/best-practices/testing/vitest-unit.md +0 -451
- package/docs/best-practices/typescript/README.md +0 -45
- package/docs/best-practices/typescript/any-and-unknown.md +0 -73
- package/docs/best-practices/typescript/deriving-vs-decoupling.md +0 -83
- package/docs/best-practices/typescript/discriminated-unions.md +0 -75
- package/docs/best-practices/typescript/enums-alternatives.md +0 -72
- package/docs/best-practices/typescript/essential-patterns.md +0 -119
- package/docs/best-practices/typescript/generics-patterns.md +0 -105
- package/docs/best-practices/typescript/micro-opinions.md +0 -87
- package/docs/best-practices/typescript/runtime-validation.md +0 -62
- package/docs/best-practices/typescript/satisfies-operator.md +0 -100
- package/docs/best-practices/typescript/tsconfig-cheat-sheet.md +0 -160
- package/docs/best-practices/typescript/type-organization.md +0 -64
- package/docs/best-practices/typescript/type-vs-interface.md +0 -80
- package/docs/commands/code-quality.md +0 -36
- package/docs/commands/onboard.md +0 -63
- package/docs/commands/pr-review.md +0 -91
- package/docs/commands/pr-summary.md +0 -50
- package/docs/commands/proto-check.md +0 -59
- package/docs/commands/ticket.md +0 -56
- package/docs/skills/code-style.md +0 -26
- package/docs/skills/systematic-debugging.md +0 -70
- package/docs/skills/testing-patterns.md +0 -140
- package/docs/skills/typescript-conventions.md +0 -283
- package/docs/skills/verification-before-completion.md +0 -103
- package/docs/stacks/capacitor-ota.md +0 -145
- package/docs/stacks/cloudflare-d1-kv.md +0 -144
- package/docs/stacks/esnext-idioms.md +0 -25
- package/docs/stacks/i18n-typesafe.md +0 -141
- package/docs/stacks/playwright-patterns.md +0 -179
- package/docs/stacks/protobuf-contracts.md +0 -85
- package/docs/stacks/rust-wasm-patterns.md +0 -106
- package/docs/stacks/solidjs-patterns.md +0 -110
- package/docs/stacks/storybook-patterns.md +0 -177
- package/docs/stacks/vanilla-extract-patterns.md +0 -115
- package/docs/stacks/vite-vitest-patterns.md +0 -485
package/bin/postinstall.mjs
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* claude-toolkit postinstall
|
|
5
|
-
*
|
|
6
|
-
* Runs in the consumer project after install. If a claude-toolkit.config.ts
|
|
7
|
-
* exists, it regenerates .claude/ — but only when the installed toolkit version
|
|
8
|
-
* differs from the one that last generated it, so it fires on a toolkit update,
|
|
9
|
-
* not on every install.
|
|
10
|
-
*
|
|
11
|
-
* Guarantees:
|
|
12
|
-
* - Never fails the consumer's install (all errors swallowed; always exit 0).
|
|
13
|
-
* - Never runs inside the toolkit's own repo (dev install).
|
|
14
|
-
* - Never creates or edits the committed config — only regenerates .claude/.
|
|
15
|
-
* - Writes no committed files when there's no config (prints a one-line nudge).
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { spawnSync } from "node:child_process";
|
|
19
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
20
|
-
import { dirname, join, resolve } from "node:path";
|
|
21
|
-
import { fileURLToPath } from "node:url";
|
|
22
|
-
|
|
23
|
-
function readJsonSafe(path) {
|
|
24
|
-
try {
|
|
25
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
26
|
-
} catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
const toolkitDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
33
|
-
// INIT_CWD is set by npm/bun/pnpm/yarn to the dir where install was invoked.
|
|
34
|
-
const consumerRoot = resolve(process.env.INIT_CWD || process.cwd());
|
|
35
|
-
|
|
36
|
-
// 1. Skip when running inside the toolkit's own repo (dev install).
|
|
37
|
-
if (consumerRoot === toolkitDir) process.exit(0);
|
|
38
|
-
const consumerPkg = readJsonSafe(join(consumerRoot, "package.json"));
|
|
39
|
-
if (consumerPkg?.name === "claude-toolkit") process.exit(0);
|
|
40
|
-
|
|
41
|
-
// 2. No config -> stay hands-off; just nudge once. Never write committed files.
|
|
42
|
-
const hasConfig =
|
|
43
|
-
existsSync(join(consumerRoot, "claude-toolkit.config.ts")) ||
|
|
44
|
-
existsSync(join(consumerRoot, "claude-toolkit.config.js"));
|
|
45
|
-
if (!hasConfig) {
|
|
46
|
-
console.log(
|
|
47
|
-
'[claude-toolkit] Run "bunx claude-toolkit" to set up your Claude Code config (.claude/).',
|
|
48
|
-
);
|
|
49
|
-
process.exit(0);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 3. Only regenerate when the toolkit version changed since the last generation.
|
|
53
|
-
const toolkitVersion = readJsonSafe(join(toolkitDir, "package.json"))?.version;
|
|
54
|
-
const markerPath = join(consumerRoot, ".claude", ".toolkit-version");
|
|
55
|
-
const lastVersion = existsSync(markerPath) ? readFileSync(markerPath, "utf8").trim() : null;
|
|
56
|
-
if (toolkitVersion && lastVersion === toolkitVersion) process.exit(0);
|
|
57
|
-
|
|
58
|
-
// 4. Regenerate via the CLI (reuses config loading + clean rebuild). Best-effort:
|
|
59
|
-
// spawnSync sets `.error` if bun is missing — we ignore it rather than fail.
|
|
60
|
-
spawnSync("bun", [join(toolkitDir, "bin", "cli.ts"), "postinstall"], {
|
|
61
|
-
cwd: consumerRoot,
|
|
62
|
-
stdio: "inherit",
|
|
63
|
-
env: { ...process.env, INIT_CWD: consumerRoot },
|
|
64
|
-
});
|
|
65
|
-
} catch {
|
|
66
|
-
// Never break the consumer's install over config regeneration.
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
process.exit(0);
|
package/docs/README.md
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# claude-toolkit Documentation
|
|
2
|
-
|
|
3
|
-
Complete reference for all skills, commands, and agents provided by claude-toolkit.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
Run `bunx claude-toolkit` in your project — on the first run it creates `claude-toolkit.config.ts` (pre-filled from stack detection) and generates `.claude/`. Run it again anytime to regenerate; add `--update` to pull newly-detected stacks into the config. `.claude/` also regenerates automatically on install when the toolkit version changes. See the [README](../README.md#cli-commands) for the full CLI.
|
|
8
|
-
|
|
9
|
-
## Core Skills
|
|
10
|
-
|
|
11
|
-
Skills that are always included regardless of stack configuration.
|
|
12
|
-
|
|
13
|
-
| Skill | Description |
|
|
14
|
-
| -------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
15
|
-
| [ct-systematic-debugging](skills/systematic-debugging.md) | Four-phase methodology for diagnosing and fixing bugs without guesswork |
|
|
16
|
-
| [ct-testing-patterns](skills/testing-patterns.md) | Framework-agnostic TDD practices, mocking strategies, and test organization |
|
|
17
|
-
| [ct-typescript-conventions](skills/typescript-conventions.md) | Strict TypeScript patterns, plus TS7 native-compiler selection |
|
|
18
|
-
| [ct-verification-before-completion](skills/verification-before-completion.md) | Evidence-based completion claims with structured verification checklist |
|
|
19
|
-
| [ct-code-style](skills/code-style.md) | Code structure & style: guard clauses, lookup tables, no magic values |
|
|
20
|
-
|
|
21
|
-
## Commands
|
|
22
|
-
|
|
23
|
-
Slash commands available in Claude Code sessions.
|
|
24
|
-
|
|
25
|
-
| Command | Description |
|
|
26
|
-
| ----------------------------------------- | -------------------------------------------------------------------------- |
|
|
27
|
-
| [/ct:code-quality](commands/code-quality.md) | Run lint, typecheck, and format checks with structured reporting |
|
|
28
|
-
| [/ct:pr-review](commands/pr-review.md) | Checklist-based code review against project standards |
|
|
29
|
-
| [/ct:pr-summary](commands/pr-summary.md) | Generate a structured PR summary from branch diff and commits |
|
|
30
|
-
| [/ct:onboard](commands/onboard.md) | Systematically explore and understand a codebase area |
|
|
31
|
-
| [/ct:ticket](commands/ticket.md) | Work end-to-end on a ticket: understand, explore, plan, implement, deliver |
|
|
32
|
-
| [/ct:proto-check](commands/proto-check.md) | Validate protobuf definitions, lint, breaking changes, and code generation |
|
|
33
|
-
|
|
34
|
-
## Agents
|
|
35
|
-
|
|
36
|
-
Specialized agents with dedicated models and review capabilities.
|
|
37
|
-
|
|
38
|
-
| Agent | Model | Description |
|
|
39
|
-
| -------------------------------------------- | ------ | -------------------------------------------------------------------------- |
|
|
40
|
-
| [ct-code-reviewer](agents/ct-code-reviewer.md) | Opus | Senior code reviewer with stack-aware analysis and severity-based feedback |
|
|
41
|
-
| [ct-github-workflow](agents/ct-github-workflow.md) | Sonnet | Git workflow assistant for branching, commits, and PR creation |
|
|
42
|
-
|
|
43
|
-
## Stack Skills
|
|
44
|
-
|
|
45
|
-
Stack-specific skills activated based on your `claude-toolkit.config.ts` configuration.
|
|
46
|
-
|
|
47
|
-
| Skill | Stack | Description |
|
|
48
|
-
| -------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------ |
|
|
49
|
-
| [ct-solidjs-patterns](stacks/solidjs-patterns.md) | `solidjs` | Reactivity, signals, effects, component patterns, and props handling |
|
|
50
|
-
| [ct-vite-vitest-patterns](stacks/vite-vitest-patterns.md) | `vite` | Vite build config, plugins, env vars, Vitest testing, coverage, browser mode |
|
|
51
|
-
| [ct-vanilla-extract-patterns](stacks/vanilla-extract-patterns.md) | `vanilla-extract` | Type-safe CSS with zero runtime: styles, recipes, themes, sprinkles |
|
|
52
|
-
| [ct-rust-wasm-patterns](stacks/rust-wasm-patterns.md) | `rust-wasm` | Rust WASM for Cloudflare Workers: routing, handlers, env bindings |
|
|
53
|
-
| [ct-protobuf-contracts](stacks/protobuf-contracts.md) | `protobuf` | Protocol Buffers for API contracts: schema design, versioning, code generation |
|
|
54
|
-
| [ct-cloudflare-d1-kv](stacks/cloudflare-d1-kv.md) | `cloudflare` | D1 database and KV cache: queries, migrations, caching patterns |
|
|
55
|
-
| [ct-i18n-typesafe](stacks/i18n-typesafe.md) | `i18n-typesafe` | Type-safe internationalization with compile-time key checking |
|
|
56
|
-
| [ct-playwright-patterns](stacks/playwright-patterns.md) | `playwright` | E2E testing with Page Objects, fixtures, auth, network mocking, CI/CD |
|
|
57
|
-
| [ct-storybook-patterns](stacks/storybook-patterns.md) | `storybook` | Interaction testing, CSF 3, play functions, a11y, visual regression |
|
|
58
|
-
| [ct-capacitor-ota](stacks/capacitor-ota.md) | `capacitor` | Capacitor 8 native runtime and Capgo OTA live updates, channels, encryption |
|
|
59
|
-
| [ct-esnext-idioms](stacks/esnext-idioms.md) | `esnext` | Modern ECMAScript runtime idioms: Temporal, iterator helpers, using, structuredClone |
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Code Reviewer Agent
|
|
2
|
-
|
|
3
|
-
> Senior code reviewer with stack-aware analysis.
|
|
4
|
-
|
|
5
|
-
**Type:** Agent
|
|
6
|
-
**Model:** Opus (highest capability)
|
|
7
|
-
**Source:** [`core/agents/ct-code-reviewer.md`](../core/agents/ct-code-reviewer.md)
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
A senior code reviewer agent that thoroughly reviews code changes, providing actionable feedback organized by severity. It adapts review criteria to the project's stack and conventions.
|
|
12
|
-
|
|
13
|
-
## Review Process
|
|
14
|
-
|
|
15
|
-
1. **Read the full diff** and all changed files in their entirety -- understands surrounding context, not just changed lines
|
|
16
|
-
2. **Identify the stack** by reading project config files -- adapts criteria accordingly
|
|
17
|
-
3. **Apply the review checklist** to every changed file
|
|
18
|
-
4. **Compile findings** with severity levels and specific file/line references
|
|
19
|
-
|
|
20
|
-
## Review Checklist
|
|
21
|
-
|
|
22
|
-
### Critical Issues
|
|
23
|
-
|
|
24
|
-
| Category | Checks |
|
|
25
|
-
| --- | --- |
|
|
26
|
-
| **Logic Correctness** | Off-by-one errors, inverted conditions, unhandled edge cases, race conditions, incorrect state transitions, dead code |
|
|
27
|
-
| **Error Handling** | Swallowed errors, missing context in error messages, leaked resources, unhandled crashes, missing error boundaries |
|
|
28
|
-
| **Security** | SQL/XSS/command injection, missing auth, secrets in code, CORS issues, missing rate limiting |
|
|
29
|
-
|
|
30
|
-
### Warnings
|
|
31
|
-
|
|
32
|
-
| Category | Checks |
|
|
33
|
-
| --- | --- |
|
|
34
|
-
| **Type Safety** | `any` usage, unsafe casts, missing null checks, implicit coercions, overly broad generics |
|
|
35
|
-
| **Performance** | Unnecessary re-renders, N+1 queries, missing pagination, sync-when-should-be-async, memory leaks |
|
|
36
|
-
| **Testing** | New behavior without tests, implementation-detail tests, missing edge cases, flaky patterns |
|
|
37
|
-
|
|
38
|
-
### Suggestions
|
|
39
|
-
|
|
40
|
-
| Category | Checks |
|
|
41
|
-
| --- | --- |
|
|
42
|
-
| **Naming and Readability** | Misleading names, abbreviations, functions doing too much, deep nesting, comments describing "what" instead of "why" |
|
|
43
|
-
|
|
44
|
-
## Output Format
|
|
45
|
-
|
|
46
|
-
```markdown
|
|
47
|
-
## Code Review
|
|
48
|
-
|
|
49
|
-
**Reviewed:** {files or PR description}
|
|
50
|
-
**Verdict:** APPROVE | REQUEST_CHANGES | COMMENT
|
|
51
|
-
|
|
52
|
-
### Critical ({count})
|
|
53
|
-
### Warnings ({count})
|
|
54
|
-
### Suggestions ({count})
|
|
55
|
-
### Looks Good
|
|
56
|
-
### Summary
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Best Practices Reference
|
|
60
|
-
|
|
61
|
-
Stack-aware review informed by these guides:
|
|
62
|
-
|
|
63
|
-
| Review Area | Guide |
|
|
64
|
-
| --- | --- |
|
|
65
|
-
| `any` usage, type safety patterns | [any & unknown](../best-practices/typescript/any-and-unknown.md) |
|
|
66
|
-
| `type` vs `interface` conventions | [Type vs Interface](../best-practices/typescript/type-vs-interface.md) |
|
|
67
|
-
| SolidJS-specific mistakes (destructuring, effects) | [SolidJS Anti-Patterns](../best-practices/solidjs/anti-patterns.md) |
|
|
68
|
-
| Props reactivity issues | [SolidJS Props Patterns](../best-practices/solidjs/props-patterns.md) |
|
|
69
|
-
|
|
70
|
-
## Principles
|
|
71
|
-
|
|
72
|
-
- **Be specific** -- "This catch block on line 42 swallows the database connection error" is useful; "This could be improved" is not
|
|
73
|
-
- **Distinguish severity honestly** -- not everything is critical, not everything is a suggestion
|
|
74
|
-
- **Acknowledge good work** -- reviews that only list problems are incomplete
|
|
75
|
-
- **Stay in scope** -- review the changes, not the entire codebase
|
|
76
|
-
- **Offer alternatives, not just objections** -- suggest a fix or direction for every problem flagged
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# GitHub Workflow Agent
|
|
2
|
-
|
|
3
|
-
> Git workflow assistant for branching, commits, and PRs.
|
|
4
|
-
|
|
5
|
-
**Type:** Agent
|
|
6
|
-
**Model:** Sonnet
|
|
7
|
-
**Source:** [`core/agents/ct-github-workflow.md`](../core/agents/ct-github-workflow.md)
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
A Git workflow assistant that helps with branch management, commit formatting, and pull request creation following consistent conventions.
|
|
12
|
-
|
|
13
|
-
## Branch Naming
|
|
14
|
-
|
|
15
|
-
Format: `{prefix}/{short-description}`
|
|
16
|
-
|
|
17
|
-
| Prefix | Use Case | Example |
|
|
18
|
-
|---|---|---|
|
|
19
|
-
| `feat` | New feature | `feat/user-avatar-upload` |
|
|
20
|
-
| `fix` | Bug fix | `fix/login-redirect-loop` |
|
|
21
|
-
| `chore` | Maintenance, deps, config | `chore/upgrade-eslint-9` |
|
|
22
|
-
| `refactor` | Code restructuring | `refactor/extract-auth-service` |
|
|
23
|
-
| `docs` | Documentation only | `docs/api-authentication` |
|
|
24
|
-
| `test` | Test additions or fixes | `test/payment-edge-cases` |
|
|
25
|
-
| `hotfix` | Urgent production fix | `hotfix/null-crash-checkout` |
|
|
26
|
-
|
|
27
|
-
**Rules:** lowercase with hyphens, under 4 words, specific enough to identify at a glance.
|
|
28
|
-
|
|
29
|
-
## Conventional Commits
|
|
30
|
-
|
|
31
|
-
Format: `{type}({scope}): {description}`
|
|
32
|
-
|
|
33
|
-
| Type | When |
|
|
34
|
-
|---|---|
|
|
35
|
-
| `feat` | New feature visible to users |
|
|
36
|
-
| `fix` | Bug fix |
|
|
37
|
-
| `refactor` | Code change with no behavior difference |
|
|
38
|
-
| `test` | Adding or updating tests |
|
|
39
|
-
| `docs` | Documentation changes |
|
|
40
|
-
| `chore` | Build, CI, dependency updates |
|
|
41
|
-
| `perf` | Performance improvement |
|
|
42
|
-
| `style` | Formatting, whitespace (no logic change) |
|
|
43
|
-
|
|
44
|
-
**Examples:**
|
|
45
|
-
```
|
|
46
|
-
feat(auth): add JWT refresh token rotation
|
|
47
|
-
fix(cart): prevent duplicate items on rapid clicks
|
|
48
|
-
refactor(api): extract validation middleware from route handlers
|
|
49
|
-
chore(deps): upgrade next.js to 15.1
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Rules:**
|
|
53
|
-
- Scope is optional but encouraged (module or feature area)
|
|
54
|
-
- Description starts lowercase, imperative mood ("add" not "added")
|
|
55
|
-
- Body explains "why" not "what"
|
|
56
|
-
- Breaking changes: add `!` after type/scope (e.g., `feat(api)!: change auth response format`)
|
|
57
|
-
|
|
58
|
-
## PR Creation Workflow
|
|
59
|
-
|
|
60
|
-
### 1. Pre-flight Checks
|
|
61
|
-
- Tests pass
|
|
62
|
-
- Types check
|
|
63
|
-
- No lint errors
|
|
64
|
-
- No merge conflicts
|
|
65
|
-
|
|
66
|
-
### 2. PR Title
|
|
67
|
-
Same conventional format as commits, under 70 characters.
|
|
68
|
-
|
|
69
|
-
### 3. PR Description
|
|
70
|
-
```markdown
|
|
71
|
-
## Summary
|
|
72
|
-
{1-3 bullet points: what and why}
|
|
73
|
-
|
|
74
|
-
## Changes
|
|
75
|
-
- {Grouped list of meaningful changes}
|
|
76
|
-
|
|
77
|
-
## Testing
|
|
78
|
-
- [ ] {How to test}
|
|
79
|
-
- [ ] {Edge cases verified}
|
|
80
|
-
|
|
81
|
-
## Notes
|
|
82
|
-
{Trade-offs, follow-up work, deployment considerations}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 4. Pre-Open Checklist
|
|
86
|
-
- Branch up to date with base
|
|
87
|
-
- All tests pass
|
|
88
|
-
- Types check cleanly
|
|
89
|
-
- No lint errors
|
|
90
|
-
- PR title follows conventional format
|
|
91
|
-
- Changes are focused (one concern per PR)
|
|
92
|
-
|
|
93
|
-
## Principles
|
|
94
|
-
|
|
95
|
-
- **Small PRs** -- if a PR touches more than 10 files or 300 lines, consider splitting
|
|
96
|
-
- **One concern per PR** -- do not mix a feature with a refactor with a dependency upgrade
|
|
97
|
-
- **Commit history matters** -- each commit should be a logical, buildable unit
|
|
98
|
-
- **PR description is for the reviewer** -- write it to save their time
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Capacitor & OTA Best Practices
|
|
2
|
-
|
|
3
|
-
> A curated collection of best practices for Capacitor 8 native apps and Capgo over-the-air (OTA) live updates, sourced from official Capacitor documentation, the Capgo docs and blog, and the plugin maintainers as of June 2026.
|
|
4
|
-
|
|
5
|
-
Capacitor wraps a web app (your `webDir` bundle) in a native iOS/Android shell. **OTA** lets you replace that web bundle on installed devices in minutes — without an app store review cycle. Capgo (`@capgo/capacitor-updater`) is the live-update layer that delivers, verifies, and rolls back those bundles.
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
┌─────────────────────────────┐
|
|
9
|
-
│ Native shell (store) │ ← Capacitor core + plugins; ships via App Store / Play
|
|
10
|
-
│ ┌───────────────────────┐ │ Changes here REQUIRE a new binary.
|
|
11
|
-
│ │ Web bundle (OTA) │ │ ← JS / HTML / CSS; swapped by Capgo in minutes.
|
|
12
|
-
│ │ notifyAppReady() ✓ │ │ Changes here ship over the air.
|
|
13
|
-
│ └───────────────────────┘ │
|
|
14
|
-
└─────────────────────────────┘
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## The Two Layers — and the Golden Rule
|
|
18
|
-
|
|
19
|
-
| Layer | What it is | How it ships | Review latency |
|
|
20
|
-
| -------------- | ------------------------------------------- | --------------------------- | ------------------- |
|
|
21
|
-
| **Native** | Capacitor core, plugins, native deps | App Store / Google Play | Hours to days |
|
|
22
|
-
| **Web (OTA)** | Your compiled `webDir` (JS/HTML/CSS/assets) | Capgo channel swap | Minutes |
|
|
23
|
-
|
|
24
|
-
**Golden rule:** OTA the web layer only. If a change needs a native API the installed shell doesn't have — a new plugin, a native dependency, a Capacitor major bump — it **must** go through the store first. OTA-ing a native contract mismatch crashes the app. Every other rule in this guide follows from this one.
|
|
25
|
-
|
|
26
|
-
## When to Use Which Channel
|
|
27
|
-
|
|
28
|
-
| Question | Answer |
|
|
29
|
-
| ----------------------------------------------------------------- | --------------------------------------- |
|
|
30
|
-
| Did I change native code, add a plugin, or bump Capacitor major? | **Store binary** (then OTA on top) |
|
|
31
|
-
| Bug fix / copy change / styling / feature in JS only? | **OTA** to `production` |
|
|
32
|
-
| Needs QA sign-off before users see it? | **OTA** to `staging`, promote later |
|
|
33
|
-
| Testing on dev/emulator builds? | **OTA** to `development` |
|
|
34
|
-
| Need to undo a bad release right now? | **Channel rollback** (crown icon) |
|
|
35
|
-
|
|
36
|
-
## Technology Versions (as of June 2026)
|
|
37
|
-
|
|
38
|
-
| Tool | Version | Notes |
|
|
39
|
-
| -------------------------- | ------- | ---------------------------------------------------------------- |
|
|
40
|
-
| `@capacitor/core` & CLI | ^8.3.x | 8.3.1 (2026-04-16); Node 22+ required |
|
|
41
|
-
| `@capacitor/ios` | ^8.3.x | iOS 15.0 target, Xcode 26+, SPM default for new projects |
|
|
42
|
-
| `@capacitor/android` | ^8.3.x | minSdk 24, compileSdk/targetSdk 36, Gradle 8.14.3, Kotlin 2.2.20 |
|
|
43
|
-
| `@capgo/capacitor-updater` | ^8.x | Major tracks Capacitor major; v8 stores channel locally |
|
|
44
|
-
| `@capgo/cli` | latest | `npx @capgo/cli@latest …` — pin in CI |
|
|
45
|
-
|
|
46
|
-
## Shared Principles
|
|
47
|
-
|
|
48
|
-
1. **`notifyAppReady()` is non-negotiable.** Call it at the top of bootstrap. Without it, every OTA bundle auto-rolls back after `appReadyTimeout`.
|
|
49
|
-
2. **Match the bundle to the shell.** A web bundle is only valid against the native version that shipped it. Use channel version gates to prevent mismatches.
|
|
50
|
-
3. **Stage every rollout.** Canary to ~10%, widen over 24h. Instant rollback beats instant deploy.
|
|
51
|
-
4. **Sign your bundles.** End-to-end encryption (RSA-2048 + AES-256) means only your users can read an update — keep the private key out of git.
|
|
52
|
-
5. **Keep the cloud in control of production.** Omit `defaultChannel` from production binaries so the dashboard default governs rollout and rollback.
|
|
53
|
-
6. **Monitor before you widen.** Watch the `appReady` / `downloadFailed` ratio; a spike is your signal to roll back.
|
|
54
|
-
7. **Pin tooling.** Unpinned `@capgo/cli@latest` in CI can change upload behavior between runs.
|
|
55
|
-
|
|
56
|
-
## Guides
|
|
57
|
-
|
|
58
|
-
| Guide | Summary |
|
|
59
|
-
| ------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
60
|
-
| [Capacitor 8 Platform](capacitor-8.md) | Version floor, breaking changes, SPM-by-default, SystemBars, upgrade checklist. |
|
|
61
|
-
| [Live Updates & OTA Strategy](live-updates-ota.md) | What to OTA vs ship native, performance, delta updates, scheduling. |
|
|
62
|
-
| [Capgo Setup & API](capgo-setup.md) | Plugin install, config, `notifyAppReady`, autoUpdate modes, manual flow, CLI. |
|
|
63
|
-
| [Channels & Staged Rollouts](channels-and-rollouts.md) | Channel ladder, precedence, canary rollouts, rollback, monitoring. |
|
|
64
|
-
| [Security & Encryption](security-encryption.md) | E2E encryption (v2), key management, code signing, store compliance. |
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Capacitor 8 Platform
|
|
2
|
-
|
|
3
|
-
> Capacitor 8 raised the platform floor across the board. Get the toolchain right before touching OTA — a mismatched native baseline is the first thing that breaks live updates.
|
|
4
|
-
|
|
5
|
-
Latest at time of writing: **8.3.1** (2026-04-16). 8.3.0 (2026-03-25) and 8.2.0 (2026-03-06) precede it.
|
|
6
|
-
|
|
7
|
-
## Minimum Requirements
|
|
8
|
-
|
|
9
|
-
| Area | Requirement |
|
|
10
|
-
| ------- | --------------------------------------------------------------------------- |
|
|
11
|
-
| Node | **22+** (latest LTS recommended) |
|
|
12
|
-
| iOS | Xcode **26.0+**, deployment target **15.0** |
|
|
13
|
-
| Android | Android Studio Otter (2025.2.1)+, `minSdk 24`, `compileSdk 36`, `targetSdk 36` |
|
|
14
|
-
| Gradle | Android Gradle plugin **8.13.0**, wrapper **8.14.3**, Kotlin **2.2.20** |
|
|
15
|
-
|
|
16
|
-
## Headline Changes
|
|
17
|
-
|
|
18
|
-
### Swift Package Manager is the default (iOS)
|
|
19
|
-
|
|
20
|
-
New iOS projects scaffold with **SPM instead of CocoaPods**. Existing CocoaPods projects keep working — the ecosystem is migrating, not forcing a cutover. 8.3.0 added experimental config for `swift-tools-version` and support for SPM package traits in the generated `Package.swift`.
|
|
21
|
-
|
|
22
|
-
### Edge-to-edge via the SystemBars plugin (Android)
|
|
23
|
-
|
|
24
|
-
An internal `SystemBars` plugin now handles status/navigation bar appearance for immersive layouts automatically, with a public API for fine control. It version-gates behavior and coexists with `@capacitor/status-bar`. Consequently the old config flag **`android.adjustMarginsForEdgeToEdge` was removed** — use SystemBars instead.
|
|
25
|
-
|
|
26
|
-
## Breaking Changes Checklist
|
|
27
|
-
|
|
28
|
-
When upgrading to Capacitor 8:
|
|
29
|
-
|
|
30
|
-
- [ ] **Node 22+** on every dev machine and CI runner.
|
|
31
|
-
- [ ] **Android config syntax:** Gradle properties now require `=` (e.g. `compileSdk = 36`, not `compileSdk 36`).
|
|
32
|
-
- [ ] **Android layout rename:** `bridge_layout_main.xml` → `capacitor_bridge_layout_main.xml`.
|
|
33
|
-
- [ ] **Android resize:** add `density` to `configChanges` in `AndroidManifest.xml` to stop the WebView reloading on resize.
|
|
34
|
-
- [ ] **Remove `android.adjustMarginsForEdgeToEdge`** from `capacitor.config` — replaced by SystemBars.
|
|
35
|
-
- [ ] **iOS `appendUserAgent`:** the fixed concatenation may need a leading space to preserve your intended user-agent string.
|
|
36
|
-
- [ ] **iOS lifecycle:** the framework now emits `viewDidAppear` / `viewWillTransition` — delete any custom extensions that duplicated this.
|
|
37
|
-
|
|
38
|
-
## 8.2–8.3 Notable Fixes
|
|
39
|
-
|
|
40
|
-
These land automatically on patch upgrades but are worth knowing because they touch OTA-adjacent behavior:
|
|
41
|
-
|
|
42
|
-
- **Android `server.url` with paths** is now parsed correctly (8.3.0) — relevant if you point the WebView at a custom/self-hosted update host.
|
|
43
|
-
- **Android `isNewBinary()`** handles a null `versionName` (8.3.1) — the check that decides whether a native update invalidates OTA bundles.
|
|
44
|
-
- **HTTP `fetch`** handles `URL` objects and form-data boundary extraction (8.3.0/8.3.1).
|
|
45
|
-
- **CLI** inlines CSS sourcemaps alongside JS (8.3.0) and respects `CAPACITOR_COCOAPODS_PATH` (8.3.1).
|
|
46
|
-
|
|
47
|
-
## Keeping Native and OTA in Lockstep
|
|
48
|
-
|
|
49
|
-
The single most important interaction: **a native upgrade invalidates incompatible OTA bundles.** `resetWhenUpdate: true` (the Capgo default) wipes downloaded bundles when the native app updates, so users fall back to the bundle baked into the new binary rather than running a stale OTA bundle against new native code. Keep it on unless you have a specific reason not to.
|
|
50
|
-
|
|
51
|
-
When you bump Capacitor or add a plugin:
|
|
52
|
-
|
|
53
|
-
1. Ship a new store binary with the updated native layer.
|
|
54
|
-
2. Bump your bundle's version so old shells don't pull a bundle meant for the new native contract.
|
|
55
|
-
3. Use channel version gates (`--disable-auto-update major|minor`) to enforce the boundary.
|
|
56
|
-
|
|
57
|
-
## See Also
|
|
58
|
-
|
|
59
|
-
- [Live Updates & OTA Strategy](live-updates-ota.md) — what's safe to OTA on top of a given binary
|
|
60
|
-
- [Channels & Staged Rollouts](channels-and-rollouts.md) — version gates that enforce the native/web contract
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Capgo Setup & API
|
|
2
|
-
|
|
3
|
-
> `@capgo/capacitor-updater` ships in three modes: fully managed (Capgo Cloud), self-hosted (your own update server), or manual (you drive every download/apply in JS). This guide covers the managed path and the manual escape hatch.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i @capgo/capacitor-updater && npx cap sync
|
|
9
|
-
npx @capgo/cli@latest init <API_KEY>
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
`init` is an interactive onboarding: it registers the app in Capgo Cloud, injects the `notifyAppReady()` call, builds, uploads the first bundle, and verifies the update round-trips. Run it once per app.
|
|
13
|
-
|
|
14
|
-
## notifyAppReady() — Read This First
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
import { CapacitorUpdater } from "@capgo/capacitor-updater";
|
|
18
|
-
|
|
19
|
-
// As early as possible in bootstrap, before heavy async work.
|
|
20
|
-
CapacitorUpdater.notifyAppReady();
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The plugin arms a timer (`appReadyTimeout`, default **10000ms**) the moment a bundle loads. Call `notifyAppReady()` before it fires and the bundle is confirmed; miss it and the plugin **auto-rolls back** to the previous bundle. This is the mechanism that makes a broken release self-heal — never remove it, and don't bury it behind slow startup code.
|
|
24
|
-
|
|
25
|
-
## Configuration Reference
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
// capacitor.config.ts
|
|
29
|
-
import type { CapacitorConfig } from "@capacitor/cli";
|
|
30
|
-
|
|
31
|
-
const config: CapacitorConfig = {
|
|
32
|
-
appId: "com.example.app",
|
|
33
|
-
appName: "Example",
|
|
34
|
-
webDir: "dist",
|
|
35
|
-
plugins: {
|
|
36
|
-
CapacitorUpdater: {
|
|
37
|
-
autoUpdate: "atBackground",
|
|
38
|
-
appReadyTimeout: 10000,
|
|
39
|
-
responseTimeout: 20,
|
|
40
|
-
autoDeleteFailed: true,
|
|
41
|
-
autoDeletePrevious: true,
|
|
42
|
-
resetWhenUpdate: true,
|
|
43
|
-
// defaultChannel: "Development", // TEST/QA BUILDS ONLY
|
|
44
|
-
// publicKey: "...", // injected by `key create` for E2E encryption
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export default config;
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
| Setting | Default | Purpose |
|
|
53
|
-
| -------------------- | -------------------------------------- | ------------------------------------------------------------ |
|
|
54
|
-
| `autoUpdate` | `"atBackground"` | When to apply downloaded updates (see table below) |
|
|
55
|
-
| `appReadyTimeout` | `10000` (ms) | Grace period for `notifyAppReady()` before rollback |
|
|
56
|
-
| `responseTimeout` | `20` (s) | Update-server API call timeout |
|
|
57
|
-
| `periodCheckDelay` | `600` (s) | Poll interval; **cannot be < 600** |
|
|
58
|
-
| `autoDeleteFailed` | `true` | Remove bundles that failed to apply |
|
|
59
|
-
| `autoDeletePrevious` | `true` | Remove the prior bundle after a successful update |
|
|
60
|
-
| `resetWhenUpdate` | `true` | Wipe OTA bundles when the native app updates |
|
|
61
|
-
| `defaultChannel` | _(unset)_ | Pin a channel — **test builds only** |
|
|
62
|
-
| `allowModifyUrl` | `false` | Let JS change update/stats/channel URLs at runtime |
|
|
63
|
-
| `publicKey` | _(unset)_ | RSA public key for end-to-end encryption (v2) |
|
|
64
|
-
| `updateUrl` | `https://plugin.capgo.app/updates` | Update-check endpoint (override for self-hosted) |
|
|
65
|
-
| `statsUrl` | `https://plugin.capgo.app/stats` | Stats endpoint |
|
|
66
|
-
| `channelUrl` | `https://plugin.capgo.app/channel_self`| Channel self-assignment endpoint |
|
|
67
|
-
|
|
68
|
-
> `directUpdate` is deprecated. Use the `autoUpdate` string modes instead.
|
|
69
|
-
|
|
70
|
-
## autoUpdate Modes
|
|
71
|
-
|
|
72
|
-
| Value | Behavior |
|
|
73
|
-
| ---------------------------- | -------------------------------------------------------------- |
|
|
74
|
-
| `false` / `"off"` | No automatic updates — you drive the lifecycle from JS |
|
|
75
|
-
| `"atBackground"` *(default)* | Download silently; apply when the app moves to the background |
|
|
76
|
-
| `"atInstall"` | Apply immediately after a fresh install / native update |
|
|
77
|
-
| `"onLaunch"` | Apply immediately on next launch, then revert to background |
|
|
78
|
-
| `"always"` | Apply immediately whenever an update check runs |
|
|
79
|
-
| `"onlyDownload"` | Download but never auto-apply; emits `updateAvailable` |
|
|
80
|
-
|
|
81
|
-
**Default lifecycle:** on launch Capgo checks the channel → downloads any new bundle silently → waits for background/close → user gets the update on next launch. Seamless, no spinner.
|
|
82
|
-
|
|
83
|
-
## Manual Mode
|
|
84
|
-
|
|
85
|
-
Set `autoUpdate: false` to control everything yourself — useful for custom UX (e.g. "Update available" prompts) or applying only on explicit user action.
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { CapacitorUpdater } from "@capgo/capacitor-updater";
|
|
89
|
-
import { App } from "@capacitor/app";
|
|
90
|
-
import { SplashScreen } from "@capacitor/splash-screen";
|
|
91
|
-
|
|
92
|
-
CapacitorUpdater.addListener("download", ({ percent }) => {
|
|
93
|
-
console.log(`Downloading: ${percent}%`);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
App.addListener("appStateChange", async ({ isActive }) => {
|
|
97
|
-
if (isActive) {
|
|
98
|
-
const latest = await CapacitorUpdater.getLatest();
|
|
99
|
-
if (latest.url) {
|
|
100
|
-
const bundle = await CapacitorUpdater.download({
|
|
101
|
-
version: latest.version,
|
|
102
|
-
url: latest.url,
|
|
103
|
-
});
|
|
104
|
-
await CapacitorUpdater.next({ id: bundle.id }); // queue for next background
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Core methods
|
|
111
|
-
|
|
112
|
-
| Method | Purpose |
|
|
113
|
-
| ----------------- | -------------------------------------------------------------- |
|
|
114
|
-
| `notifyAppReady()`| Confirm the current bundle booted (always required) |
|
|
115
|
-
| `getLatest()` | Query the server for the latest bundle metadata |
|
|
116
|
-
| `download()` | Download a bundle by `{ version, url }` |
|
|
117
|
-
| `next({ id })` | Queue a bundle to apply on next background |
|
|
118
|
-
| `set({ id })` | Apply a bundle now — **destroys the JS context** (hard reload) |
|
|
119
|
-
| `current()` | Inspect the active bundle + native version |
|
|
120
|
-
| `reload()` | Apply a pending update without backgrounding |
|
|
121
|
-
| `reset()` | Revert to the bundle baked into the native binary |
|
|
122
|
-
| `setChannel()` | Switch the device's channel at runtime (v8+, self-assign) |
|
|
123
|
-
|
|
124
|
-
### Events
|
|
125
|
-
|
|
126
|
-
`download` · `downloadComplete` · `updateAvailable` · `downloadFailed` · `appReady` · `majorAvailable`
|
|
127
|
-
|
|
128
|
-
Subscribe to `downloadFailed` and `appReady` for monitoring; subscribe to `majorAvailable` to detect a bundle that requires a native update you can't OTA.
|
|
129
|
-
|
|
130
|
-
## CLI Cheat Sheet
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
npx @capgo/cli@latest login <API_KEY> # store key (--local to scope to repo)
|
|
134
|
-
npx @capgo/cli@latest app add com.example.app # register an app
|
|
135
|
-
npx @capgo/cli@latest bundle upload --channel=production # build → upload → assign
|
|
136
|
-
npx @capgo/cli@latest bundle upload --key-v2 --channel=production # encrypted upload
|
|
137
|
-
npx @capgo/cli@latest bundle upload --delta-only # require delta-capable clients
|
|
138
|
-
npx @capgo/cli@latest bundle compatibility -c production # check native compatibility first
|
|
139
|
-
npx @capgo/cli@latest channel set production -s default # set the cloud default channel
|
|
140
|
-
npx @capgo/cli@latest key create # generate the E2E key pair
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Useful `bundle upload` flags: `--channel`, `--key-v2` / `--no-key`, `--delta` / `--delta-only`, `--external` (link your own storage), `--tus` (resumable upload), `--encrypted-checksum`.
|
|
144
|
-
|
|
145
|
-
**Pin the CLI version in CI** (`@capgo/cli@8.x` rather than `@latest`) so upload behavior doesn't change between pipeline runs.
|
|
146
|
-
|
|
147
|
-
## See Also
|
|
148
|
-
|
|
149
|
-
- [Channels & Staged Rollouts](channels-and-rollouts.md) — what `--channel` and `setChannel` actually do
|
|
150
|
-
- [Security & Encryption](security-encryption.md) — the `--key-v2` flow in full
|
|
151
|
-
- [Live Updates & OTA Strategy](live-updates-ota.md) — when to use each `autoUpdate` mode
|