@pikku/skills 0.12.30 → 0.12.32
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/package.json +10 -6
- package/skills/pikku-addon/SKILL.md +5 -0
- package/skills/pikku-build/references/ship.md +79 -0
- package/skills/pikku-knowledge/SKILL.md +14 -0
- package/skills/pikku-services/references/services.md +7 -1
- package/CHANGELOG.md +0 -1368
package/CHANGELOG.md
DELETED
|
@@ -1,1368 +0,0 @@
|
|
|
1
|
-
# @pikku/skills
|
|
2
|
-
|
|
3
|
-
## 0.12.30
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- 9c5aa96: dev/serve: always inject the local content service
|
|
8
|
-
|
|
9
|
-
`pikku dev` and `pikku serve` only built `LocalContent` when `pikku.config.json`
|
|
10
|
-
declared a `content` block, so a project without one type-checks, renders and
|
|
11
|
-
starts clean and then throws the first time anything uploads a file. Every field
|
|
12
|
-
already had a default, so the block was gating a service that needed no
|
|
13
|
-
configuration. It is now always constructed; the `content` block still overrides
|
|
14
|
-
the storage path, URL prefixes and size limit.
|
|
15
|
-
|
|
16
|
-
Also documents it in the `pikku-services` skill: these singletons arrive as
|
|
17
|
-
`existingServices` and are never named in `services.ts`, so their absence there
|
|
18
|
-
is not evidence they are off — which is what makes the `if (!content) throw`
|
|
19
|
-
guard the skill already forbids look justified.
|
|
20
|
-
|
|
21
|
-
- 5e2a579: pikku-wiring: document how an MCP tool is actually reached
|
|
22
|
-
|
|
23
|
-
`references/mcp.md` ended with a standalone `PikkuMCPServer` bootstrap — a
|
|
24
|
-
`start.ts` that builds services, loads `mcp.gen.json` and calls `connectStdio()`.
|
|
25
|
-
Nothing in a `pikku dev` / `pikku serve` / deployed app does that: the runtime
|
|
26
|
-
mounts the MCP server itself at `/mcp` (`mcpPath` to move it) whenever
|
|
27
|
-
`mcp.gen.json` has at least one entry. An agent following the old section wrote a
|
|
28
|
-
server process nobody runs, and then could not tell the person who asked for the
|
|
29
|
-
tool where to point their assistant.
|
|
30
|
-
|
|
31
|
-
Replaces it with the reachable URL, the two things that read as breakage — the
|
|
32
|
-
mount is skipped while there is nothing to serve, and correct MCP wiring has no
|
|
33
|
-
`wires/mcp` directory and no `mcp` config block — and the instruction to hand over
|
|
34
|
-
the URL. Swaps the stdio-logger red flag for a `/mcp` 404 one.
|
|
35
|
-
|
|
36
|
-
## 0.12.29
|
|
37
|
-
|
|
38
|
-
### Patch Changes
|
|
39
|
-
|
|
40
|
-
- 96b65ae: Document how an addon ships database tables: `pikku db export`, the artifact the
|
|
41
|
-
consumer resolves through the package name, and the silent failure when it is
|
|
42
|
-
neither exported nor packed.
|
|
43
|
-
- c4ee98d: **pikku-build** gains `references/design.md`: the composition doctrine that no theme can supply. An app built to the letter of the skill still came out looking like nobody had decided anything — a form at the top of every list screen, sixty identical cards each carrying two filled buttons, an "urgent" group holding half the fridge, a scaffolded login page with a Google button the app had no credentials for, and the whole thing judged against a dev database full of `Ripe peaches d193e2aa` left behind by scenario runs. The new reference names the bar (six questions a screen has to answer), the composition rules that get it there, the screens agents forget — login, navigation, empty states — and the reset-and-restart that has to happen before any of it is judged. §8 now says out loud that half of it belongs at §6, because a design pass over eight finished milestones is a repaint.
|
|
44
|
-
- f99547e: Two things an agent building a vision feature had to discover by reading source. **pikku-agent** now documents `attachments`: the `data`/`url` split, that a `url` is downloaded server-side (so a caller-supplied one is an SSRF surface the runner's host allowlist exists for), that the model id — not the provider prefix — decides whether an image is read at all, and that reading a picture into typed data is the tool-free case `output` was waiting for. **pikku-fabric** gains "Reaching a model": `pikku dev` builds the `agentRunner` from a matching `OPENAI_BASE_URL`/`OPENAI_API_KEY` or `LITELLM_PROXY_URL`/`LITELLM_API_KEY` pair and otherwise 503s every agent with `AIProviderNotConfiguredError`, and `pikku fabric llm key --env` is the one command that fills either pair in from the Fabric AI gateway.
|
|
45
|
-
|
|
46
|
-
## 0.12.28
|
|
47
|
-
|
|
48
|
-
### Patch Changes
|
|
49
|
-
|
|
50
|
-
- 591593a: Document `pikku knowledge next` in the `pikku-knowledge` skill: what the six actions mean,
|
|
51
|
-
that `reason` is machine wording never to be repeated to a person, and that `ask-user`
|
|
52
|
-
carries a separate `question` whose empty `options` list means offer free text rather than
|
|
53
|
-
invent choices.
|
|
54
|
-
- 591593a: Document the two frontmatter keys a driving loop writes, in `pikku-knowledge`.
|
|
55
|
-
|
|
56
|
-
`statusAt:` and `attempts:` are bookkeeping rather than content, and an agent
|
|
57
|
-
that rewrites a note has to know not to hand-edit them — clearing `attempts:`
|
|
58
|
-
hands back a budget that exists to stop a note nothing can satisfy being
|
|
59
|
-
rewritten forever.
|
|
60
|
-
|
|
61
|
-
Also corrects the status vocabulary: it is `designing` → `proposed` →
|
|
62
|
-
`dispatched` → `built`. The skill said `proposed` → `dispatched` → `built`,
|
|
63
|
-
"nothing else", while `validate` has always accepted `designing`.
|
|
64
|
-
|
|
65
|
-
- f5a8ee4: Teach `pikku-kysely` to count round trips.
|
|
66
|
-
|
|
67
|
-
The skill documented the query builder API but said nothing about how many times
|
|
68
|
-
a function body crosses the wire, so generated functions routinely awaited four
|
|
69
|
-
or five queries in series — invisible locally, a stacked latency in a deployed
|
|
70
|
-
stage. Adds the four shapes that collapse: independent reads into `Promise.all`,
|
|
71
|
-
parent-then-children into the `jsonArrayFrom` helpers already documented below
|
|
72
|
-
it, read-then-write into one `returning()`/`onConflict` statement that also
|
|
73
|
-
closes the race, and a read that only feeds the next `where` into a subquery or
|
|
74
|
-
CTE. Plus the correction that a transaction adds round trips rather than
|
|
75
|
-
removing them.
|
|
76
|
-
|
|
77
|
-
## 0.12.27
|
|
78
|
-
|
|
79
|
-
### Patch Changes
|
|
80
|
-
|
|
81
|
-
- 28f39f2: Add the `pikku-blueprint-to-fabric` and `pikku-admin-to-fabric` skills, which rebuild a legacy app (and its generated back-office admin) as a Fabric app from a `.knowledge/` Product Blueprint.
|
|
82
|
-
|
|
83
|
-
Both skills were written against an older corpus, so every cross-reference is repointed at the skill that owns the material today: `pikku-queue`/`pikku-cron`/`pikku-http` to `pikku-wiring`, `pikku-better-auth` to `pikku-auth`, `pikku-react-query` to `pikku-react`, `pikku-feature` to `pikku-build`. Four steps named skills that no longer exist at all and are rewritten rather than repointed — the post-clone cleanup, the AOP verification loop, versioning, and the Stage 9 parity check. The stale `wireVariable`/`wireSecret` names are corrected to `defineVariable`/`defineSecret`.
|
|
84
|
-
|
|
85
|
-
`scripts/inventory.mjs` now exits non-zero with the reason when the blueprint directory is missing, a required file is absent, a file is unparseable, or an expected array has the wrong shape. It previously swallowed all of those and printed a table of zeros, which reads as a small app rather than an unusable blueprint.
|
|
86
|
-
|
|
87
|
-
## 0.12.26
|
|
88
|
-
|
|
89
|
-
### Patch Changes
|
|
90
|
-
|
|
91
|
-
- 206dc04: pikku-auth's Better Auth reference gains two-factor, security hardening and post-signup hooks
|
|
92
|
-
- 206dc04: pikku-react's client reference now says what `transformDate: true` costs you: a fully-zoned ISO instant arrives as a `Date` while a bare or zoneless date stays a string, so one field's runtime type follows the value — a string method on a revived one throws, and a raw one in JSX crashes the route.
|
|
93
|
-
- 206dc04: Add `pikku-a11y`, `pikku-seo`, `pikku-permissions`, `pikku-list-query` and
|
|
94
|
-
`pikku-realtime`, which lived in Fabric's sandbox image and are not about Fabric.
|
|
95
|
-
|
|
96
|
-
None of them needs a sandbox, a console or the `fabric` CLI, so a local project
|
|
97
|
-
gets the same guidance the hosted build agent has been getting. `pikku-realtime`
|
|
98
|
-
carries the SSE and channel patterns inline rather than pointing at a scaffold
|
|
99
|
-
command that only exists inside Fabric.
|
|
100
|
-
|
|
101
|
-
- 206dc04: pikku-build's multi-app reference now says how to decide it is two apps, not just how to clone one
|
|
102
|
-
- 206dc04: The corpus now fails on a bare `fabric` command, which the OSS reader has no binary for
|
|
103
|
-
- 206dc04: Three review fixes across the wiring skills: pikku-list-query now caps `limit` and reads `filter` as the recursive AND/OR tree it is (a `'status' in filter` check silently returns unfiltered rows for a group or an operator leaf); pikku-realtime warns that `/events/:topic` is unauthenticated so a topic must carry a projection rather than `returningAll()`, and invalidates the `[name, input]` query key instead of hand-patching a `ListOutput`; pikku-workflow replaces "each step is its own transaction" — pikku opens none — with where atomicity actually comes from, plus provider idempotency keys for retried external side effects.
|
|
104
|
-
- 206dc04: Give `pikku-architect`, `pikku-build`, `pikku-knowledge` and
|
|
105
|
-
`pikku-software-archaeology` an `installGroups`. A skill with none is skipped
|
|
106
|
-
whenever any group is requested, so `pikku skills install --core` never
|
|
107
|
-
installed these four — including the archaeology skill other tooling documents
|
|
108
|
-
as installed by that command.
|
|
109
|
-
|
|
110
|
-
Also qualify pikku-i18n's "do not wrap `m`" rule: wrapping the namespace is a
|
|
111
|
-
real tradeoff (it forgoes per-message tree-shaking) rather than a mistake, and
|
|
112
|
-
is worth it when it buys something the gate cannot, such as debug masking.
|
|
113
|
-
|
|
114
|
-
- 206dc04: Give `pikku-workflow` the "should this even BE a workflow?" section: the
|
|
115
|
-
external-boundary test, the checkout-with/without-payment split, "one durable
|
|
116
|
-
step is a queue worker, not a workflow", and "atomicity is a TRANSACTION, not a
|
|
117
|
-
workflow". It answers the question that comes before choosing a factory, and it
|
|
118
|
-
was only written down in Fabric's copy of the skill.
|
|
119
|
-
|
|
120
|
-
## 0.12.25
|
|
121
|
-
|
|
122
|
-
### Patch Changes
|
|
123
|
-
|
|
124
|
-
- 498662a: Measure a finished milestone against its plan, with `pikku knowledge plan progress`.
|
|
125
|
-
|
|
126
|
-
The reconciliation itself already existed — `planShortfall` reads pikku's generated meta under `.pikku/` and answers "was this planned function written, this route wired, this `pikkuScenario` exported" by set membership. Nothing in the CLI could run it, so the only thing closing a milestone was the build agent's own account of what it had done.
|
|
127
|
-
|
|
128
|
-
`pikku knowledge plan progress <milestone>` prints what the milestone still owes, separating what BLOCKS (the first pass) from what a later pass picks up, and exits non-zero while anything blocks. Its problems include the two checks no meta covers: a browser scenario that opens a page and asserts it is still on it, and an `on delete cascade` the plan promised that no migration declares.
|
|
129
|
-
|
|
130
|
-
Two skills follow it. The new `pikku-architect` writes the plan against the milestone note through `pikku knowledge plan set`, as a seat separate from the build — a builder who writes its own plan can build a fraction, plan only that fraction, and certify itself complete. `pikku-build` now plans each milestone before building it (§5a) and closes it on `plan progress` rather than on memory (§6a), with `pikku knowledge plan defer` as the only way an unbuilt item leaves the first pass.
|
|
131
|
-
|
|
132
|
-
Two things `plan set` needed before an architect could actually satisfy it: it now refuses a `covers` entry naming a note that does not exist, or carrying a hash that is not that note's current one — and names the correct hash, which is also the only way to obtain one. Unchecked, a placeholder hash was accepted and the note it claimed read as edited-since from the moment the milestone shipped, dropping silently back into a backlog nobody had planned. The plan's build rendering no longer names a runtime-specific command for creating a frontend, since two builds read it and each creates one a different way.
|
|
133
|
-
|
|
134
|
-
- e0bf0ce: Add a `pikku-webhook` skill covering the outgoing webhook primitive — `WebhookService` / `QueueWebhookService`, the `pikku-outgoing-webhooks` queue worker, `scaffold.webhook`, `config.webhook` (signing secret, header, retries, SSRF allowlist), receiver-side verification, and `KyselyWebhookService`'s delivery/attempt history. The corpus previously mentioned it in one table row, so agents hand-rolled `fetch` + HMAC instead of using it.
|
|
135
|
-
|
|
136
|
-
## 0.12.24
|
|
137
|
-
|
|
138
|
-
### Patch Changes
|
|
139
|
-
|
|
140
|
-
- 202cb72: Refuse a scenario step whose prose opens with its own actor (PKU681). The
|
|
141
|
-
reporter already renders the actor as the sentence's subject, so a step
|
|
142
|
-
authored as `'sam' creates the client` and run as `{ actor: actors.sam }`
|
|
143
|
-
reads "Given sam 'sam' creates the client" — and the hardcoded name desyncs
|
|
144
|
-
the moment the call site changes actor. Only the subject position is refused:
|
|
145
|
-
naming someone else mid-sentence, or an actor keyed after a role noun used as
|
|
146
|
-
a noun ("creates the admin client"), is left alone.
|
|
147
|
-
|
|
148
|
-
## 0.12.23
|
|
149
|
-
|
|
150
|
-
### Patch Changes
|
|
151
|
-
|
|
152
|
-
- f4e2e89: Add file attachments to `EmailService`.
|
|
153
|
-
|
|
154
|
-
`BaseSendEmailInput` gains an optional `attachments: EmailAttachment[]`, so it is
|
|
155
|
-
available on all three input variants — text, HTML and template. The new
|
|
156
|
-
`EmailAttachment` type is exported from `@pikku/core/services` alongside the
|
|
157
|
-
input types, and is shaped so that mapping it onto Resend, SendGrid, Nodemailer
|
|
158
|
-
or SES v2 is a straight field rename rather than a translation.
|
|
159
|
-
|
|
160
|
-
`content` is `Uint8Array | string`, where a string is always read as base64.
|
|
161
|
-
Both forms are accepted because both are what callers already hold: bytes come
|
|
162
|
-
out of a fetch or a file read, and base64 comes out of a database column or a
|
|
163
|
-
provider API. `Buffer` is deliberately absent from the type — it is a subclass
|
|
164
|
-
of `Uint8Array`, so Node callers can still pass one, while the type stays usable
|
|
165
|
-
in Cloudflare Workers, where `Buffer` does not exist.
|
|
166
|
-
|
|
167
|
-
`LocalEmailService` now logs attachment metadata — filename, content type,
|
|
168
|
-
content id, disposition and content length — instead of dropping the field
|
|
169
|
-
silently. The content itself is deliberately not logged.
|
|
170
|
-
|
|
171
|
-
The template-rendering wrapper documented in the emails skill rebuilt its
|
|
172
|
-
delegate payload field by field and therefore dropped `attachments`; it now
|
|
173
|
-
forwards them.
|
|
174
|
-
|
|
175
|
-
- 9022169: Cover `pikku persona run`, and give the corpus a CLI command inventory.
|
|
176
|
-
|
|
177
|
-
`pikku doc` computes the `#pikku/*` API surface and lists no CLI commands, so
|
|
178
|
-
for anything invoked as `pikku <cmd>` the skills corpus is the only place it
|
|
179
|
-
exists. Two things were missing from it.
|
|
180
|
-
|
|
181
|
-
`pikku-scenario` covered declaring personas but not running one. Its new
|
|
182
|
-
`references/persona-run.md` covers the virtual-user run: the seven dispositions
|
|
183
|
-
and what each one is for, the three credentials and which wins, the budget and
|
|
184
|
-
`--seed` replay, why production takes only `accountable` and why that rule is
|
|
185
|
-
checked at build time and again at sign-in, the role check that happens before
|
|
186
|
-
the first step, and `sync` / `list` / `secret`.
|
|
187
|
-
|
|
188
|
-
`pikku-concepts` gains a one-line-per-command inventory of the CLI, grouped by
|
|
189
|
-
what you are doing and pointing at the skill that teaches each one. A dash means
|
|
190
|
-
no skill covers it beyond that line, which is a reason to read `--help` rather
|
|
191
|
-
than assume the command does what its name suggests.
|
|
192
|
-
|
|
193
|
-
- acca415: Consolidate the skills corpus from 63 skills to 21.
|
|
194
|
-
|
|
195
|
-
The corpus had grown one skill per package and one per transport, so an agent's
|
|
196
|
-
first decision was a routing problem — which of ten wiring skills, which of five
|
|
197
|
-
auth skills — before it could reach anything that helped. Most of what those
|
|
198
|
-
skills carried was signatures and option keys, which `pikku doc` computes from
|
|
199
|
-
the compiler and cannot go stale.
|
|
200
|
-
|
|
201
|
-
Each family collapses to one chooser skill plus per-topic `references/*.md`. The
|
|
202
|
-
chooser answers the question the compiler cannot: which thing to pick, what
|
|
203
|
-
differs between the options, and what goes wrong silently. The families:
|
|
204
|
-
|
|
205
|
-
- `pikku-deploy` — eight runtime skills
|
|
206
|
-
- `pikku-service-backends` — six adapter skills, organised by the core interface
|
|
207
|
-
they implement rather than by vendor
|
|
208
|
-
- `pikku-wiring` — ten transport skills
|
|
209
|
-
- `pikku-auth` — five skills that all answered "who is this and may they",
|
|
210
|
-
fronted by the authentication-versus-authorization distinction
|
|
211
|
-
- `pikku-services` — services, config, audit and logging
|
|
212
|
-
- `pikku-agent` — the agent, its runner and the voice middlewares
|
|
213
|
-
- `pikku-react` and `pikku-i18n` — the client and localisation families
|
|
214
|
-
- `pikku-meta` — project metadata, contract versioning and the dependency audit
|
|
215
|
-
- `pikku-build` — the three build modes, feature work and post-clone cleanup
|
|
216
|
-
- `pikku-software-archaeology` and `pikku-fabric` — each gains its second phase
|
|
217
|
-
|
|
218
|
-
The doc-surface routing table (`LEAF_EDITORIAL`) points at the merged skills, and
|
|
219
|
-
the fabric install group is back to what it names: skills about Fabric.
|
|
220
|
-
|
|
221
|
-
## 0.12.22
|
|
222
|
-
|
|
223
|
-
### Patch Changes
|
|
224
|
-
|
|
225
|
-
- 5ace170: Fix the `#pikku` import specifiers the skills teach.
|
|
226
|
-
|
|
227
|
-
Twenty-five examples across ten skills named a leaf that does not export the
|
|
228
|
-
symbol — `pikkuAuth`/`pikkuPermission`/`addGlobalPermission` from `#pikku/function`
|
|
229
|
-
(they are in `#pikku/auth`), `addHTTPMiddleware` from `#pikku/http` (`#pikku/middleware`),
|
|
230
|
-
`pikkuServices`/`pikkuWireServices` from `#pikku/function` (`#pikku/setup`),
|
|
231
|
-
`pikkuWorkflowFunc` from `#pikku/function` (`#pikku/workflow`), `pikkuScenario` and
|
|
232
|
-
friends from `#pikku/scenario` and from `#pikku/workflow/pikku-workflow-types.gen.js`
|
|
233
|
-
(`#pikku/scenarios`), and `defineSystemRole` from a bare `#pikku` (`#pikku/scopes`).
|
|
234
|
-
|
|
235
|
-
`pikku-addon` also claimed an addon authors against `#pikku/addon/function` and
|
|
236
|
-
`#pikku/addon/setup`. It does not: `pikku new addon` writes an `imports` map that
|
|
237
|
-
points `#pikku/*` at the addon's own `.pikku/addon/` tree, so an addon uses the
|
|
238
|
-
same subpaths an application does. The `addon` segment is the package's business,
|
|
239
|
-
never part of a specifier.
|
|
240
|
-
|
|
241
|
-
An agent following these wrote a file that took schema generation red —
|
|
242
|
-
`Package import specifier "#pikku" is not defined in package .../packages/functions/package.json`
|
|
243
|
-
— which is a failure the example, not the agent, was responsible for.
|
|
244
|
-
|
|
245
|
-
## 0.12.21
|
|
246
|
-
|
|
247
|
-
### Patch Changes
|
|
248
|
-
|
|
249
|
-
- 77ae071: `pikku fabric report` sends a finding — something about pikku that cost an agent time — to fabric. It needs a login but no linked project: a finding is about the framework rather than about anyone's project, and the reports worth having most come from checkouts that have nothing to name.
|
|
250
|
-
|
|
251
|
-
The finding can be given as JSON on stdin (`--stdin`) instead of as flags. Half the fields are prose, and prose carries apostrophes, quotes, backticks and newlines — every one a shell metacharacter before it is a character in a sentence — so an error message pasted into `--error` used to break the command at its first newline. The same schema validates either path.
|
|
252
|
-
|
|
253
|
-
Nothing is written to the repo, so nothing goes stale on an abandoned branch, and the terminal prints exactly what left the machine. Reporting never fails a build.
|
|
254
|
-
|
|
255
|
-
A finding that cannot be sent is held in `~/.fabric/findings` rather than dropped: logged out, unlinked, or fabric unreachable are the states a finding is most likely to be describing, and a scaffold that never got far enough to log in is exactly the thing worth hearing about. The queue drains on the next report that succeeds, keeps the project each finding was filed against, and is bounded at 100. `pikku fabric findings list`, `flush` and `clear` inspect and control it.
|
|
256
|
-
|
|
257
|
-
The resolved `@pikku/*` versions are read off the installed tree rather than out of `package.json`, since a range says nothing about what actually ran. A skewed tree and a package resolving through a workspace or link are both flagged, because either is a reason to read the finding differently.
|
|
258
|
-
|
|
259
|
-
The `pikku-feature` skill now tells an agent when to file one: work around it first, investigate only when there is no workaround, report at the depth already reached, and never patch pikku itself from inside a project that is using it.
|
|
260
|
-
|
|
261
|
-
- 32d1280: Prefix the better-auth plugin factories with `pikku`: `pikkuActor`, `pikkuBan`,
|
|
262
|
-
`pikkuFabric`, `pikkuDelegatedAuth` and `pikkuCredentialOAuth`.
|
|
263
|
-
|
|
264
|
-
A `betterAuth({ plugins: [...] })` array mixes this package's plugins with
|
|
265
|
-
better-auth's own, and until now nothing at the call site told them apart —
|
|
266
|
-
`plugins: [actor(...), ban(), fabric(...), organization()]` reads as four
|
|
267
|
-
plugins from one place when only the last is better-auth's. The prefix says
|
|
268
|
-
which package a plugin came from where it is actually wired.
|
|
269
|
-
|
|
270
|
-
The old names are still exported as deprecated aliases bound to the same
|
|
271
|
-
functions, so no import has to change. Nothing about the plugins themselves
|
|
272
|
-
moved: the `id` each registers under — `pikku-ban`, `actor`, `fabric`,
|
|
273
|
-
`delegated-auth`, `credential-oauth` — is unchanged, so no deployed database or
|
|
274
|
-
session is affected.
|
|
275
|
-
|
|
276
|
-
The pieces that read a plugin's _export_ name rather than its id accept both:
|
|
277
|
-
`PLUGIN_REGISTRY` is keyed under the prefixed and the bare name, and the
|
|
278
|
-
`pikku validate` ban/actor checks and the `scaffold.userAdmin` ban check count
|
|
279
|
-
either spelling as wired. Their messages now point at the new names.
|
|
280
|
-
|
|
281
|
-
## 0.12.20
|
|
282
|
-
|
|
283
|
-
### Patch Changes
|
|
284
|
-
|
|
285
|
-
- 7a15c9c: An actor credential is one persona's, not everyone's
|
|
286
|
-
|
|
287
|
-
`SCENARIO_ACTOR_SECRET` was a skeleton key. Anyone holding it could post any
|
|
288
|
-
`actor: true` address to `/auth/sign-in/actor` and get that persona's session —
|
|
289
|
-
including the `admin` persona, which provisioning grants real admin. The browser
|
|
290
|
-
switcher held it too, baked into the dev bundle as `VITE_SCENARIO_ACTOR_SECRET`,
|
|
291
|
-
so "the reviewer can sign in as each kind of user" and "the reviewer's bundle is
|
|
292
|
-
entitled to every persona" were the same fact.
|
|
293
|
-
|
|
294
|
-
It is now a root that credentials derive from, never one that is presented:
|
|
295
|
-
|
|
296
|
-
```ts
|
|
297
|
-
deriveActorSecret(root, email) // HKDF-expanded HMAC-SHA256 over the address
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
The endpoint re-derives the expected value for whichever address is signing in
|
|
301
|
-
and compares, so nothing is stored or looked up, a credential minted for one
|
|
302
|
-
persona is refused for every other, and rotating the root invalidates all of
|
|
303
|
-
them at once. The root itself is no longer a valid credential, and a root under
|
|
304
|
-
32 characters refuses the endpoint rather than deriving weak credentials from
|
|
305
|
-
it — the server log says why, the client is not told.
|
|
306
|
-
|
|
307
|
-
What that buys, in the places that used to need the whole key:
|
|
308
|
-
|
|
309
|
-
- **`pikku dev`** mints one credential per declared persona into
|
|
310
|
-
`VITE_DEV_ACTOR_SECRETS` and no longer writes `VITE_SCENARIO_ACTOR_SECRET` at
|
|
311
|
-
all. The root stays on the server.
|
|
312
|
-
- **`pikku persona secret <id>`** mints them for anything else, and a run given
|
|
313
|
-
`PIKKU_PERSONA_SECRETS=id=secret,…` can sign in as those personas and no
|
|
314
|
-
others — asking for one outside the list throws naming the persona instead of
|
|
315
|
-
falling back to the root.
|
|
316
|
-
|
|
317
|
-
`useDevActors()` and `<DevActorSwitcher />` take `secrets` (one per address)
|
|
318
|
-
where they took `secret`, and an actor with no credential is no longer offered
|
|
319
|
-
rather than rendering a row that 401s. `HttpPersonasConfig.secret` and the
|
|
320
|
-
Playwright provider's `secret` additionally accept a resolver, which is how a
|
|
321
|
-
partially-credentialled run is expressed.
|
|
322
|
-
|
|
323
|
-
- ee9da9e: pikku-react now covers linking from a Mantine element: `component={Link}` widens the router generic to `AnyRouter` and stops checking `to` and `params`, so the skill teaches a wrapped typed `Link` reached through `renderRoot` instead.
|
|
324
|
-
- 7d641f3: The three build skills now draw the line between the manual click-through (a smoke check, for layout) and verification: anything worth driving through the UI belongs in a scenario's browser step, not in a browser session steered by hand that nothing re-runs.
|
|
325
|
-
- ee9da9e: The hardcoded-copy check stops flagging a feature's own name
|
|
326
|
-
|
|
327
|
-
Two rules disagreed. `runScenarioFileChecks` requires every `pikkuFeature` to
|
|
328
|
-
live in a `*.scenario.ts`, and moving one there is what put it in front of the
|
|
329
|
-
hardcoded-copy check — which then flagged the feature's own `name` because the
|
|
330
|
-
app catalogue happens to hold the same word:
|
|
331
|
-
|
|
332
|
-
```
|
|
333
|
-
name: 'Downloads', → ✗ "Downloads" → nav__downloads | downloads__title
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
Complying with the first rule created violations of the second, and the advice
|
|
337
|
-
— read the string from the app catalogue — would tie the Console's language to
|
|
338
|
-
the product's. `name`, `description` and `template` declared directly on a
|
|
339
|
-
`pikkuFeature`, `pikkuScenario` or `pikkuScenarioStep` are Console meta and are
|
|
340
|
-
now skipped. A `name` nested deeper — `getByRole('button', { name: 'Speichern'
|
|
341
|
-
})` — is a selector built out of UI copy and is still caught.
|
|
342
|
-
|
|
343
|
-
## 0.12.19
|
|
344
|
-
|
|
345
|
-
### Patch Changes
|
|
346
|
-
|
|
347
|
-
- f1ccfe3: A step ladder reads as one paragraph, not a list of restatements
|
|
348
|
-
|
|
349
|
-
Every step prefixed its actor with `the `, named that actor again, and repeated
|
|
350
|
-
the phase keyword. A three-step run by one person said their name three times
|
|
351
|
-
and `Given` three times, only read as English when the persona key happened to
|
|
352
|
-
be a role noun, and never said who that person was — the fabric template's own
|
|
353
|
-
placeholder came out as `the nadia opens /app`.
|
|
354
|
-
|
|
355
|
-
```
|
|
356
|
-
Given yasser (the founder) signs in
|
|
357
|
-
When yasser opens the dashboard
|
|
358
|
-
And sees the audit log
|
|
359
|
-
And nadia reviews the invite
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
The article is gone: the actor key is the subject verbatim, so a persona named
|
|
363
|
-
after a person reads as that person. A repeated phase reads as `And`, the way
|
|
364
|
-
Gherkin has always written it. A step that continues both the phase and the
|
|
365
|
-
actor drops the repeated subject, because English drops a repeated subject in a
|
|
366
|
-
compound predicate — it takes both, since eliding across a phase change gives
|
|
367
|
-
`When opens the dashboard`, and a pronoun rather than a name would give `they
|
|
368
|
-
sees`, step templates being authored in the third person singular.
|
|
369
|
-
|
|
370
|
-
An actor is introduced once, by the persona's `jobTitle` — prose someone wrote
|
|
371
|
-
for a reader. `roles` is authorisation, so a persona whose only description is a
|
|
372
|
-
`reviewer` grant gets no introduction rather than one assembled out of grants.
|
|
373
|
-
A row carries `sentenceWithRole` alongside `sentence`, set only where an actor
|
|
374
|
-
is first named, so a renderer can offer the introduction as a toggle without
|
|
375
|
-
parsing a composed sentence back apart.
|
|
376
|
-
|
|
377
|
-
`{placeholder}` filling, the `#ordinal` lookup for repeated step names and an
|
|
378
|
-
actorless step reading as its description alone are all unchanged.
|
|
379
|
-
|
|
380
|
-
## 0.12.18
|
|
381
|
-
|
|
382
|
-
### Patch Changes
|
|
383
|
-
|
|
384
|
-
- 7d8082a: Add `pikku fabric variables set` and `pikku fabric variables get`
|
|
385
|
-
|
|
386
|
-
`secrets` was the only stage-scoped store the CLI exposed, so a value declared
|
|
387
|
-
with `defineVariable` could be set locally through `.env` and not at all on a
|
|
388
|
-
deployed stage — `variables.get('NAME')` compiled, ran, and answered `undefined`
|
|
389
|
-
forever, with nothing saying why. The fabric API already had
|
|
390
|
-
`setStageConsoleVariable` and `getStageConsoleVariable`; only the CLI surface was
|
|
391
|
-
missing.
|
|
392
|
-
|
|
393
|
-
`set` stores the value the way `LocalVariablesService` reads one: `JSON.parse`,
|
|
394
|
-
falling back to the raw string. `--value true` is therefore the boolean on a
|
|
395
|
-
stage exactly as it is from `.env`, and `--value '"true"'` is the string. `get`
|
|
396
|
-
prints the stored value as JSON so the two are distinguishable, which is usually
|
|
397
|
-
why you are looking.
|
|
398
|
-
|
|
399
|
-
Variables are not sealed and are readable back — that is the difference from
|
|
400
|
-
`secrets`, and anything that would hurt to print belongs in `secrets set`.
|
|
401
|
-
|
|
402
|
-
## 0.12.17
|
|
403
|
-
|
|
404
|
-
### Patch Changes
|
|
405
|
-
|
|
406
|
-
- a3deea4: Document machine authentication as middleware that sets a session. A caller with an identity (a sandbox, a deployed container, a machine host) is resolved once in `addHTTPMiddleware('*')`, which calls `setSession`; the function is then a plain `pikkuFunc` gated with `scopes` and reads `session`, rather than verifying the bearer token in its own body or in a `permissions` check that returns `true`.
|
|
407
|
-
|
|
408
|
-
The middleware skill also spells out why this cannot be `addTagMiddleware`: tag middleware runs inside `runPikkuFunc`, which the RPC dispatch calls without a `sessionService`, so a session set there never reaches a function invoked over `POST /rpc/:rpcName`.
|
|
409
|
-
|
|
410
|
-
- 30e390b: Skills now name the three languages a project has, and refuse to let them
|
|
411
|
-
collapse into one.
|
|
412
|
-
|
|
413
|
-
An agent building a doctor's portal for a German practice read "the entire UI is
|
|
414
|
-
German" as an instruction about the codebase. It shipped
|
|
415
|
-
`project.inlang/settings.json` with `baseLocale: "de"` and no `en.json` — which
|
|
416
|
-
broke `--add-locale` permanently — alongside RPC functions `getUebersicht` and
|
|
417
|
-
`getPatientendetail`, components `Zeitstrahl` and `AufmerksamkeitStreifen`, and
|
|
418
|
-
database tables `vorgang` and `ereignis`. Nothing in the skills had ever told it
|
|
419
|
-
these were three separate decisions, so it made one.
|
|
420
|
-
|
|
421
|
-
`pikku-concepts` now carries the canonical statement — identifiers are always
|
|
422
|
-
English and no setting changes that; meta (`description`, `title`, `template`)
|
|
423
|
-
follows `locale` in `pikku.config.json`; the product's UI language lives in the
|
|
424
|
-
message catalogue with `defaultLocale`, never in `baseLocale`. `pikku-build-app`
|
|
425
|
-
§1a asks the question and writes the answer into the config; `pikku-scenario`
|
|
426
|
-
splits step identifiers from step prose and admits where the English-only
|
|
427
|
-
reporter frame still shows through; `pikku-i18n` states why `baseLocale` stays
|
|
428
|
-
`en` and what to set instead. `pikku-build-quick`, `pikku-build-platform`,
|
|
429
|
-
`pikku-feature` and `pikku-fabric` carry the short form.
|
|
430
|
-
|
|
431
|
-
## 0.12.16
|
|
432
|
-
|
|
433
|
-
### Patch Changes
|
|
434
|
-
|
|
435
|
-
- 0b1bf53: `pikku dev` turns actor quick login on and mints its secret; `pikku serve` never
|
|
436
|
-
does
|
|
437
|
-
|
|
438
|
-
Which command is running is the thing that knows whether "sign in as <persona>"
|
|
439
|
-
should work, so the two server commands now say so rather than leaving it to
|
|
440
|
-
whatever the environment happens to contain.
|
|
441
|
-
|
|
442
|
-
`pikku dev` sets `PIKKU_DEV_ACTOR_SIGN_IN` before it loads the project and, if no
|
|
443
|
-
actor secret is set, mints a cryptographically random one for the run under both
|
|
444
|
-
`SCENARIO_ACTOR_SECRET` and the `VITE_`-prefixed copy the dev frontend can
|
|
445
|
-
actually read — only prefixed variables reach `import.meta.env`, and the switcher
|
|
446
|
-
runs in the browser. Requiring every contributor to hand-manage a secret for a
|
|
447
|
-
server that is trusted with the database anyway bought nothing and cost setup
|
|
448
|
-
friction on every machine. An explicitly-set secret always wins: a project
|
|
449
|
-
pointing its scenario runs and its dev server at one value has to keep that
|
|
450
|
-
value. The minted one lives only in this process's environment, so it is gone
|
|
451
|
-
when the server stops and yesterday's cannot sign anything in today. Both cases
|
|
452
|
-
are logged, naming where the secret came from — the previous silence is what made
|
|
453
|
-
a missing control unanswerable from outside the container. Where the two names
|
|
454
|
-
disagree the command says so instead of picking one quietly, because that
|
|
455
|
-
disagreement presents as "the switcher signs in nowhere".
|
|
456
|
-
|
|
457
|
-
`pikku serve` is the production server command and does the opposite: it clears
|
|
458
|
-
the marker outright, so an inherited environment cannot switch passwordless
|
|
459
|
-
sign-in on behind the operator, and it warns when it had something to clear. What
|
|
460
|
-
it deliberately leaves alone is `PIKKU_ALLOW_ACTOR_SIGN_IN` — scenario suites have
|
|
461
|
-
to be able to run against a deployed stage, and that opt-in is the supported way
|
|
462
|
-
to say so.
|
|
463
|
-
|
|
464
|
-
`pikku validate`'s fix hint for a project with personas but no actor sign-in no
|
|
465
|
-
longer tells people to control the endpoint by withholding the secret, which is
|
|
466
|
-
no longer how it is controlled, and the `pikku-better-auth` skill documents the
|
|
467
|
-
gate, the two escape hatches, and the two distinct refusals.
|
|
468
|
-
|
|
469
|
-
- 8519a73: Say plainly that the dev seed is local only. No deploy applies it, so the test for a row is not whether it looks realistic but whether the app would be broken without it in production — a venue, a catalogue, a tenant is configuration and belongs in a migration. Names the failure it causes: a stage whose pages return 200 while its first data read throws.
|
|
470
|
-
|
|
471
|
-
## 0.12.15
|
|
472
|
-
|
|
473
|
-
### Patch Changes
|
|
474
|
-
|
|
475
|
-
- 56d6fde: Tag the skills Fabric sandboxes rely on with `installGroups: [fabric]`, so `pikku skills install --fabric` pulls them
|
|
476
|
-
- 56d6fde: `pikku-info` becomes `pikku-meta`, and now owns the whole metadata surface rather
|
|
477
|
-
than the four `pikku info` tables.
|
|
478
|
-
|
|
479
|
-
Fifty-one skills already open with "Discover before editing. Run the relevant
|
|
480
|
-
`pikku meta ... --json`", and no skill documented that command — the one that did
|
|
481
|
-
exist covered a different, smaller command and was named after it. It also carried
|
|
482
|
-
no `installGroups`, so `pikku skills install --core` never installed it and agents
|
|
483
|
-
never saw it at all.
|
|
484
|
-
|
|
485
|
-
It now covers reading (`context`, `functions`, `schemas`, `workflows`, `wires`,
|
|
486
|
-
`permissions`, `middleware`, `clients`), changing (`pikku meta apply` — the batch
|
|
487
|
-
contract, which properties each kind accepts, and why one `pikku all` at the end
|
|
488
|
-
beats one per property), and keeps the `pikku info` tables as the human-readable
|
|
489
|
-
view. `installGroups: [core]` means it ships.
|
|
490
|
-
|
|
491
|
-
## 0.12.14
|
|
492
|
-
|
|
493
|
-
### Patch Changes
|
|
494
|
-
|
|
495
|
-
- 4058c3a: A default skills install is now the seventeen that teach a `#pikku/*` door, not everything
|
|
496
|
-
- 4058c3a: `pikku doc --ai` now names the skill that teaches each door, and pikku-concepts sends you there first
|
|
497
|
-
- 4058c3a: Gate the door-to-skill table so it cannot name a skill a default install does not get
|
|
498
|
-
- 9d48e8a: Fail `pikku fabric validate` when a scenario step hardcodes a string the message catalogue already owns.
|
|
499
|
-
|
|
500
|
-
A browser step that says `getByLabel('Full Name')` passes only while the app happens to render the base locale, and any copy edit turns it into a selector timeout that points at the wizard rather than at the rename that caused it. Validate now reads each `apps/<app>/messages/<baseLocale>.json` and errors on any string in a `*.steps.ts` / `*.scenario.ts` that is verbatim a catalogue value, naming the key to use.
|
|
501
|
-
|
|
502
|
-
It scans every literal rather than only the ones sitting in a `getBy*` call, because copy passed to a project helper — `pick('Where would you like to work?', …)` — reaches the DOM just the same. Comments are stripped first, since the prose around a step quotes the copy it is explaining. A project with no inlang app is not scanned, and a string the catalogue does not own (a test id, a fixture filename) is left alone.
|
|
503
|
-
|
|
504
|
-
The `pikku-scenario` skill gains the corresponding rule, including typing the lookup off the catalogue JSON rather than the generated Paraglide output, so a renamed key is a compile error instead of a run-time timeout.
|
|
505
|
-
|
|
506
|
-
- 4058c3a: Add a `client` install group, so frontend-facing skills can be pulled without the whole `core` set: `pikku skills install --client`. `installGroups` has always been a list and the resolver installs a skill if _any_ requested group matches, so `[core, client]` keeps every existing `--core` install identical.
|
|
507
|
-
|
|
508
|
-
Tagged `[core, client]`: `pikku-react`, `pikku-react-query`, `pikku-workflows-client`, `pikku-paraglide`, `pikku-i18n`, `pikku-rtl`.
|
|
509
|
-
|
|
510
|
-
- 4058c3a: Correct the `fabric` install group, which had drifted into a catch-all. It now holds only the two skills a Fabric sandbox agent actually needs: `pikku-fabric` and `pikku-ai-voice` (Fabric apps use voice I/O, and it was reaching nobody).
|
|
511
|
-
|
|
512
|
-
Moved to `core`, because they describe general Pikku work rather than anything Fabric-specific: `pikku-software-archaeology`, `pikku-product-second-opinion`, `pikku-schema-cfworker` (the Fabric template's Workers entry files are generated, so no agent ever writes `CFWorkerSchemaService`), `pikku-deploy-cloudflare` and `pikku-fabric-debug` (Fabric deploys and reads logs through CI, not through the app agent).
|
|
513
|
-
|
|
514
|
-
Deleted `pikku-tag-middleware`, a tombstone pointing at `pikku-middleware`. It carried no `installGroups`, so it never installed anywhere and only cost a name in the corpus.
|
|
515
|
-
|
|
516
|
-
Dropped `pikku-build-app`, `pikku-build-quick` and `pikku-build-platform` out of `core`. They are whole-app build procedures that duplicate whatever the host agent's own prompt already says, so auto-installing them into every project put three rival build modes in the picker. They still ship in the package and install with `--only`.
|
|
517
|
-
|
|
518
|
-
- 4058c3a: Drop seven single-door skills out of the core install group
|
|
519
|
-
|
|
520
|
-
`--core` installed a reference skill for every transport whether or not a
|
|
521
|
-
project used one. The seven moved here (`pikku-services`, `pikku-queue`,
|
|
522
|
-
`pikku-cli`, `pikku-trigger`, `pikku-schedule`, `pikku-schema-ajv`,
|
|
523
|
-
`pikku-schema-cfworker`) join the deploy and adapter skills as `--only`
|
|
524
|
-
installs, so a project that wires a queue asks for the queue skill.
|
|
525
|
-
|
|
526
|
-
Measured against 24 fabric build runs, none of the seven was loaded once,
|
|
527
|
-
while their descriptions sat in the picker on every turn.
|
|
528
|
-
|
|
529
|
-
## 0.12.13
|
|
530
|
-
|
|
531
|
-
### Patch Changes
|
|
532
|
-
|
|
533
|
-
- 58cb0f8: Scaffold an addon whose exports point at the leaf its codegen actually writes
|
|
534
|
-
|
|
535
|
-
`pikku all` roots an addon's generated tree at `.pikku/addon/`, but `pikku new
|
|
536
|
-
addon` still wrote the pre-split targets: `./.pikku/*` resolved to
|
|
537
|
-
`./dist/.pikku/*` and the internal RPC map to `./dist/.pikku/rpc/...`, neither of
|
|
538
|
-
which exists in the published package. The subpaths a consumer writes are
|
|
539
|
-
unchanged — only the targets gain the `addon` segment.
|
|
540
|
-
|
|
541
|
-
The addon manifest reference in the `pikku-addon` skill described the same
|
|
542
|
-
package.json one migration further back, with `imports` and `exports` naming the
|
|
543
|
-
source tree and `files: ["dist", ".pikku"]` shipping `.ts` files Node cannot
|
|
544
|
-
load. It now documents the built layout, and why `imports` and tsconfig `paths`
|
|
545
|
-
deliberately point at different trees.
|
|
546
|
-
|
|
547
|
-
The plain scaffold — no `--secret`, `--oauth` or `--credential` — built its API
|
|
548
|
-
service with `new XService(variables)` against a class declaring no constructor,
|
|
549
|
-
so `pikku new addon <name>` produced a package that did not typecheck until the
|
|
550
|
-
author deleted the argument. Only the authenticating variants take one.
|
|
551
|
-
|
|
552
|
-
## 0.12.12
|
|
553
|
-
|
|
554
|
-
### Patch Changes
|
|
555
|
-
|
|
556
|
-
- 8d6a6bc: fix(cli): a scaffold flag says a surface exists, not who may call it
|
|
557
|
-
|
|
558
|
-
`scaffold.<feature>` accepted an `auth` field, and the generated wrapper emitted
|
|
559
|
-
it onto the wired function. That put authentication in two places at once: the
|
|
560
|
-
target function already declares whether it needs a session, its wiring, its
|
|
561
|
-
scopes and its addon gate already refine it, and `runPikkuFunc` already enforces
|
|
562
|
-
all of that on every call. The scaffold flag only stacked a coarser gate in
|
|
563
|
-
front of the one that actually decides, and — being a config field — it could
|
|
564
|
-
disagree with the function it was gating.
|
|
565
|
-
|
|
566
|
-
`PikkuScaffoldFeature` is now `boolean | { path?: string }`. It answers two
|
|
567
|
-
things and no more: whether the surface is generated, and where the file is
|
|
568
|
-
written. A feature that was `{ "auth": false }` becomes plain `true`, and
|
|
569
|
-
`pikku enable` loses its `--noAuth` flag along with the dimension it set.
|
|
570
|
-
|
|
571
|
-
The six generators that took the flag no longer take one. The four that generate
|
|
572
|
-
a dispatcher — public RPC, public agent, workflow routes and the events channel
|
|
573
|
-
— now emit a fixed `auth: false`. That is the wrapper declining to gate, not the
|
|
574
|
-
scaffold declaring the surface public: `rpcCaller` forwards to whichever
|
|
575
|
-
function the caller named, and that function's own `auth`, permissions, scopes
|
|
576
|
-
and addon gate are what decide. Emitting nothing would not be neutral, since a
|
|
577
|
-
wiring without `auth` requires a session and would reject the call before the
|
|
578
|
-
gate that decides ever ran. The two that generate scoped admin functions — user
|
|
579
|
-
admin and virtual users — emit no `auth`, because they are `pikkuFunc` with
|
|
580
|
-
their own `scopes`: session-required by construction, and the deciding function
|
|
581
|
-
rather than a wrapper in front of one.
|
|
582
|
-
|
|
583
|
-
The legacy `'auth'` / `'no-auth'` string values are gone with it. A bare string
|
|
584
|
-
is still refused rather than read as a `path`: under `boolean | object` no
|
|
585
|
-
string is valid, so guessing one would turn a typo into a generated file nobody
|
|
586
|
-
asked for.
|
|
587
|
-
|
|
588
|
-
- 31ad85f: fix(emails): escape substituted values in the generated email renderer
|
|
589
|
-
|
|
590
|
-
`renderEmailTemplate` spliced values into HTML unescaped and looped substitution
|
|
591
|
-
until it reached a fixed point, so a value containing `"` broke out of the
|
|
592
|
-
attribute it landed in, a value containing markup was injected verbatim, and a
|
|
593
|
-
value containing `{{...}}` was re-expanded as a template on the next pass. An
|
|
594
|
-
ordinary CSS font stack from `theme.json` was enough to corrupt the document.
|
|
595
|
-
|
|
596
|
-
Rendering is now layered by trust. Partials are inlined first; `theme.*` and
|
|
597
|
-
`t.*` are expanded next as template-author input; caller `data` is substituted in
|
|
598
|
-
a single pass that is never rescanned. Values are HTML-escaped in `.html` output
|
|
599
|
-
and left raw in `.subject.txt` / `.text.txt`. `{{content}}` and partials stay
|
|
600
|
-
raw, and `{{{value}}}` is a new opt-in raw form. The console's email preview uses
|
|
601
|
-
the same renderer, so previews match what is sent.
|
|
602
|
-
|
|
603
|
-
## 0.12.11
|
|
604
|
-
|
|
605
|
-
### Patch Changes
|
|
606
|
-
|
|
607
|
-
- 7722ceb: Split the addon leaf so an application cannot shadow a linked addon's own
|
|
608
|
-
|
|
609
|
-
An addon authored its services through `#pikku/addon`, and so did an
|
|
610
|
-
application installing one. Node keeps those apart — `#pikku/*` is a
|
|
611
|
-
package-private subpath import, resolved against the addon's own
|
|
612
|
-
`package.json` — but tsconfig `paths` are global to a tsx process, and every
|
|
613
|
-
runtime template maps `#pikku/*` onto a sibling package. A linked addon's
|
|
614
|
-
`#pikku/addon` was resolved against the _application's_ leaf, which holds the
|
|
615
|
-
install half and none of the authoring exports, and every template failed to
|
|
616
|
-
boot with `does not provide an export named 'pikkuAddonServices'`.
|
|
617
|
-
|
|
618
|
-
The authoring half now sits at `#pikku/addon/setup`. An application generates a
|
|
619
|
-
flat `.pikku/<leaf>`, so there is nothing there for that specifier to match and
|
|
620
|
-
the resolver falls back to Node, which reads the addon's own imports. Addons
|
|
621
|
-
declaring themselves import `pikkuAddonConfig`, `pikkuAddonServices` and
|
|
622
|
-
`pikkuAddonWireServices` from `#pikku/addon/setup`; `wireAddon` and
|
|
623
|
-
`wireRemoteAddon` stay at `#pikku/addon`.
|
|
624
|
-
|
|
625
|
-
`wireAddon` and `wireRemoteAddon` also move off `@pikku/core/rpc` onto
|
|
626
|
-
`@pikku/core/addon`. Being reached over rpc is how an addon is called rather
|
|
627
|
-
than what it is, and it put the whole addon surface behind the rpc subpath for
|
|
628
|
-
consumers that only wanted to install one.
|
|
629
|
-
|
|
630
|
-
- 6eef0a0: Bump every dependency to its latest compatible minor/patch across the monorepo.
|
|
631
|
-
- 3b1164a: feat(react,mantine): ship the dev actor switcher instead of making every app copy it
|
|
632
|
-
|
|
633
|
-
The dev-only "Sign in as …" control — one click signs in as a declared scenario
|
|
634
|
-
persona, no password — was hand-copied into every app that needed it, because
|
|
635
|
-
`pikku fabric validate` requires any frontend with a login screen to have one.
|
|
636
|
-
The `devActors()` / `signInAsActor()` pair was byte-identical everywhere it
|
|
637
|
-
landed, including the `import.meta.env.DEV` gate that keeps the shared secret out
|
|
638
|
-
of production bundles. That is not a thing each app should be re-deriving from a
|
|
639
|
-
copy-paste.
|
|
640
|
-
|
|
641
|
-
Split along the dependency line:
|
|
642
|
-
|
|
643
|
-
- `@pikku/react` gains `useDevActors()`, `signInAsActor()` and `parseDevActors()`.
|
|
644
|
-
UI-free, so it stays inside the package's react-only dependency budget.
|
|
645
|
-
- `@pikku/mantine/dev` gains `<DevActorSwitcher />`, built on that hook. It is a
|
|
646
|
-
new entry point rather than part of `/core`, because `/core`'s contract is
|
|
647
|
-
"drop-in alias for `@mantine/core`" and exporting a component Mantine has no
|
|
648
|
-
counterpart for would break it.
|
|
649
|
-
|
|
650
|
-
The component takes `onSignedIn` rather than depending on a router, and the
|
|
651
|
-
actors/secret are passed in rather than read from env — how env is spelled is a
|
|
652
|
-
bundler fact (`import.meta.env.VITE_*` vs `process.env.NEXT_PUBLIC_*`), and a
|
|
653
|
-
package that guesses gets it wrong for half its consumers.
|
|
654
|
-
|
|
655
|
-
The skills document it in the four places an agent would look: `pikku-better-auth`
|
|
656
|
-
for the `actor` plugin's endpoint (which had only `/dev/quick-login` before, and
|
|
657
|
-
so sent agents to the wrong control), `pikku-scenario` for the actor list being
|
|
658
|
-
the same one a human signs in through, `pikku-react` for the hook, and
|
|
659
|
-
`pikku-fabric` for the validate rule that requires it.
|
|
660
|
-
|
|
661
|
-
`fabric validate` now also accepts a `useDevActors()` call site as evidence the
|
|
662
|
-
control is wired, so apps that want their own UI on the shared logic pass. The
|
|
663
|
-
hand-rolled shape still passes too — nothing existing breaks. Its fix text no
|
|
664
|
-
longer tells you to hand-write the helper, which would have become wrong advice
|
|
665
|
-
the day this shipped.
|
|
666
|
-
|
|
667
|
-
- 266e3bc: `#pikku` is a namespace, not a module: one subpath per wiring
|
|
668
|
-
|
|
669
|
-
The bare `#pikku` specifier resolved to `.pikku/pikku-types.gen.ts`, a hub that
|
|
670
|
-
re-exported all twelve wiring leaves with `export *` — undoing the split the
|
|
671
|
-
leaves exist for, each of which still says so in its own generated header
|
|
672
|
-
("HTTP-specific type definitions for tree-shaking optimization"). Reaching that
|
|
673
|
-
hub put 33 distinct `@pikku/core` subpaths into the module graph, and neither
|
|
674
|
-
consumer could drop them again: bundlers keep `export *` chains because the app
|
|
675
|
-
declares no `sideEffects`, and Node and tsx do not tree-shake at all, so an app
|
|
676
|
-
with no queues still executed `@pikku/core/queue` at boot.
|
|
677
|
-
|
|
678
|
-
The hub is gone. An app now imports the leaf the name belongs to —
|
|
679
|
-
`#pikku/function`, `#pikku/http`, `#pikku/workflow` — and a project's `imports`
|
|
680
|
-
map declares two patterns, because both resolvers pick the more specific one:
|
|
681
|
-
|
|
682
|
-
```json
|
|
683
|
-
"#pikku/*.js": "./.pikku/*.ts",
|
|
684
|
-
"#pikku/*": "./.pikku/*/index.ts"
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
A source tree names the `.ts` on both. Webpack, esbuild and Bun all rewrite a
|
|
688
|
-
`.js` specifier to the `.ts` beside it for a relative import but not for an
|
|
689
|
-
imports-map target, so a `.js` target there resolves to a file that does not
|
|
690
|
-
exist. The two places that keep `.js` are the ones where it is the real file: a
|
|
691
|
-
published addon, whose map points into `dist`, and a project that imports a
|
|
692
|
-
declaration-only generated file such as `pikku-rpc-wirings-map.gen.d.ts`, where
|
|
693
|
-
naming the `.js` lets the type resolver's own mapping reach the `.d.ts`.
|
|
694
|
-
|
|
695
|
-
`pikku` generates the leaf indexes and removes the hub, and `pikku validate`
|
|
696
|
-
reports a barrel import as an error. The split also turns the addon boundary
|
|
697
|
-
from advice into a rule: an addon never generates the wiring leaves, so
|
|
698
|
-
`#pikku/http` fails at the specifier rather than yielding "no exported member"
|
|
699
|
-
from a hub that quietly dropped the re-export.
|
|
700
|
-
|
|
701
|
-
- 9fce0f1: Give a persona step its actor instead of making it unwrap one
|
|
702
|
-
|
|
703
|
-
`requireActor(scenarioStep)` was the first line of every step that acts as
|
|
704
|
-
somebody, and it existed because the actor lived on the `scenarioStep` wire as
|
|
705
|
-
an optional property. A property of a wire member is either optional for every
|
|
706
|
-
binding or required for all of them, so the only expressible answer was
|
|
707
|
-
"optional", and each step paid for it with a guard.
|
|
708
|
-
|
|
709
|
-
The actor is now its own wire member, `wire.actor`, injected by the runner. Wire
|
|
710
|
-
members can be required per binding, so a step declares whether it runs as
|
|
711
|
-
somebody and the type follows:
|
|
712
|
-
|
|
713
|
-
```typescript
|
|
714
|
-
export const buysAnApple = pikkuScenarioStep<
|
|
715
|
-
{ qty: number },
|
|
716
|
-
{ orderId: string }
|
|
717
|
-
>({
|
|
718
|
-
name: 'buysAnApple',
|
|
719
|
-
actor: true,
|
|
720
|
-
default: async (_services, { qty }, { actor }) =>
|
|
721
|
-
actor.invoke('placeOrder', { qty }),
|
|
722
|
-
})
|
|
723
|
-
```
|
|
724
|
-
|
|
725
|
-
A `browser` binding implies it — a window is opened as somebody, so every
|
|
726
|
-
binding of a step that has one gets the actor too. A step that declares neither
|
|
727
|
-
has no `actor` on its wire at all, rather than an optional one: a pure assertion
|
|
728
|
-
over what an earlier step returned has nobody to be, and `attemptsSignIn`
|
|
729
|
-
deliberately posts credentials instead of reusing an actor's established
|
|
730
|
-
session. That distinction is why the requirement is declared per step rather
|
|
731
|
-
than inferred from the step being a persona step — "persona step ⇒ has an actor"
|
|
732
|
-
is false, and a guard built on it rejects the 61 steps in the e2e suite that
|
|
733
|
-
correctly run without one.
|
|
734
|
-
|
|
735
|
-
Dispatching a step that declared an actor without `{ actor: actors.x }` now
|
|
736
|
-
fails before the body runs, with `ScenarioActorRequired` naming the step.
|
|
737
|
-
`ScenarioBrowserActorRequired` is replaced by it, and `requireActor` is gone
|
|
738
|
-
from `@pikku/core/scenario` and the generated `#pikku/scenario` barrel.
|
|
739
|
-
|
|
740
|
-
- 9fce0f1: Say what a scenario step is actually given, and stop the skill teaching an RPC call that throws
|
|
741
|
-
|
|
742
|
-
The `pikku-scenario` skill's two `default` witnesses destructured `rpc` from
|
|
743
|
-
services and called `rpc.invoke`. That is exactly what the scenario runner
|
|
744
|
-
refuses: steps run in the CLI process, and `guardRpc` answers every member with
|
|
745
|
-
_"Scenario tried to run 'getOrder' as an internal step. Every workflow.do in a
|
|
746
|
-
scenario must carry { actor: actors.x }"_. Both examples now go through
|
|
747
|
-
`actor.invoke` off the step's wire, which is the path the surrounding prose
|
|
748
|
-
already described.
|
|
749
|
-
|
|
750
|
-
Adds a **What a step is given** section, because nothing said it. The services
|
|
751
|
-
object is built by hand in `scenario.ts` and holds `logger`, `workflowService`,
|
|
752
|
-
`workflowRunService` and — only when the project declares agents — `agentRunner`.
|
|
753
|
-
There is no `kysely`, no `variables`, no `secrets` and none of the project's own
|
|
754
|
-
services, so a step that destructures one gets `undefined` and fails on first
|
|
755
|
-
use, which reads like a broken container and is not. The section names the three
|
|
756
|
-
ways in (`invoke`, `invokeRaw`, a plain `fetch` at `env.apiUrl`), the two
|
|
757
|
-
consequences that shape how steps get written, and the condition on
|
|
758
|
-
`agentRunner` — `createDevAgentRunner` needs a base URL _and_ a key together, so
|
|
759
|
-
a project with only `OPENAI_API_KEY` set gets `undefined` and every conversing
|
|
760
|
-
scenario fails before the persona says anything.
|
|
761
|
-
|
|
762
|
-
Adds **Declaring personas in TypeScript**, covering the one-call rule and the
|
|
763
|
-
trap underneath it: `definePersonas` is read from source and never evaluated, so
|
|
764
|
-
every value must be statically knowable — but only `name` is validated. A
|
|
765
|
-
computed `personality` is dropped in silence and the persona runs with a blank
|
|
766
|
-
temperament. `stringProperty` accepts `ts.isStringLiteralLike`, so a
|
|
767
|
-
no-substitution template literal is read and is the way to write a long
|
|
768
|
-
personality across several lines; a `+` concatenation is not. Also records that
|
|
769
|
-
`actorInstructions` builds the conversing persona's prompt from `name`,
|
|
770
|
-
`jobTitle`, `personality` and the scenario's `task` only — `disposition`,
|
|
771
|
-
`goals` and `roles` are stored and shown but never reach it.
|
|
772
|
-
|
|
773
|
-
Finally, the three `import ... from '#pikku/workflow/pikku-workflow-types.gen.js'`
|
|
774
|
-
lines now point at `#pikku/scenarios/pikku-scenario-types.gen.js`, which is where
|
|
775
|
-
the scenario surface moved when the barrel was split.
|
|
776
|
-
|
|
777
|
-
Also corrects three import specifiers the skill still taught from before the
|
|
778
|
-
`#pikku` leaves landed: `#pikku/scenarios/pikku-scenario-types.gen.js` and
|
|
779
|
-
`@pikku/core/workflow` both become `#pikku/scenario`, which is the one door the
|
|
780
|
-
leaf exists to be and the specifier every step file in the e2e suite already
|
|
781
|
-
uses.
|
|
782
|
-
|
|
783
|
-
- 727671b: `wireAddon` and `wireRemoteAddon` move from `#pikku/function` to `#pikku/addon`.
|
|
784
|
-
|
|
785
|
-
Installing an addon and authoring one are the same concept from opposite ends,
|
|
786
|
-
so they are one import: an application's `#pikku/addon` carries the two install
|
|
787
|
-
functions, an addon package's carries `pikkuAddonConfig`, `pikkuAddonServices`,
|
|
788
|
-
`pikkuAddonWireServices` and `AddonBaseServices`.
|
|
789
|
-
|
|
790
|
-
Two generation fixes came with it:
|
|
791
|
-
|
|
792
|
-
- `CredentialsMap` is generated as a type alias rather than an interface. An
|
|
793
|
-
interface has no implicit index signature, so it was never assignable to the
|
|
794
|
-
`Record<string, unknown>` that `GetCredential` is constrained by, and every
|
|
795
|
-
generated project reported two errors on its own function types.
|
|
796
|
-
- An unresolved `SingletonServices` type is now `PKU724` instead of a services
|
|
797
|
-
map with no entries in it. Written out, the empty map made every service
|
|
798
|
-
optional and the real failure resurfaced as unrelated "possibly undefined"
|
|
799
|
-
errors in files nobody had touched.
|
|
800
|
-
|
|
801
|
-
## 0.12.10
|
|
802
|
-
|
|
803
|
-
### Patch Changes
|
|
804
|
-
|
|
805
|
-
- 7406bfe: Rename the agent runtime from `AI*` to `Agent*` (#596)
|
|
806
|
-
|
|
807
|
-
`AI` described the model provider, not the thing being named. Every symbol that
|
|
808
|
-
belongs to the agent runtime now says `Agent`; the symbols that genuinely wrap a
|
|
809
|
-
model provider — `AIEmbeddingService`, `AIProviderOptions`, `AIEmbedParams`,
|
|
810
|
-
`AITranscriptionParams`, `AIGenerateImageParams` and their siblings, and the
|
|
811
|
-
`@pikku/ai-vercel` / `@pikku/ai-deepinfra` / `@pikku/ai-voice` packages — keep
|
|
812
|
-
their names.
|
|
813
|
-
|
|
814
|
-
**Wiring**
|
|
815
|
-
- `pikkuAIAgent` → `pikkuAgent`, `pikkuAIScorer` → `pikkuAgentScorer`,
|
|
816
|
-
`pikkuAIJudge` → `pikkuAgentJudge`
|
|
817
|
-
- `CoreAIAgent` → `CoreAgent`, `AIAgentInput` → `AgentInput`, `AIAgentStep` →
|
|
818
|
-
`AgentStep`, `AIMessage` → `AgentMessage`, and the rest of the agent types
|
|
819
|
-
- `AIAgentRunnerService` → `AgentRunnerService`, `AIStorageService` →
|
|
820
|
-
`AgentStorageService`, `AIRunStateService` → `AgentRunStateService`
|
|
821
|
-
|
|
822
|
-
**Entry points**
|
|
823
|
-
|
|
824
|
-
`@pikku/core/agent` → `@pikku/core/agent`, `@pikku/core/agent-scorer` →
|
|
825
|
-
`@pikku/core/agent-scorer`.
|
|
826
|
-
|
|
827
|
-
**Queues**
|
|
828
|
-
|
|
829
|
-
The scorer queues are now `agent-score-fast` and `agent-score-slow`. Drain the
|
|
830
|
-
old `ai-score-fast` / `ai-score-slow` queues before deploying — jobs still
|
|
831
|
-
sitting on them when the new workers start will never be picked up.
|
|
832
|
-
|
|
833
|
-
**Scaffolds**
|
|
834
|
-
|
|
835
|
-
The agent scaffold pikku wrote for your project — `<scaffold>/agent/agent.gen.ts`
|
|
836
|
-
and its schemas file — imports `@pikku/core/ai-agent`, which no longer exists. A
|
|
837
|
-
scaffold is normally written once and then left alone, so `pikku all` would find
|
|
838
|
-
it present and leave the broken import in place. It now deletes an agent scaffold
|
|
839
|
-
importing either removed entry point and regenerates it in the same run. Anything
|
|
840
|
-
you added to that file goes with it, so move local edits out first.
|
|
841
|
-
|
|
842
|
-
**Database**
|
|
843
|
-
|
|
844
|
-
The agent tables are renamed: `ai_threads`, `ai_message`, `ai_tool_call`,
|
|
845
|
-
`ai_working_memory`, `ai_run` and `ai_run_score` become `agent_threads`,
|
|
846
|
-
`agent_message`, `agent_tool_call`, `agent_working_memory`, `agent_run` and
|
|
847
|
-
`agent_run_score`, along with their indexes and the `ai_working_memory_pk`
|
|
848
|
-
constraint. The same rename applies to the MongoDB collections.
|
|
849
|
-
|
|
850
|
-
`ensurePikkuSchema` creates tables it cannot find, so an existing database will
|
|
851
|
-
get empty `agent_*` tables and leave the old data stranded in `ai_*`. Rename
|
|
852
|
-
them before the first boot on the new version:
|
|
853
|
-
|
|
854
|
-
```sql
|
|
855
|
-
ALTER TABLE ai_threads RENAME TO agent_threads;
|
|
856
|
-
ALTER TABLE ai_message RENAME TO agent_message;
|
|
857
|
-
ALTER TABLE ai_tool_call RENAME TO agent_tool_call;
|
|
858
|
-
ALTER TABLE ai_working_memory RENAME TO agent_working_memory;
|
|
859
|
-
ALTER TABLE ai_run RENAME TO agent_run;
|
|
860
|
-
ALTER TABLE ai_run_score RENAME TO agent_run_score;
|
|
861
|
-
```
|
|
862
|
-
|
|
863
|
-
- e7e5319: Add `pikku semver`, which derives a release's semver from a diff against a deployed surface and writes `.pikku/changes.gen.json`
|
|
864
|
-
|
|
865
|
-
A function or client-facing wiring that disappeared is major, an addition is minor, and a surface that did not move is patch. Where the generated JSON Schemas are available the verdict goes below the id level: a removed field or a newly required input field is breaking, an added optional one is not — direction-aware, so an output field going optional counts even though the same change on an input does not. `versions.pikku.json` is consumed, so a `@v2` bump does not read as a removal while v1 is still published.
|
|
866
|
-
|
|
867
|
-
The baseline is `--against <path|url>`: another `.pikku` directory, a snapshot file, or a snapshot published by `pikku semver --emit`. `--fail-on <level>` turns the verdict into a CI gate.
|
|
868
|
-
|
|
869
|
-
- 411f89a: Add `pikku update`: report which `@pikku/*` dependencies can move forward, and which peers those versions need.
|
|
870
|
-
|
|
871
|
-
Reporting only by default. `--update` writes the new ranges into every covered package.json — the project root plus every workspace it declares — and then runs an install with the package manager the project names (`--no-install` to skip). `--update-peers` additionally writes the ranges unsatisfied peers require; it is separate because a peer bump can cross a major of a third-party package.
|
|
872
|
-
|
|
873
|
-
Peers are read off the version the run lands on rather than the one installed, so an update that needs a companion bump says so before it is applied. Ranges that cannot be substituted into (`workspace:*`, `file:`, unions, x-ranges) are reported and left alone, and a package the registry could not answer for is reported as unresolved rather than current.
|
|
874
|
-
|
|
875
|
-
## 0.12.9
|
|
876
|
-
|
|
877
|
-
### Patch Changes
|
|
878
|
-
|
|
879
|
-
- b5fa1e5: Enumerate addon secret and credential grants in the deployment manifest.
|
|
880
|
-
|
|
881
|
-
`wireAddon`'s `secretGrants` / `credentialGrants` widen an addon's scope the same
|
|
882
|
-
way `globalSecrets` does, only narrower — but the manifest reported the exemption
|
|
883
|
-
and not the grant, so a deployment could not see the secrets an app had lent an
|
|
884
|
-
addon. `grantedSecretAddons` and `grantedCredentialAddons` now list them by name,
|
|
885
|
-
including override keys, since scoping is checked before an override renames.
|
|
886
|
-
|
|
887
|
-
The `pikku-addon` skill documents the whole grant family and the scoping rule
|
|
888
|
-
behind it, rather than the override fields alone.
|
|
889
|
-
|
|
890
|
-
## 0.12.8
|
|
891
|
-
|
|
892
|
-
### Patch Changes
|
|
893
|
-
|
|
894
|
-
- 0ab1a88: feat(knowledge): draw a note's scenario and its decision, and say the vocabulary exists
|
|
895
|
-
|
|
896
|
-
The console already drew ```mermaid fences as diagrams and `> [!NOTE]` blocks as
|
|
897
|
-
callouts, and nothing told the librarian either existed — the skill that governs
|
|
898
|
-
what goes in a note never mentioned them, so notes were written as prose and
|
|
899
|
-
tables into a renderer that would happily have drawn the graph. The gap was the
|
|
900
|
-
guidance, not the format.
|
|
901
|
-
|
|
902
|
-
Two blocks join them. A slice's ```gherkin scenario is drawn rather than
|
|
903
|
-
highlighted: the keywords line up in a column so the shape of the scenario is
|
|
904
|
-
readable before a word of it is, and each quoted persona becomes a chip — which
|
|
905
|
-
also makes a first-person scenario, the form the format rejects, visibly a block
|
|
906
|
-
with no personas in it.
|
|
907
|
-
|
|
908
|
-
A new ```decision fence states what a decision note owes: `chosen`, `rules-out`,
|
|
909
|
-
`because`. The middle one is the half that gets dropped, so `pikku knowledge
|
|
910
|
-
validate` now warns when a fence says what was chosen and never says what it
|
|
911
|
-
closes off. The fence is optional and a decision argued in prose is still a
|
|
912
|
-
decision — validate checks the fences that exist rather than asking every note
|
|
913
|
-
to be reformatted.
|
|
914
|
-
|
|
915
|
-
`Markdown` is exported from `@pikku/console` so the fabric console can render the
|
|
916
|
-
same notes through the same vocabulary instead of a second `<ReactMarkdown>`.
|
|
917
|
-
|
|
918
|
-
- 8978fbd: feat(workflow): let an approval gate declare who may answer it
|
|
919
|
-
|
|
920
|
-
`workflow.approval()` gains `approvers` (`'any' | 'owner' | 'not-initiator'`)
|
|
921
|
-
and `approverScope`, so a gate can require four-eyes sign-off, restrict itself
|
|
922
|
-
to the run's initiator, or require the decider to hold a named scope.
|
|
923
|
-
|
|
924
|
-
Both are enforced when the workflow replays the gate — the same place, and for
|
|
925
|
-
the same reason, the decision payload is validated: the policy is a value on
|
|
926
|
-
the workflow, and a decision can be recorded before the run has ever reached
|
|
927
|
-
the gate. A decision that fails the policy is discarded and the gate stays
|
|
928
|
-
closed. Where the run has already published its policy, the check also runs at
|
|
929
|
-
submission time so the caller gets a 403 rather than silence.
|
|
930
|
-
|
|
931
|
-
An answer is now recorded where it can be answered for later. The settled
|
|
932
|
-
decision carries `decidedBy` and `decidedAt` in its `ApprovalOutcome`, so who
|
|
933
|
-
signed reaches `workflowStep.result` and `workflowStepHistory` rather than
|
|
934
|
-
living only in mutable run state. Every answer — accepted, refused at the door,
|
|
935
|
-
or cleared on replay — is also written to the audit sink as
|
|
936
|
-
`workflow.approval.decided`, which outlives the run: `deleteRun` cascades to
|
|
937
|
-
steps and history, and a refused attempt never reaches a step at all. Projects
|
|
938
|
-
with no audit service wired are unaffected.
|
|
939
|
-
|
|
940
|
-
**This loosens the default.** `approveStep` previously refused anyone but the
|
|
941
|
-
run's initiator, unconditionally. A gate that declares no `approvers` now
|
|
942
|
-
accepts a decision from anyone the approve entrypoint admits — restore the old
|
|
943
|
-
behaviour per-gate with `approvers: 'owner'`, or gate the approve route with
|
|
944
|
-
`auth`/`permissions`. Ownership still governs _reads_ of a run unchanged.
|
|
945
|
-
|
|
946
|
-
## 0.12.7
|
|
947
|
-
|
|
948
|
-
### Patch Changes
|
|
949
|
-
|
|
950
|
-
- e110c55: Add `scenario.expectScore` — grade a finished agent run with a declared scorer and assert on it.
|
|
951
|
-
|
|
952
|
-
An agent's answer cannot be matched against a fixed string, so a scenario grades
|
|
953
|
-
it instead. `expectScore(step, runId, scorer, { atLeast, atMost, reference })`
|
|
954
|
-
runs one declared scorer against the run the scenario just triggered and fails
|
|
955
|
-
with the reason the judge gave. The default bound is `atLeast: 0.5`, so an
|
|
956
|
-
unqualified assertion still fails a run graded zero.
|
|
957
|
-
|
|
958
|
-
Grading goes over the new `pikkuScenarioGradeRun` instrumentation RPC, which the
|
|
959
|
-
dev server registers alongside the coverage and stub RPCs — so it exists only in
|
|
960
|
-
processes that should have it, and never in a deployed bundle. It grades from
|
|
961
|
-
the snapshot the runtime already took when the run finished, which is what makes
|
|
962
|
-
a scenario's grade the same measurement production's sampler makes rather than
|
|
963
|
-
an approximation of it: a run's prompt, answer and tool calls are spread across
|
|
964
|
-
a thread's messages, where the boundary of one run is not recoverable.
|
|
965
|
-
|
|
966
|
-
Two things differ deliberately from live scoring. The sample rate is ignored — a
|
|
967
|
-
scorer grading 1% of traffic still grades every scenario run — and the grade is
|
|
968
|
-
returned rather than recorded, so a test's score never lands among the
|
|
969
|
-
production figures. `reference` supplies the answer key a `requiresReference`
|
|
970
|
-
judge grades against, which is the only way such a judge is reachable at all.
|
|
971
|
-
|
|
972
|
-
- 2f15aad: `pikku workspace validate` is now `pikku validate`, and it checks addon packaging
|
|
973
|
-
|
|
974
|
-
The command no longer needs to be told what kind of project it is looking at.
|
|
975
|
-
Each check declares the condition under which it means anything and runs
|
|
976
|
-
wherever that condition holds, so a repo that is an app, a pile of publishable
|
|
977
|
-
addons, or both gets exactly the checks that apply — and a run that found
|
|
978
|
-
nothing to check says so instead of printing a tick.
|
|
979
|
-
|
|
980
|
-
The new checks are for addons, and both state the same property at a different
|
|
981
|
-
level: every relative import in a shipped generated file, and every `exports` or
|
|
982
|
-
`imports` target, must resolve to a file the package actually publishes.
|
|
983
|
-
|
|
984
|
-
That property was false in every published `@pikku/addon-*`. They shipped
|
|
985
|
-
`dist/.pikku` without the `types/application-types.d.ts` those files import —
|
|
986
|
-
14 typecheck errors inside `node_modules` for any app depending on one — and
|
|
987
|
-
they published a second, dead copy of `.pikku` at the root whose imports reached
|
|
988
|
-
for a `src/` and `types/` the tarball did not contain, behind the very subpath
|
|
989
|
-
consumers import their bootstrap through.
|
|
990
|
-
|
|
991
|
-
Addons now point every entry point at the built copy under `dist`; the addon's
|
|
992
|
-
own build resolves `#pikku` through tsconfig `paths`, so nothing has to reach
|
|
993
|
-
into the source tree. `pikku new-addon` scaffolds that shape, and the addon
|
|
994
|
-
skill teaches it.
|
|
995
|
-
|
|
996
|
-
## 0.12.6
|
|
997
|
-
|
|
998
|
-
### Patch Changes
|
|
999
|
-
|
|
1000
|
-
- 2ff07e0: Remove `pikku db seed`. Seeding is now a step of `pikku db reset`, which grew `--no-seed`.
|
|
1001
|
-
|
|
1002
|
-
`seed` read like something you might point at any environment. It never was. It exists
|
|
1003
|
-
for one job: put enough test data into a **dev** database that the app isn't empty on
|
|
1004
|
-
first run. Production and staging are provisioned, not seeded — accounts and their role
|
|
1005
|
-
grants come from `pikku persona sync` or a migration, and always have.
|
|
1006
|
-
|
|
1007
|
-
A standalone seed command is also what made seed files unpleasant to write. Because it
|
|
1008
|
-
could be run against a database in any state, every seed had to defend itself with
|
|
1009
|
-
`INSERT OR IGNORE`, `ON CONFLICT DO NOTHING`, `IF NOT EXISTS`. Folding it into reset
|
|
1010
|
-
removes that: `pikku db reset` wipes, migrates, then seeds, so the seed only ever meets
|
|
1011
|
-
an empty database and **plain `INSERT`s are correct**. The guarantee is structural now
|
|
1012
|
-
rather than a documented convention.
|
|
1013
|
-
|
|
1014
|
-
```bash
|
|
1015
|
-
pikku db reset # wipe + migrate + test data
|
|
1016
|
-
pikku db reset --no-seed # wipe + migrate, empty — for empty-state and onboarding work
|
|
1017
|
-
```
|
|
1018
|
-
|
|
1019
|
-
Seeding also inherits reset's guards for free: it refuses `NODE_ENV=production`, and
|
|
1020
|
-
refuses a database resolved outside the runtime directory.
|
|
1021
|
-
|
|
1022
|
-
The seed file keeps a name that says what it is:
|
|
1023
|
-
- `db/postgres-seed.sql` → `db/postgres-dev-seed.sql`
|
|
1024
|
-
- `db/sqlite-seed.sql` → `db/sqlite-dev-seed.sql`
|
|
1025
|
-
|
|
1026
|
-
**Migrating:** rename the file, and drop the idempotency guards from it if you like.
|
|
1027
|
-
`pikku db seed` no longer exists — use `pikku db reset`. A project that keeps the old
|
|
1028
|
-
filename gets no error: reset reports the database is empty, which is the one failure
|
|
1029
|
-
mode worth knowing about up front. The Fabric validator's `seed-sql-missing` finding is
|
|
1030
|
-
now `dev-seed-sql-missing` and looks for the new name.
|
|
1031
|
-
|
|
1032
|
-
- 1e74b01: Remove `pikku db seed`. Seeding is now a step of `pikku db reset`, which grew `--no-seed`.
|
|
1033
|
-
|
|
1034
|
-
`seed` read like something you might point at any environment. It never was. It exists
|
|
1035
|
-
for one job: put enough test data into a **dev** database that the app isn't empty on
|
|
1036
|
-
first run. Production and staging are provisioned, not seeded — accounts and their role
|
|
1037
|
-
grants come from `pikku persona sync` or a migration, and always have.
|
|
1038
|
-
|
|
1039
|
-
A standalone seed command is also what made seed files unpleasant to write. Because it
|
|
1040
|
-
could be run against a database in any state, every seed had to defend itself with
|
|
1041
|
-
`INSERT OR IGNORE`, `ON CONFLICT DO NOTHING`, `IF NOT EXISTS`. Folding it into reset
|
|
1042
|
-
removes that: `pikku db reset` wipes, migrates, then seeds, so the seed only ever meets
|
|
1043
|
-
an empty database and **plain `INSERT`s are correct**. The guarantee is structural now
|
|
1044
|
-
rather than a documented convention.
|
|
1045
|
-
|
|
1046
|
-
```bash
|
|
1047
|
-
pikku db reset # wipe + migrate + test data
|
|
1048
|
-
pikku db reset --no-seed # wipe + migrate, empty — for empty-state and onboarding work
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
Seeding also inherits reset's guards for free: it refuses `NODE_ENV=production`, and
|
|
1052
|
-
refuses a database resolved outside the runtime directory.
|
|
1053
|
-
|
|
1054
|
-
The seed file keeps a name that says what it is:
|
|
1055
|
-
- `db/postgres-seed.sql` → `db/postgres-dev-seed.sql`
|
|
1056
|
-
- `db/sqlite-seed.sql` → `db/sqlite-dev-seed.sql`
|
|
1057
|
-
|
|
1058
|
-
**Migrating:** rename the file, and drop the idempotency guards from it if you like.
|
|
1059
|
-
`pikku db seed` no longer exists — use `pikku db reset`. A project that keeps the old
|
|
1060
|
-
filename gets no error: reset reports the database is empty, which is the one failure
|
|
1061
|
-
mode worth knowing about up front. The Fabric validator's `seed-sql-missing` finding is
|
|
1062
|
-
now `dev-seed-sql-missing` and looks for the new name.
|
|
1063
|
-
|
|
1064
|
-
- 95f6144: Audit the twelve core skills against the shipped APIs and correct the drift.
|
|
1065
|
-
- pikku-ai-agent: `instructions` does not exist — the prompt is `role`/`personality`/`goal` (required); tools are `ref()` handles; import from `#pikku/agent/pikku-agent-types.gen.js`; invoke via `rpc.agent.*` rather than `runAIAgent(name, input, { singletonServices })`
|
|
1066
|
-
- pikku-scenario: step bodies live under `default`/`browser`/`cli` bindings, not a `func`; `scaffold.scenarios` is a boolean, not the rejected `"auth"` string
|
|
1067
|
-
- pikku-addon: there is no `addon()` helper — `ref()` covers local and addon functions
|
|
1068
|
-
- pikku-realtime: SSE is `PikkuRealtime.subscribeToTopic`; `publish`'s channelId argument excludes rather than targets
|
|
1069
|
-
- pikku-cli: factories come from `#pikku`; documents options parsing, permissions/middleware/auth and the generated websocket backend
|
|
1070
|
-
- pikku-services, pikku-config, pikku-middleware, pikku-rpc, pikku-workflow, pikku-queue, pikku-cron, pikku-websocket: corrected option names, wire objects, scopes/secrets coverage and cross-skill routing
|
|
1071
|
-
|
|
1072
|
-
- facd61f: Audit the remaining skills against the shipped APIs and correct the drift.
|
|
1073
|
-
- pikku-mcp: there is no `wireMCPTool` — a tool _is_ the function (`mcp: true` or `pikkuMCPToolFunc`), while `uri`/`title`/`name` belong on `wireMCPResource`/`wireMCPPrompt` rather than on the `pikkuMCP*Func` factories; resources return `{ uri, text }` only; `PikkuMCPServer` takes `(config, logger)`
|
|
1074
|
-
- pikku-http: `channel` is on the wire, not services; `sse` is `get`-only and `query` is `post`-only; `docs` was never a `wireHTTP` option; factories come from `#pikku`
|
|
1075
|
-
- pikku-security: documents `authBearer`'s static-token mode, `authCookie`'s merged defaults and re-issue rule, and that every strategy is a no-op without an HTTP request or with a session already set
|
|
1076
|
-
- pikku-better-auth: the `admin:users:*` scope tree gained create/ban/remove/sessions/password, and `syncProjectedAdminRole` projects them onto `user.role` for better-auth's own `admin()` endpoints; documents dev quick login
|
|
1077
|
-
- pikku-react / pikku-react-query / pikku-workflows-client: `createPikku` options are flat `CorePikkuFetchOptions` with `authHeaders` and the `setAuthorizationJWT`/`setAPIKey`/`setHeader` setters (no request interceptor); `useWorkflowStatus` never stops polling on its own
|
|
1078
|
-
- pikku-trigger: a source function runs once at startup with singleton services only; documents `InMemoryTriggerService` startup and the skipped-metadata warning
|
|
1079
|
-
- pikku-schedule: the singleton is `schedulerService` and `start()` is what registers the cron jobs; documents `scheduleRPC` and the one-off task API
|
|
1080
|
-
- pikku-ws: there is no `PikkuWSServer` — `pikkuWebsocketHandler({ server, wss, logger })` over a `noServer: true` `WebSocketServer` is the real API
|
|
1081
|
-
- pikku-info: there are only four subcommands, and `--silent` works despite the spurious "Unknown option" warning
|
|
1082
|
-
- pikku-versioning: `override` is not required — a matching `V<n>` export suffix is stripped automatically — and the live function must be bumped explicitly; `versions init` writes an empty manifest, so `versions update` has to follow it
|
|
1083
|
-
- pikku-audit: documents `audit: { durability }`, the `Safe<>` guard on `auditLog.write`, `createInvocationAudit`'s logger argument, and `createAuditedKysely`'s options
|
|
1084
|
-
- pikku-kysely: six packages, not four — `@pikku/kysely-node-sqlite` / `-bun-sqlite` build the instance functions query, while `createSQLiteKysely` is typed to `KyselyPikkuDB` and wires `SerializePlugin`; the secret service config is `{ key, keyVersion, previousKey, audit }`, not `{ kekSecret, salt }`, and `getSecret` returns a `SecretValue`
|
|
1085
|
-
- pikku-emails: template variables are always optional and never required-able; unresolved placeholders render blank rather than failing; documents `pikku emails init`
|
|
1086
|
-
- pikku-rtl: rewritten off i18next — there is no `t()` or `i18n.changeLanguage` anywhere in the repo; Arabic is a `messages/ar.json` listed in `project.inlang/settings.json`
|
|
1087
|
-
- pikku-i18n: enum labels use the singular `enum__<group>__<member>` namespace `@pikku/paraglide` generates from, not hand-written `enums__` maps; notes the console's wrapped `m` as a leftover rather than a pattern, and that the `mKey`/`mList` runtime resolvers have been removed for good
|
|
1088
|
-
- pikku-deps: the summary has `totalIssues`/`totalUpdates` and no `info` bucket, issue `url`/`cvssScore`/`recommendedVersion` are nullable rather than optional, lockfile detection covers pnpm and npm too, and a non-zero `bun audit` exit only counts as data when it produced output
|
|
1089
|
-
- pikku-feature: stage changed files by path — `git add -A` sweeps up regenerated artifacts and, on a shared checkout, another agent's work
|
|
1090
|
-
- pikku-jose: `decode` verifies the signature and expiry (it is not an unchecked read), keys resolve by the token's `kid` rather than being tried in turn, and the algorithm is fixed HS256
|
|
1091
|
-
- pikku-machine-auth: documents restricting a key below its owner via `scopes` on the mapped session, the deliberate verify-vs-scope failure split, and that `betterAuthStatelessSession` has no api-key path
|
|
1092
|
-
- pikku-redis / pikku-mongodb: the secret-service config is `{ key, keyVersion, previousKey, … }`, not the fabricated `{ kekSecret, salt }`; both packages also ship a `SessionStore`
|
|
1093
|
-
- pikku-pino: log methods take trailing meta varargs and are `Safe<>`-guarded against secrets; `debug` takes a string only
|
|
1094
|
-
- pikku-aws / pikku-backblaze: every `ContentService` method takes an args object with a logical `bucket` stored as a path prefix, not positional arguments; `S3ContentConfig` is `{ bucketName, region, endpoint }` and `B2ContentConfig` has no `cdnUrl`; documents `signURL` failing open, the fixed 3600s presign, SQS's 900s delay ceiling and throwing `getJob`, and that `AWSSecrets.getSecret` returns a `SecretValue` and reports every failure as the same fatal error
|
|
1095
|
-
- pikku-gateway-slack: `SlackGatewayAdapter` takes `{ signingSecret, tokenResolver }` — there is no `botToken`, one adapter serves every workspace; `verifySlackSignature` is `(secret, signature, timestamp, body)` and returns a boolean; `parseSlashCommand` returns camelCase fields with the raw payload on `raw`; the generic `send()` is a no-op, so replies must go through `createBoundSend`/`SlackGatewayHelper`
|
|
1096
|
-
- pikku-ai-vercel: model strings are `provider/model`, not `provider:model`; documents the `'*'` catch-all, `withApiKey`, the transcribe/speech/image/embed methods, and that the service key must be `aiAgentRunner`
|
|
1097
|
-
- pikku-ai-voice: rewritten — `@pikku/ai-voice` is a deprecated empty package with no `STTService`/`TTSService`; `voiceInput`/`voiceOutput` come from `@pikku/core/ai-agent` and attach via `aiMiddleware`, with per-script voices, `NoSpeechDetectedError`, and speak-only-when-spoken-to
|
|
1098
|
-
- both above: there is no `wireAIAgent` — agents are declared with `pikkuAIAgent` from the generated agent types
|
|
1099
|
-
- pikku-schema-ajv / pikku-schema-cfworker: the two validators are not drop-in equivalents — AJV caches by name forever and fills defaults in place, cfworker recompiles on a changed schema and applies no defaults; a missing schema throws a bare string rather than an `Error`
|
|
1100
|
-
- pikku-n8n-import: the output directory is `--out/-o`, not a positional argument, and `pikku import n8n` already accepts a directory and flattens array/`{workflows:[]}` exports — an un-importable workflow is skipped while the rest of a batch still imports
|
|
1101
|
-
- pikku-template-clone: `create-pikku` keeps only the chosen package manager's lockfile and may have written an empty `yarn.lock`, so commit it after the first install rather than as scaffolded
|
|
1102
|
-
- pikku-fabric: the wirings file comment claimed a `wireMCPTool` that has never existed, and the conversion checklist named `fabric.config.json` with a `production.branch` — the real file is `pikkufabric.config.json` with `production.domain`; notes that several CLI messages print the shorter name anyway
|
|
1103
|
-
- pikku-fabric-debug: `metrics` also requires `--branch`, and `--follow`'s own help text advertises SSE for what is a 2-second client poll
|
|
1104
|
-
- pikku-deploy-express: documents `getHttpServer`/`enableReaper`, that the health check is registered in the constructor (before any middleware, so it cannot be wrapped in auth), what `init()` installs and in what order, and that Express buffers the body so the parser limit is the only place `maxBodySize` can stop an oversized request
|
|
1105
|
-
- pikku-deploy-fastify: `enableCors` throws `Method not implemented.`; the health check lives in `init()`, not the constructor; the plugin registers a catch-all `fastify.all('/*')` and only sets `bodyLimit` when `maxBodySize` is supplied, so Fastify's stricter 1MB default otherwise stands
|
|
1106
|
-
- pikku-deploy-uws: `PikkuUWSServer` has no `enableCors`, static assets or `content`; `init()` registers the health check plus catch-all HTTP and websocket handlers, `httpOptions` never reaches the websocket one and `loadSchemas` is never passed; `stop()` throws a bare string and waits a fixed 2s; documents the byte-counting `maxBodySize` 413 and why `@pikku/ws` needs `noServer: true`
|
|
1107
|
-
- pikku-deploy-lambda: `runFetch` is payload v1 and `runFetchV2` v2 — only v2 echoes an origin or returns a 500; scheduled handlers should use `runLambdaScheduled`, which runs every task in the bundle and swallows per-task failures; the SQS worker's `batchItemFailures` needs `ReportBatchItemFailures` to mean anything; websocket handlers return a real `APIGatewayProxyResult` that must not be replaced with a hardcoded 200; documents the handler factories, `SQS_QUEUE_URL_*` resolution and the binary-unsupported/stale-connection eventhub behaviour
|
|
1108
|
-
- pikku-deploy-cloudflare: the hand-rolled `setup-services.ts` never called `setSingletonServices`, so every request would have thrown a CF 1101 — use the exported `setupServices(env, factories)` and the handler factories; documents `runFetch`'s 426 upgrade path, `cf-ray` traceId and `exposeErrors: false` default, that `runScheduled` stops after the first cron match, and the `WEBSOCKET_HIBERNATION_SERVER` binding plus the 1008/403 connect-denial path
|
|
1109
|
-
- pikku-deploy-nextjs: `pikkuAPIRequest` strips a leading `/api` (toggle with `removeAPIPrefix`) and passes no wiring options; the helper set includes `patch` and has no `staticPatch`/`staticDel`; the static variants differ by `skipUserSession`, not just where they run, and both bubble errors; documents `PikkuNextJSWorkerRPC` and `toNextJsAuthHandler`
|
|
1110
|
-
- pikku-deploy-azure: the exports are `AzInvocationLogger` and `PikkuAZTimerRequest` — `PikkuAzFunctionsLogger` never existed; real deployments go through `createAzureHandler(factories, handlerTypes)` returning `{ http, queue, timer }`; `createAzureWebSocketHandler` is a 501 stub; documents the text-flattened HTTP response, `AZURE_QUEUE_NAME_*` resolution, the 7-day visibility cap, the timer running every task without per-task error handling, and `setLevel` being a no-op
|
|
1111
|
-
- pikku-product-second-opinion: stop asserting a fixed TanStack Start release stage — `@tanstack/react-start`'s major tracks the Router line, so the version says nothing about maturity; check the vendor at write-up time
|
|
1112
|
-
|
|
1113
|
-
- 2f72189: Point the `versions check` hints at a command that exists.
|
|
1114
|
-
|
|
1115
|
-
Three different failures told you to run `npx pikku versions-update`. There is
|
|
1116
|
-
no such command — `update` is a subcommand of `versions` — so anyone following
|
|
1117
|
-
the hint hit "unknown command" at the moment they were trying to repair a
|
|
1118
|
-
contract manifest. It now prints `npx pikku versions update`.
|
|
1119
|
-
|
|
1120
|
-
The pikku-versioning skill carried a paragraph warning agents the hint was
|
|
1121
|
-
wrong; with the hint fixed, that warning is gone.
|
|
1122
|
-
|
|
1123
|
-
- 7b0da5e: Point `versions check` at a command that exists.
|
|
1124
|
-
|
|
1125
|
-
Three of its diagnostics told you to run `npx pikku versions-update`. There is
|
|
1126
|
-
no such command — `update` is a subcommand of `versions`, so following the hint
|
|
1127
|
-
gets an unknown-command error at the exact moment you have a failing check to
|
|
1128
|
-
clear. They now print `npx pikku versions update`.
|
|
1129
|
-
|
|
1130
|
-
The pikku-versioning skill carried a paragraph warning agents off the bad hint.
|
|
1131
|
-
With the hint corrected the warning is the only thing left naming a command that
|
|
1132
|
-
does not exist, so it goes too.
|
|
1133
|
-
|
|
1134
|
-
## 0.12.5
|
|
1135
|
-
|
|
1136
|
-
### Patch Changes
|
|
1137
|
-
|
|
1138
|
-
- fd72e58: Drop `scenario.step` — a scenario step is now always a `given`, `when` or
|
|
1139
|
-
`then`.
|
|
1140
|
-
|
|
1141
|
-
`step` rendered no keyword, which made it the phase to reach for whenever a
|
|
1142
|
-
step did not obviously fit one of the three. That is exactly the step a reader
|
|
1143
|
-
cannot check: a scenario is read by people deciding whether it describes the
|
|
1144
|
-
behaviour they wanted, and a row that says what it does without saying whether
|
|
1145
|
-
it is setup, action or claim tells them nothing to agree or disagree with. It
|
|
1146
|
-
was also the escape hatch from the assertion lint — a scenario with no `then`
|
|
1147
|
-
could be made to stop complaining by demoting its steps rather than by
|
|
1148
|
-
asserting anything.
|
|
1149
|
-
|
|
1150
|
-
Replace `scenario.step(...)` with whichever of `given`, `when` or `then` the
|
|
1151
|
-
step actually is. `then` is not a rename: it makes the step's bindings
|
|
1152
|
-
witnesses rather than alternatives, so every declared surface runs and they
|
|
1153
|
-
must agree.
|
|
1154
|
-
|
|
1155
|
-
- 75e81b1: Document `pikkuServerLifecycle` in the skills corpus. `pikku-concepts` now presents both bootstrap paths (letting `pikku dev`/`pikku serve` own the server vs. embedding in your own runtime) instead of only the hand-rolled entrypoint, `pikku-services` gains a `pikkuServerLifecycle` reference covering hook ordering, discovery rules and the `afterStop`-runs-after-services-stop caveat, and `pikku-config` documents the `lint` severity map including `customServerBootstrap`.
|
|
1156
|
-
|
|
1157
|
-
## 0.12.4
|
|
1158
|
-
|
|
1159
|
-
### Patch Changes
|
|
1160
|
-
|
|
1161
|
-
- 8075f6a: Confine `SecretService` to the places an app is wired.
|
|
1162
|
-
|
|
1163
|
-
`secrets` is now omitted from the services every function, AI agent, workflow,
|
|
1164
|
-
permission and wire receives, and the function runner replaces it with a
|
|
1165
|
-
throwing accessor so a cast cannot reach past the type. It stays available in
|
|
1166
|
-
`pikkuServices`, `pikkuWireServices`, addon service factories and middleware —
|
|
1167
|
-
read a secret there, give it to a service, and have the function ask that
|
|
1168
|
-
service.
|
|
1169
|
-
|
|
1170
|
-
Alongside it:
|
|
1171
|
-
- `wireSecret` gains `allowedHosts`, refusing a secret attached to a host it was
|
|
1172
|
-
not declared for. Permissive by default; strict via
|
|
1173
|
-
`config.secrets.requireAllowedHosts`.
|
|
1174
|
-
- `pikku-graph`'s `httpRequest` resolves and attaches its credential inside a new
|
|
1175
|
-
`httpRequester` service instead of holding the plaintext in the function.
|
|
1176
|
-
- New inspector diagnostics: `PKU950` (a `SecretService` exposed under another
|
|
1177
|
-
service name), `PKU951` (a secret read that no `wireSecret` declares) and
|
|
1178
|
-
`PKU952` (a secret read with a non-literal key).
|
|
1179
|
-
|
|
1180
|
-
## 0.12.3
|
|
1181
|
-
|
|
1182
|
-
### Patch Changes
|
|
1183
|
-
|
|
1184
|
-
- a7b26c5: rename the inspected declarations to `define*`: `wireScope` → `defineScope`, `wireSecret` → `defineSecret`, `wireVariable` → `defineVariable`, `wireCredential` → `defineCredential`
|
|
1185
|
-
|
|
1186
|
-
`wire*` meant two unrelated things. A transport wiring attaches a function to
|
|
1187
|
-
something that can invoke it — `wireHTTP`, `wireChannel`, `wireScheduler`,
|
|
1188
|
-
`wireQueueWorker` and the rest — and the thing it wires runs. These four wire
|
|
1189
|
-
nothing: they are no-ops that exist only so the call typechecks, they are
|
|
1190
|
-
tree-shaken out of the build, and their whole job is to be found by the
|
|
1191
|
-
inspector's AST pass and turned into a type union. One word for both left the
|
|
1192
|
-
declaration reading like a registration with a runtime.
|
|
1193
|
-
|
|
1194
|
-
So the vocabulary splits: **`wire*` is a transport, `define*` is an inspected
|
|
1195
|
-
declaration.**
|
|
1196
|
-
|
|
1197
|
-
```ts
|
|
1198
|
-
import { defineScope } from '@pikku/core/scope'
|
|
1199
|
-
import { defineSecret } from '@pikku/core/secret'
|
|
1200
|
-
import { defineVariable } from '@pikku/core/variable'
|
|
1201
|
-
import { defineCredential } from '@pikku/core/credential'
|
|
1202
|
-
|
|
1203
|
-
defineScope({ admin: { scopes: { invoices: { scopes: { create: {} } } } } })
|
|
1204
|
-
```
|
|
1205
|
-
|
|
1206
|
-
**Breaking:** no alias is kept. Rename the four call sites; the module subpaths
|
|
1207
|
-
(`@pikku/core/scope`, `/secret`, `/variable`) are unchanged.
|
|
1208
|
-
|
|
1209
|
-
The inspector matches these by identifier text, so a stale `wire*` call is not a
|
|
1210
|
-
type error — it is silently not extracted, and the generated union comes back
|
|
1211
|
-
empty. That fails as "this scope isn't declared" on code that was fine a moment
|
|
1212
|
-
ago, nowhere near the declaration. Grep for the old names rather than trusting a
|
|
1213
|
-
clean build.
|
|
1214
|
-
|
|
1215
|
-
An addon published with `.pikku` output generated before this release re-exports
|
|
1216
|
-
`wireSecret` from `@pikku/core/secret` and will not typecheck against this core
|
|
1217
|
-
until it is rebuilt and republished.
|
|
1218
|
-
|
|
1219
|
-
- 457cb25: Add `definePersonas()`: the people a project's scenarios and virtual users run
|
|
1220
|
-
as, declared in code.
|
|
1221
|
-
|
|
1222
|
-
There used to be three names for two-and-a-bit things — an _actor_ in
|
|
1223
|
-
`scenarios.actors`, a _persona_ in `scenarios.personas`, and a _virtual user_
|
|
1224
|
-
declared separately against an actor. In practice almost every actor was its own
|
|
1225
|
-
kind, so the second set carried no information and the third was a third place
|
|
1226
|
-
for a name to drift. There is now one declaration:
|
|
1227
|
-
|
|
1228
|
-
```ts
|
|
1229
|
-
definePersonas({
|
|
1230
|
-
shopper: {
|
|
1231
|
-
name: 'Sam Shopper',
|
|
1232
|
-
jobTitle: 'Shopper',
|
|
1233
|
-
personality: 'Buys in a hurry and leaves tabs open',
|
|
1234
|
-
roles: ['customer'],
|
|
1235
|
-
disposition: 'careless',
|
|
1236
|
-
goals: ['Buy something without reading anything'],
|
|
1237
|
-
account: {},
|
|
1238
|
-
},
|
|
1239
|
-
})
|
|
1240
|
-
```
|
|
1241
|
-
|
|
1242
|
-
A persona is a person: what they are like, what they want, the roles they hold,
|
|
1243
|
-
and **one** account they sign in with — `account: {}` plus `linkedAccounts` for
|
|
1244
|
-
the rare case of more, modelled on how better-auth does linking. A persona with a
|
|
1245
|
-
`disposition` is a virtual user; `runnable: false` marks someone who only ever
|
|
1246
|
-
exists to be acted upon — banned, shared with, reset — and is never handed a
|
|
1247
|
-
session.
|
|
1248
|
-
|
|
1249
|
-
**A persona names roles, never scopes.** Scopes come from `defineSystemRole()`
|
|
1250
|
-
expansion, so the build fails if a persona names a role nobody declared, and
|
|
1251
|
-
fails again if a role confers a scope no `defineScope` declares. Running one only
|
|
1252
|
-
ever has to check that its roles are still valid.
|
|
1253
|
-
|
|
1254
|
-
**Addresses are computed, never declared.** `personaEmail(id, domain, runId)`
|
|
1255
|
-
derives `<id>[+runId]@<domain>` from `scenarios.emailDomain`, so a seed, a
|
|
1256
|
-
scenario run and a virtual-user run cannot disagree about who they are signing in
|
|
1257
|
-
as. `scenarios.actors` and `scenarios.personas` are gone from
|
|
1258
|
-
`pikku.config.json` — only `emailDomain` remains.
|
|
1259
|
-
|
|
1260
|
-
`actor` survives in exactly one place: the name of a **slot in a scenario step**,
|
|
1261
|
-
which is the role a persona is cast in for that step. `pikkuVirtualUser()`,
|
|
1262
|
-
`kind`, `grants` and the `actor` field are removed; the `actors` service is now
|
|
1263
|
-
`personas`, and the CLI's `virtual-user` commands are now `pikku persona list` /
|
|
1264
|
-
`pikku persona run`. `budget` and `allowApprovalRequired` moved to run flags —
|
|
1265
|
-
how much you will spend today is not a fact about a person.
|
|
1266
|
-
|
|
1267
|
-
`@pikku/cucumber` drops its `Actor` class and `ActorDispatchContext`: a
|
|
1268
|
-
hand-rolled cookie jar that a persona's own typed session replaces outright.
|
|
1269
|
-
|
|
1270
|
-
- 86a50b9: scenario: replace `browser: true` + `func` with per-surface bindings on `pikkuScenarioStep`
|
|
1271
|
-
|
|
1272
|
-
A step now declares one implementation per surface it can be driven through:
|
|
1273
|
-
|
|
1274
|
-
```ts
|
|
1275
|
-
export const buysTheItem = pikkuScenarioStep<{ sku: string }, { orderId: string }>({
|
|
1276
|
-
name: 'buysTheItem',
|
|
1277
|
-
description: 'buys the item',
|
|
1278
|
-
browser: async (services, data, { browser }) => { ... },
|
|
1279
|
-
default: async (services, data, { rpc }) => { ... },
|
|
1280
|
-
})
|
|
1281
|
-
```
|
|
1282
|
-
|
|
1283
|
-
`pikku scenario run --run browser|cli|default` picks which surface the run drives,
|
|
1284
|
-
and the two phases resolve bindings differently:
|
|
1285
|
-
- **Actions** (`given` / `when` / `step`) run exactly one binding — the run
|
|
1286
|
-
surface if it has one, otherwise `default`. A step with neither now fails with
|
|
1287
|
-
`ScenarioNoSurfaceBinding` instead of silently running server-side.
|
|
1288
|
-
- **Assertions** (`then`) are witnesses, not alternatives: every declared binding
|
|
1289
|
-
runs and they must agree. Two surfaces reporting different things fails the run
|
|
1290
|
-
with `ScenarioWitnessDisagreement` rather than reporting a pass. An assertion
|
|
1291
|
-
with no witness the run can execute at all fails with `ScenarioNoWitness` —
|
|
1292
|
-
without it the step returns `undefined` and renders as a tick, reporting a pass
|
|
1293
|
-
for something nobody checked.
|
|
1294
|
-
|
|
1295
|
-
A scenario written as a step ladder that never calls `then` is now a **PKU680**
|
|
1296
|
-
critical. It proves only that nothing threw, so an assertion-free ladder of
|
|
1297
|
-
browser-bound actions would score perfect coverage while checking nothing.
|
|
1298
|
-
|
|
1299
|
-
The report gains a surface-coverage line — `n/m steps ran on browser`, counted
|
|
1300
|
-
over every step, so an action that fell back to the server lowers the ratio
|
|
1301
|
-
rather than needing a footnote. That also makes surfaces comparable over one
|
|
1302
|
-
denominator: a scenario is `4/4` on a default run and `3/4` on a browser one.
|
|
1303
|
-
Assertions that fell back are named separately and gate `--strict`, since a
|
|
1304
|
-
sentence claiming the actor saw something nobody looked at is a different problem
|
|
1305
|
-
from an action taking a shortcut.
|
|
1306
|
-
|
|
1307
|
-
**Breaking:** `browser: true` and the third `B extends boolean` type argument are
|
|
1308
|
-
gone. Rename `func` to `default` (or to `browser` where the step drove a browser)
|
|
1309
|
-
and drop the type argument.
|
|
1310
|
-
|
|
1311
|
-
## 0.12.2
|
|
1312
|
-
|
|
1313
|
-
### Patch Changes
|
|
1314
|
-
|
|
1315
|
-
- b89d3b3: Bring the knowledge base into OSS: a package, a CLI gate, a console browser and a skill
|
|
1316
|
-
|
|
1317
|
-
`knowledge/` is where a project records the things `pikku meta` cannot tell you —
|
|
1318
|
-
what a slice is for, which rule was chosen and what it rules out, what is still an
|
|
1319
|
-
open question. Tables, routes, schemas and permissions are generated, so a note
|
|
1320
|
-
that repeats them is a copy that will drift, and the profile refuses the sections
|
|
1321
|
-
where that happens.
|
|
1322
|
-
- **`@pikku/knowledge`** (new) reads the notes, builds the link graph in both
|
|
1323
|
-
directions, and validates the app-project profile: every note typed, every
|
|
1324
|
-
section indexed, every slice carrying a third-person gherkin scenario and at
|
|
1325
|
-
most three entities, and every `resource:` URI resolving against the generated
|
|
1326
|
-
meta. The resource check fails closed on drift and open on ignorance — a prefix
|
|
1327
|
-
whose meta is absent is skipped rather than called dangling.
|
|
1328
|
-
- **`pikku knowledge validate`** and **`pikku knowledge index`** replace the dead
|
|
1329
|
-
three-flat-files check. Both exit non-zero on an inconsistent base, so a
|
|
1330
|
-
pipeline can stop on one; `index` refreshes each `index.md` listing while
|
|
1331
|
-
leaving the prose around it alone, and now gives a section that holds only
|
|
1332
|
-
sub-sections an index of its own instead of leaving it unreachable.
|
|
1333
|
-
- **The console** gains a read-only Knowledge page: notes grouped by section,
|
|
1334
|
-
a rendered document with its tags, resources, links in both directions and the
|
|
1335
|
-
findings against it, and intra-bundle markdown links that open the linked note
|
|
1336
|
-
instead of leaving the page. Read-only by design — a note is edited in the repo,
|
|
1337
|
-
in the same commit as the code it describes.
|
|
1338
|
-
- **The `pikku-knowledge` skill** documents the format for agents, and Fabric
|
|
1339
|
-
builds on it rather than restating it.
|
|
1340
|
-
- **`@pikku/inspector`**: a zod schema imported from a built workspace package
|
|
1341
|
-
resolved to that package's `.d.ts`, which has no runtime exports at all, so
|
|
1342
|
-
every schema in it was reported missing. The emitted JS beside it is imported
|
|
1343
|
-
instead.
|
|
1344
|
-
|
|
1345
|
-
- e14c530: Drop OpenCode-specific discovery guidance from the bundled skills
|
|
1346
|
-
|
|
1347
|
-
Step 1 of the execution checklist in 43 skills opened with "Prefer OpenCode
|
|
1348
|
-
tools such as `pikku-meta` when available; otherwise run the relevant
|
|
1349
|
-
`pikku meta ... --json` command". The skills ship to every agent that reads
|
|
1350
|
-
them, most of which have no such tools, so the preferred branch was dead
|
|
1351
|
-
advice that an agent had to reason past before reaching the instruction that
|
|
1352
|
-
actually applies.
|
|
1353
|
-
|
|
1354
|
-
The step now just says to run `pikku meta ... --json`. The README still notes
|
|
1355
|
-
that the frontmatter shape is the one Claude Code, opencode and pi.dev all
|
|
1356
|
-
parse — that is a compatibility fact about the format, not a routing hint.
|
|
1357
|
-
|
|
1358
|
-
## 0.12.1
|
|
1359
|
-
|
|
1360
|
-
### Patch Changes
|
|
1361
|
-
|
|
1362
|
-
- 637e668: Move the bundled agent skills out of `@pikku/cli` into a new MIT-licensed `@pikku/skills` package.
|
|
1363
|
-
|
|
1364
|
-
The skills are the open core — the instruction set any harness reads to build, wire and deploy a Pikku project — but they shipped inside `@pikku/cli`, whose `files` array carried `skills/` under BUSL-1.1 with no carve-out. Their terms now stand on their own package and no longer depend on the CLI that installs them.
|
|
1365
|
-
|
|
1366
|
-
This also fixes `pikku skills install` on the native binaries. `bun build --compile` only bundles the JS import graph, so 81 markdown files reached through `readdir` never made it in: every Homebrew install failed with `Could not locate bundled skills directory`, while npm installs worked. `@pikku/skills` ships both the `skills/` directory and an embedded path → contents manifest, and reads prefer the directory when one exists — so skill edits stay live in development, and the binary falls back to the manifest it now carries.
|
|
1367
|
-
|
|
1368
|
-
No skill content changed, and `pikku skills install` takes the same flags.
|