@pikku/skills 0.12.54 → 0.12.55
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 +1 -1
- package/dist/skills.gen.js +2 -2
- package/dist/snippets.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-architect/SKILL.md +1 -1
- package/skills/pikku-architect/references/plan-defects.md +7 -7
- package/skills/pikku-auth/references/better-auth.md +92 -96
- package/skills/pikku-build/SKILL.md +9 -9
- package/skills/pikku-build/references/app.md +56 -61
- package/skills/pikku-build/references/design.md +14 -14
- package/skills/pikku-build/references/feature.md +3 -3
- package/skills/pikku-build/references/mocks.md +6 -0
- package/skills/pikku-build/references/multi-app.md +16 -16
- package/skills/pikku-build/references/openapi.md +34 -34
- package/skills/pikku-build/references/platform.md +4 -5
- package/skills/pikku-build/references/post-clone.md +1 -1
- package/skills/pikku-build/references/quick.md +63 -36
- package/skills/pikku-build/references/scenarios.md +17 -16
- package/skills/pikku-build/references/ship.md +14 -16
- package/skills/pikku-build/references/theming.md +2 -2
- package/skills/pikku-changes/SKILL.md +2 -5
- package/skills/pikku-concepts/SKILL.md +26 -27
- package/skills/pikku-concepts/references/language.md +6 -6
- package/skills/pikku-deploy/references/nextjs.md +1 -1
- package/skills/pikku-guide/SKILL.md +18 -17
- package/skills/pikku-i18n/references/messages.md +5 -6
- package/skills/pikku-knowledge/SKILL.md +3 -3
- package/skills/pikku-meta/references/audit.md +1 -1
- package/skills/pikku-permissions/SKILL.md +1 -1
- package/skills/pikku-react/SKILL.md +18 -20
- package/skills/pikku-react/references/client.md +2 -37
- package/skills/pikku-report/SKILL.md +10 -10
- package/skills/pikku-scenario/SKILL.md +63 -66
- package/skills/pikku-scenario/references/browser.md +5 -5
- package/skills/pikku-scenario/references/coverage.md +4 -4
- package/skills/pikku-scenario/references/steps.md +31 -30
- package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +38 -43
- package/skills/pikku-scenario/references/virtual-users.md +114 -0
- package/skills/pikku-seo/SKILL.md +1 -1
- package/skills/pikku-services/references/audit-wire-service.md +2 -2
- package/skills/pikku-services/references/audit.md +1 -2
- package/skills/pikku-services/references/services.md +1 -1
- package/skills/pikku-software-archaeology/SKILL.md +13 -13
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +9 -9
- package/skills/pikku-theme/SKILL.md +1 -1
- package/skills/pikku-workflow/SKILL.md +1 -1
- package/skills/pikku-admin-to-fabric/SKILL.md +0 -198
- package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -362
- package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
- package/skills/pikku-fabric/SKILL.md +0 -331
- package/skills/pikku-fabric/references/database.md +0 -128
- package/skills/pikku-fabric/references/debugging.md +0 -114
- package/skills/pikku-fabric/references/deploy.md +0 -179
- package/skills/pikku-scenario/references/personas.md +0 -123
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
# Deploying a Fabric app
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
|
|
5
|
-
- Deploy commands and organization targeting
|
|
6
|
-
- Rebuilding a disposable stage: `--reset`
|
|
7
|
-
- Exit codes, the approval gate, CI splitting, GitHub adoption and the upstream guard (inside Deploy commands)
|
|
8
|
-
- The first user on a deployed stage
|
|
9
|
-
- Opening a private stage
|
|
10
|
-
|
|
11
|
-
## Deploy commands and organization targeting
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
pikku fabric login # opens a browser; needs a human, wait for it
|
|
15
|
-
pikku fabric init https://github.com/<owner>/<repo>
|
|
16
|
-
pikku fabric validate # must pass clean
|
|
17
|
-
pikku fabric deploy apply --production -y
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
`init` and `link` import into whichever organization your session is in. When
|
|
21
|
-
you belong to several — a personal one and a company one, say — name the target
|
|
22
|
-
with `--organization`, taking a slug, a display name or an id:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
pikku fabric link --organization vlandor
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
You have to be a member of the organization you name, and its GitHub account
|
|
29
|
-
has to be connected already: importing a `github.com/<owner>/<repo>` repo needs
|
|
30
|
-
the Fabric GitHub App installed on `<owner>` _and_ linked to that organization,
|
|
31
|
-
or the import refuses by name.
|
|
32
|
-
|
|
33
|
-
The branch is positional and defaults to the checked-out one, and `-y` is the
|
|
34
|
-
short form of `--auto-approve`, so a one-shot deploy is:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pikku fabric deploy apply -y # the branch you are standing on
|
|
38
|
-
pikku fabric deploy apply my-branch -y # a named one
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
`-y` answers the prompts and nothing more. It does **not** approve migrations
|
|
42
|
-
that drop or rewrite data — that stays `--allow-destructive`, typed out on
|
|
43
|
-
purpose.
|
|
44
|
-
|
|
45
|
-
## Rebuilding a disposable stage: `--reset`
|
|
46
|
-
|
|
47
|
-
A non-production stage whose migration history or schema has drifted (an app's
|
|
48
|
-
`develop` branch) can be wiped and rebuilt in one deploy:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
pikku fabric deploy apply develop --reset # asks first, naming app + stage
|
|
52
|
-
pikku fabric deploy apply develop --reset -y # prints the warning, skips the prompt
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
It is the deployed counterpart of `pikku db reset`: **all data on that stage is
|
|
56
|
-
deleted**, every migration is re-applied and `db/<engine>-dev-seed.sql` is
|
|
57
|
-
loaded. It is refused for `--production`, for `main`, and with `--deployment-id`
|
|
58
|
-
(it only applies to a deploy it creates). It needs a fabric server that reports
|
|
59
|
-
the reset back on the deployment; against one that does not, the command fails
|
|
60
|
-
naming the deployment it created without a reset, and wipes nothing. `-y` does
|
|
61
|
-
not imply `--allow-destructive`.
|
|
62
|
-
|
|
63
|
-
Inferring the branch is safe because the git safety check refuses any branch
|
|
64
|
-
without an upstream or out of sync with it, so it cannot ship an unpushed
|
|
65
|
-
commit; the branch it picked is printed before the build starts. A detached
|
|
66
|
-
HEAD is refused by name rather than travelling on as a branch called `HEAD`.
|
|
67
|
-
|
|
68
|
-
There is no `deploy plan` subcommand — `apply` runs the same auth, git-safety
|
|
69
|
-
and ref resolution itself, and fabric produces the real plan server-side.
|
|
70
|
-
|
|
71
|
-
`apply` confirms before deploying, and with no TTY to ask — CI, an agent shell —
|
|
72
|
-
it refuses rather than hangs. `--auto-approve` (`-y`) supplies that confirmation;
|
|
73
|
-
drop it only when a human is at a real terminal.
|
|
74
|
-
|
|
75
|
-
`apply` waits for a terminal state and exits non-zero unless the deployment went
|
|
76
|
-
live. `--detach` opts out — it queues the deploy, prints the deployment id and
|
|
77
|
-
returns 0, which tells you nothing about whether it worked:
|
|
78
|
-
|
|
79
|
-
| exit | meaning |
|
|
80
|
-
| ---- | ----------------------------------------------------------------------- |
|
|
81
|
-
| 0 | live (or queued, under `--detach`) |
|
|
82
|
-
| 1 | the command could not run — not logged in, unsafe git state, bad flags |
|
|
83
|
-
| 2 | the deployment failed, errored, timed out server-side, or was cancelled |
|
|
84
|
-
| 3 | the deployment is blocked and nothing the CLI can do will unblock it |
|
|
85
|
-
| 4 | the wait hit `--timeout` with the deployment still in flight |
|
|
86
|
-
|
|
87
|
-
On a failure or timeout, `apply` prints the tail of the builder's own log (and
|
|
88
|
-
carries `buildLog` / `imageBuildLog` on the `--json` result). Read it before
|
|
89
|
-
touching code: `fabric logs` serves the running stage, not the build. When the
|
|
90
|
-
builder recorded nothing, the CLI says so — that is usually fabric-side, so run
|
|
91
|
-
`pikku fabric smoke` before assuming the project is broken.
|
|
92
|
-
|
|
93
|
-
Fabric parks every deploy at a gate after the plan phase (`status: suspended`).
|
|
94
|
-
Why it parked is the whole story, and it is `statusReason`, not `status`:
|
|
95
|
-
|
|
96
|
-
- `awaiting_approval` — the plan is fine, a human has to publish it.
|
|
97
|
-
`-y` does that; without it you get exit 3 and the command to run.
|
|
98
|
-
One exception: if fabric marked any pending migration **destructive** — a
|
|
99
|
-
drop, a truncate, a rewrite — `-y` alone declines and exits 3,
|
|
100
|
-
because a standing yes was given before anyone knew the plan dropped a table.
|
|
101
|
-
The CLI lists the migrations and fabric's reasons; `--allow-destructive`
|
|
102
|
-
accepts them for that deploy, and `-y` implies it.
|
|
103
|
-
- `needs_config` — a declared secret or variable has no value covering the
|
|
104
|
-
stage. The CLI names them. `-y` will **not** force this through;
|
|
105
|
-
set the values and re-attach — `pikku fabric secrets set <name>` for a
|
|
106
|
-
declared secret, `pikku fabric variables set <name> --value <v>` for a declared
|
|
107
|
-
variable. They are separate stores: a secret is sealed to the stage and cannot
|
|
108
|
-
be read back, a variable is stored plainly and can (`variables get`). `set`
|
|
109
|
-
reads the value as JSON when it parses, so `--value true` is the boolean on a
|
|
110
|
-
stage exactly as it is from `.env`, and `--value '"true"'` is the string.
|
|
111
|
-
- `needs_attention` — the plan is red. Nothing to approve.
|
|
112
|
-
|
|
113
|
-
The wait defaults to a 900s ceiling; `--timeout <seconds>` moves it. On timeout
|
|
114
|
-
it prints the deployment id and the re-attach command rather than lying about
|
|
115
|
-
the outcome.
|
|
116
|
-
|
|
117
|
-
Splitting kick-off from waiting across two CI jobs is the reason
|
|
118
|
-
`--deployment-id` exists, and what `--detach` is for — the first job here has to
|
|
119
|
-
return the id and exit rather than wait:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
id=$(pikku fabric deploy apply --production -y --detach --json | jq -r 'select(.event=="result").deploymentId')
|
|
123
|
-
# …later, in another job…
|
|
124
|
-
pikku fabric deploy apply --deployment-id "$id" -y
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
`--deployment-id` skips the git safety check entirely (the deployment already
|
|
128
|
-
pins a sha, and the checkout is allowed to have moved on) and refuses to be
|
|
129
|
-
combined with a branch or `--production`, which would let the two disagree.
|
|
130
|
-
|
|
131
|
-
Under `--json`, the wait emits one NDJSON event per line — `created`/`attached`,
|
|
132
|
-
`status` on each transition, `blocked`, `approved` — and the last line is the
|
|
133
|
-
terminal result object, tagged `"event": "result"`.
|
|
134
|
-
|
|
135
|
-
`init` adopts a **GitHub** repo, and adoption goes through the Pikku Fabric
|
|
136
|
-
GitHub App — the app has to be installed on the account or org that owns the
|
|
137
|
-
repo, and if it is installed with "selected repositories" this one must be in
|
|
138
|
-
the selection. There is no CLI flag that works around a missing installation:
|
|
139
|
-
`init` returns "Connect the GitHub account '<owner>'". Send the user to install
|
|
140
|
-
it, or create the project in the console instead (which provisions a Fabric-hosted
|
|
141
|
-
git repo you push to) and clone it — the remote links the checkout, or put
|
|
142
|
-
the id in `fabric.projectId` in `pikku.config.json`.
|
|
143
|
-
|
|
144
|
-
Deploy refuses to run unless the target branch equals its upstream — the guard
|
|
145
|
-
compares `main` against `main@{upstream}`. So the remote you pushed to must be
|
|
146
|
-
the one the branch tracks; a stale `origin` left over from scaffolding blocks
|
|
147
|
-
the deploy with "local HEAD … ≠ remote …" even though your code is pushed.
|
|
148
|
-
`git branch --set-upstream-to=<remote>/main main` before deploying.
|
|
149
|
-
|
|
150
|
-
## The first user on a deployed stage
|
|
151
|
-
|
|
152
|
-
When sign-up is off, the first account has to come from outside the app.
|
|
153
|
-
`pikku fabric user add <email>` is the CLI form of the console's Add user:
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
pikku fabric user add ada@example.com --name Ada # prompts; blank generates one
|
|
157
|
-
pikku fabric user add ada@example.com --password '<pw>' -b staging
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
It mints a short-lived operator token for the stage and calls the stage's own
|
|
161
|
-
`admin:createUser`, so the stage must wire `@pikku/addon-admin` as `admin` —
|
|
162
|
-
a 404 is refused by name and nothing is created. A generated password is printed
|
|
163
|
-
once; one you passed is never echoed. With no TTY, pass `--password` or pipe it.
|
|
164
|
-
|
|
165
|
-
## Opening a private stage
|
|
166
|
-
|
|
167
|
-
A non-production stage is private: without a link it answers "This preview is
|
|
168
|
-
private". `pikku fabric stage link` prints the link that opens it:
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
pikku fabric stage link access -b develop --route /login # use the stage
|
|
172
|
-
pikku fabric stage link changes -b develop # use it with the changes panel
|
|
173
|
-
pikku fabric stage visibility public -b develop # or: private
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
A stage has one live link of each kind, so asking again returns the same one
|
|
177
|
-
until it expires. A `changes` link turns the panel on first; if that needs a
|
|
178
|
-
deploy, the command says so. `visibility public` opens the stage to anyone with
|
|
179
|
-
its URL — hand out an `access` link instead when that is all you need.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Personas and actors
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
|
|
5
|
-
- [Declaring personas in TypeScript](#declaring-personas-in-typescript)
|
|
6
|
-
- [Actors that call a third-party API](#actors-that-call-a-third-party-api)
|
|
7
|
-
- [The same actors sign a human in](#the-same-actors-sign-a-human-in)
|
|
8
|
-
|
|
9
|
-
A **persona** is a person your product is for; an **actor** is one body that signs in as them. Every entry materialises exactly one actor, so `actors.<id>` exists for each declared persona and there is no second way to declare a login.
|
|
10
|
-
|
|
11
|
-
- Two people of the same kind are two entries, not one persona with two logins — "you see yours, not theirs" is only testable with two customers.
|
|
12
|
-
- Never write an email address: each is derived from the persona id and `scenarios.emailDomain`, and a hand-written one signs in as somebody who was never created.
|
|
13
|
-
- `roles` is typechecked against `defineSystemRole`; an undeclared role is a build error.
|
|
14
|
-
- A person who is only ever acted _upon_ — the account an admin bans — sets `runnable: false`: declared and seeded, never signed in, because a run as them would race the scenario that acts on them.
|
|
15
|
-
- A persona holds only what is true of that kind of person for the app's whole lifetime (`name`, `jobTitle`, `description`, `personality`, `roles`, `goals`, `disposition`). What someone is trying to get done, and the circumstances they are doing it in, belong to the **scenario**, not to them.
|
|
16
|
-
|
|
17
|
-
## Declaring personas in TypeScript
|
|
18
|
-
|
|
19
|
-
There may be **one `definePersonas` call in the whole codebase** — one place to
|
|
20
|
-
read the set from, one place to add to it. A second anywhere, including in the
|
|
21
|
-
same file, is a critical. Generated files are exempt and never claim the slot.
|
|
22
|
-
|
|
23
|
-
> [!WARNING]
|
|
24
|
-
> The declaration is **read from source, never evaluated** — the CLI writes it
|
|
25
|
-
> to JSON that a deployed stage carries without the app. So every value has to
|
|
26
|
-
> be statically knowable, and a value that is not comes out as `undefined`
|
|
27
|
-
> rather than as an error. Only `name` is checked, so a computed `personality`,
|
|
28
|
-
> `jobTitle` or `description` is dropped in silence and the persona runs with a
|
|
29
|
-
> blank temperament.
|
|
30
|
-
|
|
31
|
-
What that admits and what it does not:
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
personality: 'Wound up and short with it.' // read
|
|
35
|
-
personality: `Wound up and short with it.
|
|
36
|
-
Says what she wants in a few blunt words.` // read — no ${} in it
|
|
37
|
-
personality: 'Wound up. ' + 'Short with it.' // dropped, silently
|
|
38
|
-
personality: TEMPERAMENTS.impatient // dropped, silently
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
A no-substitution template literal is a string literal as far as the reader is
|
|
42
|
-
concerned, so it is the way to write a long personality across several lines —
|
|
43
|
-
not a concatenation, and not a `prettier-ignore`d single line. Its newlines and
|
|
44
|
-
leading indentation are kept verbatim and reach the model that way, which is
|
|
45
|
-
harmless but worth knowing before you align it to the surrounding code.
|
|
46
|
-
|
|
47
|
-
One more thing worth knowing before writing a rich persona: **`actor.converse`
|
|
48
|
-
builds its prompt from `name`, `jobTitle`, `personality` and the scenario's
|
|
49
|
-
`task` only.** Fields like `disposition`, `goals` and `roles` are read and
|
|
50
|
-
stored, and the console shows them, but they do not reach the conversing
|
|
51
|
-
persona's instructions. Anything that must shape how someone talks belongs in
|
|
52
|
-
`personality` or in the task.
|
|
53
|
-
|
|
54
|
-
A project that never declares a persona keeps working: a scenario that names no actor needs none.
|
|
55
|
-
|
|
56
|
-
- `environments.<name>.apiUrl` is required. `signInPath` defaults to `/auth/sign-in/actor`, `rpcPath` to `/rpc`.
|
|
57
|
-
- **`SCENARIO_ACTOR_SECRET` is an environment variable and never goes in `pikku.config.json`.** It signs actors in. `pikku scenario run` throws without it; a server auto-building actors warns and runs without them.
|
|
58
|
-
|
|
59
|
-
## Actors that call a third-party API
|
|
60
|
-
|
|
61
|
-
An addon generated from an upstream API (Dolibarr, a CRM, a calendar) calls it
|
|
62
|
-
with the signed-in user's own credential. An actor has none until one is stored
|
|
63
|
-
for it, so every step that reaches the addon fails with `No <X> session`. Give
|
|
64
|
-
the `actor` plugin a `credentials` option, and each actor carries its upstream
|
|
65
|
-
credential into every session:
|
|
66
|
-
|
|
67
|
-
- `names: ['dolibarr']` — the credentials to carry
|
|
68
|
-
- `store: (name, value, userId) => credentialService.set(name, value, userId)`
|
|
69
|
-
- `remove: (name, userId) => credentialService.delete(name, userId)`
|
|
70
|
-
|
|
71
|
-
At each actor sign-in the plugin reads `ACTOR_CREDENTIAL_<PERSONA>_<NAME>` —
|
|
72
|
-
`dan` + `dolibarr` is `ACTOR_CREDENTIAL_DAN_DOLIBARR` — and stores it with
|
|
73
|
-
`credentialService.set` for that actor. A bare value is stored as `{ token }`
|
|
74
|
-
(what a delegated or bearer credential holds); a JSON object is stored as-is,
|
|
75
|
-
e.g. `{"apiKey":"…"}` for an API-key credential. Unset means the actor has no
|
|
76
|
-
upstream credential: `remove` drops one stored at an earlier sign-in.
|
|
77
|
-
|
|
78
|
-
- **Values live in `.env` (or CI secrets), never in `personas.ts` or code.**
|
|
79
|
-
Use a dedicated upstream test account per persona, not a real person's.
|
|
80
|
-
- `read` defaults to `process.env`; a Worker passes `(key) => variables.get(key)`.
|
|
81
|
-
- A malformed JSON value refuses the sign-in with a 500 that names the variable.
|
|
82
|
-
- A delegated token expires upstream like any other; re-signing the actor
|
|
83
|
-
in re-stores whatever the variable holds now.
|
|
84
|
-
|
|
85
|
-
## The same actors sign a human in
|
|
86
|
-
|
|
87
|
-
Declared actors are not only for automated runs. `signInPath` is Better Auth's
|
|
88
|
-
`actor` plugin (see `pikku-auth`, a separate install), which any caller can post to — so the
|
|
89
|
-
frontend gets a one-click "Sign in as …" switcher over the **same** list, and an
|
|
90
|
-
app can be reviewed as each kind of user without anyone knowing a seed password.
|
|
91
|
-
|
|
92
|
-
The switcher holds no credential. It lists personas from
|
|
93
|
-
`/auth/sign-in/personas` and signs in by posting only a persona id to
|
|
94
|
-
`/auth/sign-in/persona`; the server resolves the address. One server piece
|
|
95
|
-
serves both, in the auth config:
|
|
96
|
-
|
|
97
|
-
```ts snippet:personaSignIn
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
It is always open under `pikku dev`. A deployed stage needs actor
|
|
101
|
-
sign-in opted in **and** its `devSwitcher` feature flag on; production never
|
|
102
|
-
has the opt-in, so it lists nobody and refuses every persona sign-in.
|
|
103
|
-
|
|
104
|
-
Do not hand-roll the switcher: `useDevActors()` (`pikku-react`, a separate install) is the logic and
|
|
105
|
-
the starter template's `<DevActorSwitcher />` is a ready rendering of it.
|
|
106
|
-
`pikku fabric validate` **requires** any frontend with a login screen to ship
|
|
107
|
-
one — without it a reviewer is locked out of their own sandbox.
|
|
108
|
-
When the switcher is missing, it is one of three things, and none of them
|
|
109
|
-
errors:
|
|
110
|
-
|
|
111
|
-
- **The list is empty.** On a deployed stage that is the gate
|
|
112
|
-
doing its job — check the opt-in and the `devSwitcher` flag. Locally, check
|
|
113
|
-
the personas declare an `email` (via `scenarios.emailDomain`) and are not
|
|
114
|
-
`runnable: false`.
|
|
115
|
-
- **`personaSignIn` is missing, or the frontend calls another API.** A dev
|
|
116
|
-
proxy (`VITE_API_PROXY`, default `http://localhost:3000`) that points at
|
|
117
|
-
another project's API lists that project's personas, or none.
|
|
118
|
-
- **It is not mounted on the page you are looking at.** The template mounts it
|
|
119
|
-
on the login screen. A public homepage that replaces the `/` → `/app`
|
|
120
|
-
redirect needs its own `<DevActorSwitcher />` in the public layout.
|
|
121
|
-
|
|
122
|
-
When the switcher lists personas but a click 404s, that persona has no `email`
|
|
123
|
-
or is `runnable: false`.
|