@kensio/skills 1.13.1 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/skills",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "Install Kensio agent skills into any agent that reads SKILL.md.",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -3,7 +3,7 @@ name: dynamodb-single-table
3
3
  description: Model data in Amazon DynamoDB as one table by default, reading the current AWS guidance before committing to a schema, writing the access patterns down before any keys exist, holding every entity type in one table, overloading generic partition and sort keys across those types, overloading and sparsifying secondary indexes, and splitting items by write rate. Use when designing or reviewing a DynamoDB schema, when a CDK stack is about to gain a second table, when an entity needs a query it has no key for, when application code fetches from two tables to assemble one response, when a Scan or a filter expression appears, when a partition runs hot or a write throttles, and when asked how to model users, orders, events or tenants in DynamoDB.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Single-table design in DynamoDB
@@ -3,7 +3,7 @@ name: github-issue-drafting
3
3
  description: Draft a GitHub issue from a short note or a rough idea, grounding every claim about the code in the repository the issue will be filed against, splitting work that is really two issues, and filing it with `gh` once the user has approved the draft. Use when turning a to-do item, a Slack message, a code TODO, a failing test or a bug report into an issue, when asked to "write up an issue for" something, to "raise", "file" or "open an issue", when asked whether something should be one issue or several, and when tidying the titles, types or labels of issues that already exist.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # GitHub issue drafting
@@ -3,7 +3,7 @@ name: isolated-testing-style
3
3
  description: Write tests that start from given/when/then, use real collaborators through simulation rather than stubs and mocks, take their isolation from randomised data rather than shared setup and teardown, and assert behaviour rather than call counts. Use when writing or reviewing tests, when a test needs a collaborator faked, when reaching for a mock, spy, `toHaveBeenCalledWith`, `beforeEach`/`afterEach` fixtures or a hardcoded expected hash, when test setup has grown tangled, and when asked "how should I test this?".
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Isolated testing style
@@ -4,7 +4,7 @@ description: Send the prose of a finished document to Pangram, a commercial AI-t
4
4
  license: Apache-2.0
5
5
  compatibility: Needs a Pangram API key and network access. Every run is billed.
6
6
  metadata:
7
- version: "1.13.1"
7
+ version: "1.14.0"
8
8
  disable-model-invocation: true
9
9
  ---
10
10
 
@@ -3,7 +3,7 @@ name: part-factory-test-data
3
3
  description: Build test data with @kensio/part-factory, keeping in the factory everything a test does not care about, passing dependencies at call time so factories stay independent, and choosing between StaticFactory, DynamicFactory, VariantFactory, MappedFactory and AsyncMappedFactory. Use when writing test fixtures or builders, when a test file is full of object literals, when a shared event, message or payload shape is being hand-written, when a required field is about to be made optional to ease test setup, and when tempted to wrap a factory in a helper function that applies overrides.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Building test data with Part Factory
@@ -3,7 +3,7 @@ name: skill-template
3
3
  description: Scaffold a new agent skill, writing the SKILL.md and its frontmatter to the Agent Skills specification, then wrapping it as a plugin in this repo with package.json, plugin.json and a marketplace entry. Use when the user asks to "add a new skill", "create a skill", "write a SKILL.md" or "start a new plugin", and when checking whether an existing skill is portable between agents.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Skill template
@@ -3,7 +3,7 @@ name: technical-prose-style
3
3
  description: Write documentation, READMEs, code comments, commit messages, release notes and PR text as plain technical prose, by removing the constructions that make unedited LLM prose tiring to read. It targets significance tails, contrastive definition, negation framing, appositive tails, colon explainers and a vocabulary that keeps renaming the same thing. Ships a script that scores prose against Django, Go, Rust and Python documentation. Use when writing or editing docs, a README, a changelog, a blog post or any prose for human readers, when asked to improve, tighten or rewrite writing, when prose "sounds like AI" or "sounds like Claude", and when reviewing documentation in a pull request.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Technical prose style
@@ -3,7 +3,7 @@ name: yulin-aws-simulation
3
3
  description: Use the @kensio/yulin in-process AWS simulator well when testing AWS code, using it directly rather than building a harness around it, driving tests, local dev and production from one synthesized CDK template, intercepting SDK clients with SimSdk, controlling simulated time, matching service errors by name, and handling properties Yulin refuses to simulate. Use when writing or reviewing tests that touch AWS, when replacing aws-sdk-client-mock or hand-rolled AWS stubs, when a CDK stack needs testing, when test setup around Yulin is growing helper classes or wrapper functions, and when Yulin refuses a template property or an SDK command.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: "1.13.1"
