@pikku/skills 0.12.64 → 0.12.67

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/skills",
3
- "version": "0.12.64",
3
+ "version": "0.12.67",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -200,7 +200,10 @@ npx pikku new addon stripe --display-name Stripe --category Payments --dir addon
200
200
  ```
201
201
 
202
202
  **Handed an OpenAPI or Swagger spec?** Don't hand-write the functions —
203
- `pikku new addon <name> --openapi <spec>` generates one function per operation,
203
+ `pikku new addon <name> --openapi <spec>` generates one function per operation
204
+ (`<spec>` is a path, a URL, or a registry catalogue name such as
205
+ `amazonaws.com:applicationcostprofiler`; inside an app,
206
+ `pikku addons add <catalogue-name>` does the same and picks `--auth` for you),
204
207
  with its schemas, service and credential. Read `references/openapi.md`.
205
208
 
206
209
  This generates `package.json` (exports `.pikku/*` + `dist/`), `pikku.config.json` (`addon: true`), `tsconfig.json` (`#pikku` path mapping), `src/services.ts`, `src/functions/`, and `types/application-types.d.ts`. For the full file contents/exports you rarely hand-edit, read `references/addon-package-manifest.md`.
@@ -378,7 +381,7 @@ At runtime an unmapped alias, or the wired name called directly, throws
378
381
  ### Studio screens
379
382
 
380
383
  An addon declares the screens it adds to Pikku Studio with `definePlugin`, in
381
- `src/screens.ts` (`pikku new addon-ui <name>` scaffolds one). It replaces
384
+ `src/screens.ts` (`pikku new addon <name> --ui` scaffolds one). It replaces
382
385
  `defineScreens`, which no longer exists.
383
386
 
384
387
  ```typescript
@@ -421,18 +424,43 @@ export default definePlugin({
421
424
  addons only; Studio enforces that). `layout: 'bare'` renders without the shell.
422
425
  - Titles are message keys in the addon's `messages/{locale}.json`, found by
423
426
  convention next to its `package.json`; there is no field for them.
427
+ - `agent: 'name'` makes that agent answer in Studio's chat panel (a second tab
428
+ beside the general chat) while the screen is open. It resolves to
429
+ `agents/<name>.md` at the addon's package root: the agent's instructions,
430
+ which name the skills it follows (plain folders `skills/<name>/SKILL.md`).
431
+ `agent: 'studio:<name>'` instead picks an agent Studio ships; `pikku all` only
432
+ checks the format and looks up no file.
433
+ The file starts with frontmatter whose `title` and `description` are message
434
+ keys in `messages/en.json`. The name matches `/^[a-z][a-z0-9-]*$/`.
435
+ - `defaultChat: false` hides Studio's general Chat tab on the screen, so the
436
+ screen's `agent` is its only chat (with no `agent`, the screen has no chat).
437
+ It defaults to `true`, must be a boolean literal, and is only written to the
438
+ metadata when declared.
439
+ - `agents/` and `skills/` ship in the published package. If `package.json` has a
440
+ `files` list, it must include them (`"files": ["dist", "messages", "agents",
441
+ "skills"]`, which `pikku new addon <name> --ui` scaffolds). A root glob such as
442
+ `**/*.md` does not count, so list the folder as well. With no `files` field
443
+ nothing is checked, so make sure `.npmignore`, or `.gitignore` when there is no
444
+ `.npmignore`, does not exclude them.
445
+ - `package.json` carries a `studio` block, `{ "addon": "<name>", "ui": "./src",
446
+ "messages": "./messages/{locale}.json" }`. Studio only links (and loads the
447
+ agents and skills of) a package with `studio.addon`; it is the addon's short
448
+ name, the `<addon>` in an agent's scope `agent:<addon>:<name>`. The `--ui`
449
+ scaffold writes it with `addon` set to the addon's name.
424
450
  - `scopes` only hide the screen. The addon's functions must enforce the same
425
451
  scopes.
426
452
 
427
453
  The inspector reads every field statically, so each must be a literal.
428
454
  `pikku all` fails on:
429
455
 
430
- | Code | When |
431
- | ------ | ------------------------------------------------------------ |
432
- | PKU345 | a field is not a literal (variable, call, spread, bad value) |
433
- | PKU357 | two screens of the addon use the same path |
434
- | PKU358 | a title key is missing from `messages/en.json` |
435
- | PKU359 | `nav.badge` names no function of the addon |
456
+ | Code | When |
457
+ | ------ | ---------------------------------------------------------------------------------------------------- |
458
+ | PKU345 | a field is not a literal (variable, call, spread, bad value) |
459
+ | PKU357 | two screens of the addon use the same path |
460
+ | PKU358 | a title or agent frontmatter key is missing from `messages/en.json` |
461
+ | PKU359 | `nav.badge` names no function of the addon |
462
+ | PKU365 | `agent` is neither a name nor `studio:<name>`, or a name has no non-empty `agents/<name>.md`, or no frontmatter `title` and `description` |
463
+ | PKU366 | `package.json` `files` leaves out `agents/` while a screen names a valid (no PKU365) non-`studio:` agent, or `skills/` while the addon has a `skills/<name>/SKILL.md` |
436
464
 
437
465
  A key missing from another locale's catalog is a warning.
438
466
 
@@ -11,7 +11,8 @@
11
11
  - 6 — Check the spec against the real API
12
12
  - Then
13
13
 
14
- When you are handed an OpenAPI or Swagger spec — a file, or a URL to one — the
14
+ When you are handed an OpenAPI or Swagger spec — a file, a URL to one, or the
15
+ name of one in the registry's catalogue (`https://www.pikku.dev/openapis`) — the
15
16
  API it describes becomes an addon: one function per operation, each with its
