@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 +1 -1
- package/skills/dynamodb-single-table/SKILL.md +1 -1
- package/skills/github-issue-drafting/SKILL.md +1 -1
- package/skills/isolated-testing-style/SKILL.md +1 -1
- package/skills/pangram-check/SKILL.md +1 -1
- package/skills/part-factory-test-data/SKILL.md +1 -1
- package/skills/skill-template/SKILL.md +1 -1
- package/skills/technical-prose-style/SKILL.md +1 -1
- package/skills/yulin-aws-simulation/SKILL.md +96 -7
package/package.json
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
16
|
-
[
|
|
17
|
-
|
|
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
|
|
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:
|
|
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.
|