6
+ version: "1.14.0"
7
7
  ---
8
8
 
9
9
  # Testing with Yulin
@@ -12,9 +12,11 @@ metadata:
12
12
  network and no AWS account. Its own docs are the authority on the API. This skill covers how to use
13
13
  it well, and that lives mostly outside the API.
14
14
 
15
- Read the package docs for anything API-shaped. Start with
16
- [the README](https://github.com/KensioSoftware/yulin#readme), then `docs/sdk/` for interception and
17
- `docs/services/<name>/` for each simulated service.
15
+ Read the package docs for anything API-shaped.
16
+ [yulinsim.dev/llms.txt](https://yulinsim.dev/llms.txt) indexes every page as plain markdown, one
17
+ link per guide and one per simulated service. Drop the `llms.txt` from a link for the HTML page. The
18
+ same pages ship in the repository, as [the README](https://github.com/KensioSoftware/yulin#readme),
19
+ then `docs/sdk/` for interception and `docs/services/<name>/` for each simulated service.
18
20
 
19
21
  This skill serves the `isolated-testing-style` skill, the general argument for simulation over
20
22
  stubs.
@@ -84,8 +86,7 @@ The two options that make a wrapper unnecessary:
84
86
 
85
87
  - **`transform`** is given the parsed template and answers with the one to deploy. It runs on the
86
88
  deployment and again on every re-read. A wrapper cannot do that. Use it for what a simulation
87
- genuinely cannot resolve, such as an ARN carrying a real account, or a hosted zone ID that came
88
- from `HostedZone.fromLookup`.
89
+ genuinely cannot resolve, such as an ARN carrying a real account.
89
90
  - **`watch`** re-applies the file when it changes, updating the stack in place. This is for dev
90
91
  servers. A `cdk synth` becomes a stack update without restarting the process, and resources the
91
92
  change left alone keep what they hold.
@@ -93,11 +94,23 @@ The two options that make a wrapper unnecessary:
93
94
  ```typescript
94
95
  await simAws.cloudFormation().deployTemplateFile({
95
96
  templatePath: "cdk.out/SiteStack.template.json",
96
- transform: withoutLookedUpHostedZone,
97
+ transform: withRealAccountArnsResolved,
97
98
  watch: { onUpdated: () => srv.reload() },
98
99
  });
99
100
  ```
100
101
 
102
+ A hosted zone ID that came from `HostedZone.fromLookup` needs no transform of its own. An
103
+ `AWS::Route53::RecordSet` naming a hosted zone ID that no zone holds gets one registered under that
104
+ ID as the record is created, and its records resolve. The zone takes its name from the records that
105
+ name it. Register it yourself with `simAws.route53().registerHostedZone({ id, name })` where a test
106
+ depends on the name, such as one listing zones by name.
107
+
108
+ A failed `cdk synth` leaves the previous template in `cdk.out` where it was, and the tests carry on
109
+ running against it. An edit that leaves an unused variable behind fails `tsc` and exits non-zero,
110
+ with the error hidden behind a redirect. The test that runs next passes against the template from
111
+ before the change. Check that the synthesized JSON changed before concluding anything from a
112
+ construct change.
113
+
101
114
  ## Intercept real SDK clients, never hand-roll stubs
102
115
 
103
116
  `SimSdk` replaces the `send` method of an AWS SDK client class or instance, so real clients answer
@@ -270,6 +283,11 @@ control also needs `lambda:InvokeFunction`. The tests passed, the release went o
270
283
  Report a false pass with what production does and what the simulation did. Report a false refusal
271
284
  with the property and the template that carries it.
272
285
 
286
+ A workaround kept while the issue is open wants a comment naming that issue, and a revisit when it
287
+ closes. One test file carried a comment saying its handler could not reach simulated AWS from inside
288
+ a simulated Lambda, citing KensioSoftware/yulin#638. That held when it was written and was fixed in
289
+ 1.16.0. The comment went on shaping the design of the test for months after that.
290
+
273
291
  ## Deploy expensive context once per test file
274
292
 
275
293
  Vitest gives each test file its own worker, so module-level state is already isolated between files.
@@ -322,3 +340,74 @@ The handler still runs in process. It can close over test state and be stepped t
322
340
  debugger. The difference from calling it directly is that a missing `s3:PutObject` on the execution
323
341
  role now fails the test, at the point AWS would have failed it. A binding can target a function by
324
342
  `logicalId`, `functionName`, `arn`, `cdkPath`, or `imageRepository` for a container image function.
343
+
344
+ ### Invoke through simulated Lambda
345
+
346
+ Binding a handler proves nothing about IAM on its own. The execution role, the function's
347
+ environment and its outbound HTTP are all applied by the invocation. The test has to go through
348
+ `simAws.lambda().invoke(new InvokeCommand({ FunctionName, Payload }))` to get any of them. A test
349
+ holding the same handler reference and calling it directly runs it in the test's own scope, as the
350
+ test's own caller, with none of the three.
351
+
352
+ The difference shows up under mutation. Removing `dynamodb:GetItem` from the role's policy in the
353
+ CDK stack and re-synthesizing failed every invoked case:
354
+
355
+ ```
356
+ AccessDenied: User: arn:aws:iam::111111111111:role/UserFunctionServiceRole1B2C3D4E
357
+ is not authorized to perform: dynamodb:GetItem
358
+ ```
359
+
360
+ The cases calling the handler directly passed. A suite that stays green through that mutation was
361
+ never covering the policy.
362
+
363
+ ### Read the environment inside the handler
364
+
365
+ A bound handler gets the function's declared environment variables with nothing stubbed.
366
+ `SimProcessEnvironment` holds a run's variables in an `AsyncLocalStorage` store and resolves
367
+ `process.env` to that store for the length of the run. Concurrent runs each see their own. Its own
368
+ doc comment states the one limit:
369
+
370
+ <!-- prose-check:off -->
371
+
372
+ > The one thing this cannot reach is a read that already happened. A handler module doing
373
+ > `const TABLE = process.env.TABLE_NAME` at module scope is evaluated when the test file imports it,
374
+ > long before any run, so it captures the host value.
375
+
376
+ <!-- prose-check:on -->
377
+
378
+ So read the environment inside the handler body. Memoise there where a warm container should build
379
+ its clients once. The substituted `Date` a bound handler reads works the same way, and a time
380
+ captured at module scope is captured equally early.
381
+
382
+ Yulin ships `SimLambdaEnvironmentConflicts` to warn about this, and it warns only where the host
383
+ value and the declared value differ. A suite that stubs the right values stays quiet and never
384
+ learns. The rule stays invisible for as long as the stubs agree.
385
+
386
+ A `vi.stubEnv` around a bound handler is the sign that the handler reads too early. Moving the reads
387
+ into the handler body removed every `vi.stubEnv` from one repository.
388
+
389
+ ### What a binding buys, and what the zip path buys
390
+
391
+ Deploying without `bindings` runs the bundle `cdk synth` produced. `deployTemplateFile` publishes
392
+ the cloud assembly's assets into the staging bucket in simulated S3, and the function's modules are
393
+ evaluated as CommonJS in a vm sandbox. That sandbox hands the code its own `process.env`, its own
394
+ `Date` and its own HTTP clients, and the module-scope problem above never arises there.
395
+
396
+ Both paths authorise through the execution role. The same policy mutation fails a zip-path test
397
+ exactly as it fails a bound one. The choice between them is about what else the test needs:
398
+
399
+ - **A binding** keeps a breakpoint working and lets the handler close over test state.
400
+ - **The zip path** exercises the artefact that deploys, its imports and its bundling included.
401
+
402
+ ### Outbound HTTP is answered by the simulation
403
+
404
+ From 1.16.2, a simulated Lambda's `fetch` and its `node:http` and `node:https` are answered by the
405
+ simulation for every hostname simulated Route 53 resolves. Those requests go through the same
406
+ in-process entry point one arriving on localhost uses. A Cognito user pool domain, an HTTP API and a
407
+ load balancer are all answered without the test knowing which of them it asked. Everything else
408
+ reaches the network as it was addressed.
409
+
410
+ This is what makes an OAuth authorization code exchange testable. That exchange lives only at the
411
+ hosted `/oauth2/token` endpoint of the user pool domain and has no SDK operation behind it. A
412
+ handler that cannot reach the domain leaves the whole exchange uncovered. The same routing lets
413
+ `CognitoJwtVerifier` fetch a simulated pool's JWKS from inside a handler with no cache primed.