@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/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/skills",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.32",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/pikkujs/pikku.git",
|
|
7
|
+
"directory": "packages/skills"
|
|
8
|
+
},
|
|
4
9
|
"description": "The Pikku agent skills — the instruction set coding agents read to build, wire and deploy Pikku projects",
|
|
5
10
|
"author": "yasser.fadl@gmail.com",
|
|
6
11
|
"license": "MIT",
|
|
@@ -10,13 +15,13 @@
|
|
|
10
15
|
"type": "module",
|
|
11
16
|
"scripts": {
|
|
12
17
|
"embed": "node scripts/embed.mjs",
|
|
13
|
-
"tsc": "
|
|
14
|
-
"build": "
|
|
18
|
+
"tsc": "bun run embed && tsc",
|
|
19
|
+
"build": "bun run embed && tsc -b",
|
|
15
20
|
"ncu": "npx npm-check-updates",
|
|
16
21
|
"test": "bash run-tests.sh",
|
|
17
22
|
"test:watch": "bash run-tests.sh --watch",
|
|
18
23
|
"test:coverage": "bash run-tests.sh --coverage",
|
|
19
|
-
"prepublishOnly": "
|
|
24
|
+
"prepublishOnly": "bun run build"
|
|
20
25
|
},
|
|
21
26
|
"exports": {
|
|
22
27
|
".": "./dist/index.js"
|
|
@@ -27,10 +32,9 @@
|
|
|
27
32
|
],
|
|
28
33
|
"devDependencies": {
|
|
29
34
|
"@types/node": "^24.13.3",
|
|
30
|
-
"typescript": "^6.0.3",
|
|
31
35
|
"yaml": "^2.9.0"
|
|
32
36
|
},
|
|
33
37
|
"engines": {
|
|
34
38
|
"node": ">=24"
|
|
35
39
|
}
|
|
36
|
-
}
|
|
40
|
+
}
|
|
@@ -324,6 +324,11 @@ wireAddon({ name: 'todos', package: '@my-org/addon-todos' })
|
|
|
324
324
|
|
|
325
325
|
After registration, run `yarn pikku all` to generate types for the addon's functions.
|
|
326
326
|
|
|
327
|
+
Give each addon its own wiring file. A deployment unit imports a `wireAddon`
|
|
328
|
+
file only while at least one addon that file wires survives the unit's filter,
|
|
329
|
+
so wiring two addons from one file means a unit needing either one registers
|
|
330
|
+
both and bundles both packages' dependencies.
|
|
331
|
+
|
|
327
332
|
If the addon ships tables, `pikku db generate` then writes one migration per
|
|
328
333
|
addon — named after the package, carrying the addon's own SQL — after Better
|
|
329
334
|
Auth's and the runtime's, so an addon table may reference `user` or a runtime
|
|
@@ -23,6 +23,85 @@ how a worker deploy fails at runtime instead of at build.
|
|
|
23
23
|
Always run `plan` before `apply`, and read it. It names what will be created,
|
|
24
24
|
updated and deleted — the deletions are the reason to look.
|
|
25
25
|
|
|
26
|
+
### How many workers you get
|
|
27
|
+
|
|
28
|
+
By default a unit holds every function that builds the same set of singleton
|
|
29
|
+
services. One unit per function is available too, but on a large app it means a
|
|
30
|
+
hundred workers whose bundles are mostly the same framework code repeated, and a
|
|
31
|
+
build and an upload for each. `deploy.grouping` in `pikku.config.json` sets the
|
|
32
|
+
shape:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
"deploy": {
|
|
36
|
+
"grouping": {
|
|
37
|
+
"strategy": "single",
|
|
38
|
+
"rules": [
|
|
39
|
+
{ "unit": "console", "addon": "console" },
|
|
40
|
+
{ "unit": "pdf", "tags": ["pdf"] }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`strategy` is the fallback for a function no rule matches:
|
|
47
|
+
|
|
48
|
+
| strategy | fallback |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `services` | one unit per distinct set of singleton services (the default) |
|
|
51
|
+
| `function` | one unit each |
|
|
52
|
+
| `single` | one shared unit |
|
|
53
|
+
|
|
54
|
+
Rules are ordered, first match wins, and match on `tags`, an `addon` namespace
|
|
55
|
+
or `routes` globs. A rule always beats the strategy, so under `function` a rule
|
|
56
|
+
merges and under `single` or `services` it carves out.
|
|
57
|
+
|
|
58
|
+
`services` is the default because it is the middle ground: `single` is too
|
|
59
|
+
coarse to reason about and `function` pays a cold start and a deploy step per
|
|
60
|
+
function. Functions are keyed
|
|
61
|
+
on the singleton services their bodies destructure, minus the ones every unit
|
|
62
|
+
builds anyway (`config`, `logger`, `variables`, `schema`, `secrets`, and the
|
|
63
|
+
per-request `rpc`/`mcp`/`channel`/`userSession`). Units are named for that set —
|
|
64
|
+
`svc-todo-store`, `svc-event-hub-todo-store`, `svc-base` for functions needing
|
|
65
|
+
nothing else — and each records it as `servicesKey` in the manifest. On the
|
|
66
|
+
`templates/functions` app it turns 44 units into 10.
|
|
67
|
+
|
|
68
|
+
The deploy target is part of the key, so a `server` unit is named `-server` and
|
|
69
|
+
can never merge with its serverless twin. That is what keeps `services` from
|
|
70
|
+
tripping the mixed-target refusal below: two functions can carry identical
|
|
71
|
+
services and still run in different places, because a function may name
|
|
72
|
+
`deploy: 'server'` itself without any service crossing it.
|
|
73
|
+
|
|
74
|
+
Read the shape before trusting it. The partition depends entirely on how varied
|
|
75
|
+
the app's service use is: an app where nearly every function reaches the same
|
|
76
|
+
database collapses to roughly `single` with a few carve-outs. Run `pikku deploy
|
|
77
|
+
plan` and look at the unit list; set `"strategy": "function"` if you want a unit
|
|
78
|
+
per function back.
|
|
79
|
+
|
|
80
|
+
Changing the strategy renames units, and a unit name is what a queue consumer, a
|
|
81
|
+
scheduled task and a `dependsOn` point at. The manifest rewrites all three, but
|
|
82
|
+
anything holding a unit name outside the manifest does not follow. Units dropped
|
|
83
|
+
from the manifest are not deleted by OSS `deploy()` either (pikkujs/pikku#543) —
|
|
84
|
+
fabric sweeps its dispatch namespace after each deploy, plain pikku leaves the
|
|
85
|
+
old workers in place.
|
|
86
|
+
|
|
87
|
+
`tags` matches the tags a function inherits from its wirings — `wireHTTP({ ...,
|
|
88
|
+
tags: ['pdf'] })` — as well as any on the function itself, which is where almost
|
|
89
|
+
every project writes them.
|
|
90
|
+
|
|
91
|
+
Two things that bite:
|
|
92
|
+
|
|
93
|
+
- **Grouping cannot change a deploy target.** Put a `serverlessIncompatible`
|
|
94
|
+
function in a group with serverless ones and the build fails naming both
|
|
95
|
+
sides. Give it its own rule — that refusal is the design, not a bug. To find
|
|
96
|
+
the culprit, read `deployment-manifest.json`: a unit carries `targetForcedBy`
|
|
97
|
+
naming the services that crossed it to `server`, and `groupedBy` naming the
|
|
98
|
+
rule that made it, so you can see which rule to carve the function out of.
|
|
99
|
+
- **Grouping widens secret scope.** Every function in a unit reads every secret
|
|
100
|
+
that unit is granted, so treat a merge as a security decision too.
|
|
101
|
+
|
|
102
|
+
Group by something that means something — a domain, a secret scope, a deploy
|
|
103
|
+
cadence. There is deliberately no automatic packing by bundle size.
|
|
104
|
+
|
|
26
105
|
The frontends build independently (`bun run build` at the root builds every
|
|
27
106
|
workspace). Serve each behind its own hostname, and put the API behind `/api` on
|
|
28
107
|
**all of them**, mirroring the Vite proxy from the multi-app reference: `/api/auth/*` keeps its
|
|
@@ -284,6 +284,20 @@ pikku knowledge plan defer <milestone> <item> -r "<why>"
|
|
|
284
284
|
|
|
285
285
|
`progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. Writing a plan is its own seat: read `pikku-architect`. Building against one is `pikku-build`.
|
|
286
286
|
|
|
287
|
+
### A finished milestone is a tombstone
|
|
288
|
+
|
|
289
|
+
**Once a milestone reaches `built`, its note and its plan are closed. Do not edit either.** Not to correct the wording, not to fold in what the build actually turned out to need, not to add the item everyone agrees should have been there. A finished milestone is the record of what was agreed and what was measured against it, and a record that can be revised afterwards measures nothing.
|
|
290
|
+
|
|
291
|
+
This is the rule the shape of the thing already implies. `progress` reconciles a plan against generated meta and fails when what shipped contradicts it — a check with no force at all if the losing side of the contradiction may simply be rewritten. `attempts:` brakes a note nothing can satisfy, and refunds that budget when the note's content really changes; a `built` note that keeps changing is that brake removed. Both only work while the plan stays still.
|
|
292
|
+
|
|
293
|
+
So when a `built` milestone turns out to be wrong or incomplete, **the answer is always a new note, never an edit to the old one**:
|
|
294
|
+
|
|
295
|
+
- It needed more than it said → a new milestone, which may name the old one.
|
|
296
|
+
- It was built differently than planned → that is what `progress` is for. Reconcile forward, or record a decision saying why the plan was not the right shape.
|
|
297
|
+
- It was simply wrong → a decision note that supersedes it. The wrong milestone stays where it is; a base whose history is edited cannot answer *why* anything is the way it is, which is most of what a base is for.
|
|
298
|
+
|
|
299
|
+
The exception, and it is narrow: bookkeeping the loop owns. `statusAt:` and `attempts:` are written by whatever moved the note, at any status, and are bookkeeping rather than content. Nothing else about a `built` note moves again.
|
|
300
|
+
|
|
287
301
|
## Profiles built on this one
|
|
288
302
|
|
|
289
303
|
OKF permits frontmatter fields a reader does not know, and the parser ignores them rather than failing. That is the extension point: a tool layered on Pikku can add its own sections and fields on top of everything above without forking the format.
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# Pikku Services (Dependency Injection)
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
## Before You Start
|
|
5
4
|
|
|
6
5
|
```bash
|
|
@@ -195,6 +194,13 @@ const createSingletonServices = pikkuServices(async (config) => {
|
|
|
195
194
|
})
|
|
196
195
|
```
|
|
197
196
|
|
|
197
|
+
A deployment split regenerates this manifest **per unit**, so the same
|
|
198
|
+
`services.ts` sees a different manifest in each bundle and each unit builds only
|
|
199
|
+
what its own functions, middleware and permissions reach. A `services.ts` that
|
|
200
|
+
constructs unconditionally gets none of that: every unit pays for every service,
|
|
201
|
+
and the split buys nothing but duplicated bytes. Branching on the manifest is
|
|
202
|
+
what makes the split real.
|
|
203
|
+
|
|
198
204
|
### Audit Wire Service
|
|
199
205
|
|
|
200
206
|
`createInvocationAudit` + `createAuditedKysely` add per-request audit buffering that flushes on request close (no-op if `audit` is unconfigured). For the full pattern, no-op behavior, custom-event usage, and Fabric notes, read `references/audit-wire-service.md`.
|