16
17
  input and output schemas, behind one service that makes the HTTP calls. Say so
17
18
  before starting ("This is an OpenAPI spec — I'll turn it into an addon first"),
@@ -26,7 +27,23 @@ A JSON or YAML document with a top-level `openapi` key (3.x) or `swagger` key
26
27
 
27
28
  ## 1 — Look at the spec first
28
29
 
29
- `--openapi` takes a path or a URL. A spec published only to signed-in callers
30
+ `--openapi` takes a path, a URL, or a catalogue name such as
31
+ `amazonaws.com:applicationcostprofiler`. A name is anything that is neither a
32
+ URL, a path, nor a `.json`/`.yaml` file; it is looked up in the registry
33
+ (`--registry`, else `pikku.config.json`'s `registry`, else
34
+ `https://api.pikkustudio.app`) and generated from the entry's spec URL. A name
35
+ the registry does not know is refused before anything is written. On the
36
+ website the page URL is a slug (`amazonaws-com-applicationcostprofiler`); the
37
+ name to pass is the one the page's command shows, with its `.` and `:`.
38
+
39
+ For a catalogue entry inside an app, the short form is
40
+ `pikku addons add amazonaws.com:applicationcostprofiler`. It names the addon
41
+ after the entry (`amazonaws-applicationcostprofiler`) and takes `--auth` from
42
+ what the registry records: `none` for a public API, `user` for OAuth or a key
43
+ each user brings, `shared` for a key the app holds, and `user` when the registry
44
+ does not know. It prints the mode it picked; pass `--auth` to override it.
45
+
46
+ A spec published only to signed-in callers
30
47
  takes the key the way the API reads it: `--openapi-header "NAME: value"`
31
48
  (repeatable), or in the URL's query string when the API reads it there
32
49
  (Dolibarr's explorer takes `?DOLAPIKEY=`). A 401 while fetching says which.
@@ -40,7 +57,7 @@ Keep a copy in `specs/` as the record of what the addon was generated from.
40
57
  ## 2 — Generate, from the app's root
41
58
 
42
59
  ```bash
43
- bunx --bun pikku new addon <name> --openapi <path-or-url>
60
+ bunx --bun pikku new addon <name> --openapi <path-url-or-catalogue-name>
44
61
  ```
45
62
 
46
63
  One command. Inside an app it writes `packages/addon-<name>` as
@@ -71,8 +71,8 @@ CF `1101`. It also stashes the env via `setCloudflareEnv`, which
71
71
  - A `GET` with `Upgrade: websocket` is routed to the hibernation server. Without
72
72
  one passed in it answers **426**, so a channel worker that forgets the second
73
73
  argument fails every upgrade while plain HTTP keeps working.
74
- - `CF-Ray` becomes the traceId when present, so a Cloudflare trace and a Pikku
75
- trace line up without extra wiring.
74
+ - `CF-Ray` does not set the traceId: it is not a W3C trace id. Core starts a new
75
+ trace, or continues a verified mesh caller's.
76
76
  - `options.exposeErrors` defaults to **`false`** — error detail is withheld from
77
77
  responses unless you opt in.
78
78
 
@@ -92,7 +92,7 @@ export const scheduled: ScheduledHandler = async (event) => {
92
92
  ```
93
93
 
94
94
  `runLambdaScheduled` runs **every** scheduled task registered in the bundle,
95
- each with its own `cron-<uuid>` traceId, and logs rather than rethrows a task
95
+ each on its own new trace, and logs rather than rethrows a task
96
96
  failure — so one bad task cannot fail the invocation or stop the others. The
97
97
  event itself is ignored; which tasks run is decided by what the unit bundled,
98
98
  not by which EventBridge rule fired.
@@ -243,3 +243,9 @@ wireChannel({
243
243
  },
244
244
  })
245
245
  ```
246
+
247
+ ## Tracing
248
+
249
+ A channel has one trace per connection: `onConnect`, `onDisconnect`, each message and each `channel.remote` call are spans in it, read from `wire.trace`. A client's `traceparent` is ignored. A serverless channel keeps the trace in `ChannelStore`, so a custom store must return the `traceparent` it was added with.
250
+
251
+ A reverse RPC carries `traceparent`, which `createChannelRPCResponder` ignores unless you pass `trustInboundTraceparent: true`. Only pass it for a peer you have authenticated.
@@ -81,6 +81,34 @@ Options:
81
81
  }
82
82
  ```
83
83
 
84
+ ### Tracing
85
+
86
+ A job continues the trace of the function that enqueued it. Inside a function,
87
+ `queueService.add` stamps `JobOptions.traceparent` from the wire, and the worker
88
+ gets the same trace id in a new span on `wire.trace`. Pass `traceparent` yourself
89
+ only to override it.
90
+
91
+ Nothing stamps a job added from a singleton service, or from a queue service
92
+ captured at start-up. That job starts a new trace. Pass `traceparent:
93
+ rpc.traceparent` when you need to carry it through one of those.
94
+
95
+ A custom `QueueService` must carry `traceparent` and set it on `QueueJob`. A
96
+ missing or invalid one starts a new trace; it is never an error.
97
+
98
+ ### Running a job as a user
99
+
100
+ Pass `pikkuUserId` in the job options and wrap the queue service in
101
+ `SignedQueueService`. The worker then runs with `wire.pikkuUserId` and the user's
102
+ stored session, on every adapter. An unsigned or forged id is dropped and the job
103
+ runs with neither.
104
+
105
+ Never take the id from client input. If the session has gone by the time the job
106
+ runs, `wire.pikkuUserId` is still set and `wire.session` is not.
107
+
108
+ A custom `QueueService` must carry `pikkuUserId` next to the payload and set it on
109
+ `QueueJob`, leaving `job.data` as it was. Check it with
110
+ `defineQueueIdentityTransportTests` from `@pikku/core/testing`.
111
+
84
112
  ## Usage Patterns
85
113
 
86
114
  ### Basic Queue Worker
@@ -63,6 +63,12 @@ will catch a skip and report it as a failure. If your middleware distinguishes
63
63
  success from failure, let the skip pass through rather than logging it as an
64
64
  error.
65
65
 
66
+ ### Tracing
67
+
68
+ Each cron firing starts a new trace, on `wire.trace`. A delayed call fires on the
69
+ trace passed as the last argument of `scheduleRPC`: a workflow sleep passes the
70
+ run's, and nothing passes it for you elsewhere, so use `wire.rpc.traceparent`.
71
+
66
72
  ### Cron Expression Reference
67
73
 
68
74
  ```
@@ -371,6 +371,19 @@ export const userOnboarding = pikkuWorkflowGraph({
371
371
  })
372
372
  ```
373
373
 
374
+ ### Tracing
375
+
376
+ A run owns one trace, stored on `run.wire.traceparent`. It starts from the wire or
377
+ the caller's `rpc`; a start with neither, such as a trigger, gets a new trace. Every
378
+ step, retry, sleep wake-up, resume, child workflow, recovery and job a step
379
+ enqueues stays on it. Each hop is a new span whose parent is the span that started
380
+ the run. An agent's tool calls are the exception: they are not on the run's trace
381
+ yet.
382
+
383
+ ### Restarts
384
+
385
+ A run survives a crash or deploy. `pikku dev` and `pikku serve` recover it at startup and every 30s: a sleep keeps its deadline, and a step caught in flight runs again as a new attempt. A settled step never reruns. So a step can run more than once: make its side effects idempotent on `workflowStep.invocationId`, which stays the same across attempts. A step with `retries: 0` caught in flight fails instead. Any other host calls `workflowService.startRecovery()` once the queue is consuming. Set `workflow.recovery: false` to turn it off.
386
+
374
387
  ## File conventions
375
388
 
376
389
  - Place workflows in `packages/functions/src/wirings/*.workflow.ts`; export the variable so the inspector discovers it (no manual registration).