vouchington-tooling 0.1.9 → 0.3.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/README.md +45 -5
- package/dist/agent-blackboard/index.d.mts +41 -0
- package/dist/agent-blackboard/index.mjs +94 -0
- package/dist/agent-blackboard/session-id.d.mts +1 -0
- package/dist/agent-blackboard/session-id.mjs +5 -0
- package/dist/agent-blackboard/snapshot-cleanup-directory.d.mts +11 -0
- package/dist/agent-blackboard/snapshot-cleanup-directory.mjs +66 -0
- package/dist/agent-blackboard/snapshot-cleanup-key.d.mts +14 -0
- package/dist/agent-blackboard/snapshot-cleanup-key.mjs +129 -0
- package/dist/agent-blackboard/snapshot-cleanup-receipt.d.mts +6 -0
- package/dist/agent-blackboard/snapshot-cleanup-receipt.mjs +117 -0
- package/dist/agent-blackboard/snapshot-cleanup-resume.d.mts +16 -0
- package/dist/agent-blackboard/snapshot-cleanup-resume.mjs +98 -0
- package/dist/agent-blackboard/snapshot-partition-cleanup.d.mts +13 -0
- package/dist/agent-blackboard/snapshot-partition-cleanup.mjs +136 -0
- package/dist/agent-blackboard/snapshot-partition-format.d.mts +32 -0
- package/dist/agent-blackboard/snapshot-partition-format.mjs +151 -0
- package/dist/agent-blackboard/snapshot-partition-io.d.mts +4 -0
- package/dist/agent-blackboard/snapshot-partition-io.mjs +37 -0
- package/dist/agent-blackboard/snapshot-partition-read.d.mts +9 -0
- package/dist/agent-blackboard/snapshot-partition-read.mjs +70 -0
- package/dist/agent-blackboard/snapshot-partition-validate.d.mts +4 -0
- package/dist/agent-blackboard/snapshot-partition-validate.mjs +40 -0
- package/dist/agent-blackboard/snapshot-partition-write.d.mts +2 -0
- package/dist/agent-blackboard/snapshot-partition-write.mjs +91 -0
- package/dist/agent-blackboard/snapshot-partitions.d.mts +10 -0
- package/dist/agent-blackboard/snapshot-partitions.mjs +102 -0
- package/dist/agent-blackboard/snapshot-types.d.mts +67 -0
- package/dist/agent-blackboard/snapshot-types.mjs +1 -0
- package/dist/agent-blackboard/snapshot.d.mts +3 -0
- package/dist/agent-blackboard/snapshot.mjs +2 -0
- package/dist/cli/commands/agent-blackboard.d.mts +3 -0
- package/dist/cli/commands/agent-blackboard.mjs +114 -0
- package/dist/cli/commands/link-skill.d.mts +5 -0
- package/dist/cli/commands/link-skill.mjs +6 -0
- package/dist/cli/commands/retrospective-facts.d.mts +1 -0
- package/dist/cli/commands/retrospective-facts.mjs +33 -0
- package/dist/cli/index.mjs +14 -0
- package/dist/cli/parse.d.mts +12 -1
- package/dist/cli/parse.mjs +31 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +14 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +3 -0
- package/dist/retrospective-facts/exec.d.mts +3 -0
- package/dist/retrospective-facts/exec.mjs +19 -0
- package/dist/retrospective-facts/foreign.d.mts +2 -0
- package/dist/retrospective-facts/foreign.mjs +36 -0
- package/dist/retrospective-facts/format.d.mts +10 -0
- package/dist/retrospective-facts/format.mjs +64 -0
- package/dist/retrospective-facts/index.d.mts +3 -0
- package/dist/retrospective-facts/index.mjs +26 -0
- package/dist/retrospective-facts/local.d.mts +2 -0
- package/dist/retrospective-facts/local.mjs +144 -0
- package/dist/retrospective-facts/shared.d.mts +17 -0
- package/dist/retrospective-facts/shared.mjs +1 -0
- package/dist/skill-discovery/index.d.mts +12 -0
- package/dist/skill-discovery/index.mjs +64 -0
- package/dist/skill-discovery/manifest.d.mts +15 -0
- package/dist/skill-discovery/manifest.mjs +85 -0
- package/dist/skill-discovery/target-directory.d.mts +10 -0
- package/dist/skill-discovery/target-directory.mjs +126 -0
- package/package.json +26 -2
- package/scripts/build.mjs +16 -4
- package/scripts/gha/harness-admission-lane.sh +26 -0
- package/scripts/gha/harness-assert-gates.sh +24 -0
- package/skills/agent-workflow/SKILL.md +5 -0
- package/skills/agent-workflow/references/evidence-sweep.md +8 -0
- package/skills/agent-workflow/references/implementation-and-review.md +9 -0
- package/skills/agent-workflow/references/implementation.md +8 -0
- package/skills/agent-workflow/references/review.md +7 -0
- package/skills/backend-vitest-test-authoring/SKILL.md +15 -0
- package/skills/backend-vitest-test-authoring/references/integration-boundaries.md +10 -0
- package/skills/dotnet-test-authoring/SKILL.md +16 -0
- package/skills/manifest.json +158 -0
- package/skills/nextjs-vitest-test-authoring/SKILL.md +15 -0
- package/skills/nextjs-vitest-test-authoring/references/framework-boundaries.md +9 -0
- package/skills/planning/SKILL.md +3 -0
- package/skills/planning/references/impact-discovery.md +9 -0
- package/skills/playwright-authoring/SKILL.md +15 -0
- package/skills/playwright-authoring/references/browser-reliability.md +9 -0
- package/skills/postgres-node-performance-tuning/SKILL.md +15 -0
- package/skills/postgres-node-performance-tuning/references/performance-patterns.md +14 -0
- package/skills/postgres-partitioning-uuid-v7/SKILL.md +16 -0
- package/skills/postgres-partitioning-uuid-v7/references/partition-lifecycle.md +14 -0
- package/skills/storybook-authoring/SKILL.md +15 -0
- package/skills/storybook-authoring/references/component-coverage.md +9 -0
- package/skills/swift-test-authoring/SKILL.md +15 -0
- package/skills/swift-test-authoring/references/network-test-doubles.md +9 -0
- package/skills/test-authoring/SKILL.md +17 -0
- package/skills/test-authoring/references/core-practice.md +10 -0
- package/skills/vitest-test-authoring/SKILL.md +15 -0
- package/skills/vitest-test-authoring/references/mock-boundaries.md +9 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { lstat } from 'node:fs/promises';
|
|
3
|
+
import { parse, relative, resolve, sep, join } from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
export async function resolveTargetDirectory(targetRoot, beforeRevalidate) {
|
|
7
|
+
const path = resolve(targetRoot);
|
|
8
|
+
const ancestors = await snapshotTargetAncestors(path);
|
|
9
|
+
await beforeRevalidate?.();
|
|
10
|
+
await assertTargetAncestorsUnchanged(ancestors);
|
|
11
|
+
return ancestors.at(-1);
|
|
12
|
+
}
|
|
13
|
+
export async function linkDirectoryEntry(source, target, name, beforeWorker, worker = runDirectoryLinkWorker, afterWorker) {
|
|
14
|
+
await beforeWorker?.();
|
|
15
|
+
const stdout = await worker(source, target, name);
|
|
16
|
+
await afterWorker?.();
|
|
17
|
+
await assertTargetUnchanged(target);
|
|
18
|
+
if (stdout === 'created')
|
|
19
|
+
return true;
|
|
20
|
+
if (stdout === 'existing')
|
|
21
|
+
return false;
|
|
22
|
+
throw new Error('Skill link worker returned an invalid result');
|
|
23
|
+
}
|
|
24
|
+
async function runDirectoryLinkWorker(source, target, name) {
|
|
25
|
+
try {
|
|
26
|
+
const { stdout } = await execFileAsync(process.execPath, [
|
|
27
|
+
'--input-type=module',
|
|
28
|
+
'--eval',
|
|
29
|
+
LINK_WORKER,
|
|
30
|
+
source,
|
|
31
|
+
name,
|
|
32
|
+
String(target.dev),
|
|
33
|
+
String(target.ino),
|
|
34
|
+
], { cwd: target.path, windowsHide: true });
|
|
35
|
+
return stdout;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.stderr?.includes('Target root changed during skill linking'))
|
|
39
|
+
throw new Error('Target root changed during skill linking');
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function snapshotTargetDirectory(path) {
|
|
44
|
+
const stat = await lstat(path, { bigint: true });
|
|
45
|
+
if (stat.isSymbolicLink())
|
|
46
|
+
throw new Error(`Target root contains symlink: ${path}`);
|
|
47
|
+
if (!stat.isDirectory())
|
|
48
|
+
throw new Error(`Invalid target root: ${path}`);
|
|
49
|
+
return { path, dev: stat.dev, ino: stat.ino };
|
|
50
|
+
}
|
|
51
|
+
async function assertTargetUnchanged(target) {
|
|
52
|
+
try {
|
|
53
|
+
const current = await snapshotTargetDirectory(target.path);
|
|
54
|
+
if (current.dev === target.dev && current.ino === target.ino)
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
catch { }
|
|
58
|
+
throw new Error('Target root changed during skill linking');
|
|
59
|
+
}
|
|
60
|
+
async function snapshotTargetAncestors(path) {
|
|
61
|
+
const parsed = parse(path);
|
|
62
|
+
let ancestor = parsed.root;
|
|
63
|
+
const ancestors = [];
|
|
64
|
+
for (const component of relative(parsed.root, path).split(sep)) {
|
|
65
|
+
ancestor = join(ancestor, component);
|
|
66
|
+
try {
|
|
67
|
+
ancestors.push(await snapshotTargetDirectory(ancestor));
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.code === 'ENOENT')
|
|
71
|
+
throw new Error(`Target root must exist: ${path}`);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return ancestors;
|
|
76
|
+
}
|
|
77
|
+
async function assertTargetAncestorsUnchanged(ancestors) {
|
|
78
|
+
try {
|
|
79
|
+
for (const target of ancestors) {
|
|
80
|
+
const current = await snapshotTargetDirectory(target.path);
|
|
81
|
+
if (current.dev !== target.dev || current.ino !== target.ino)
|
|
82
|
+
throw new Error('Target root changed while resolving');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error('Target root changed while resolving');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const LINK_WORKER = String.raw `
|
|
90
|
+
import { lstat, readlink, symlink } from 'node:fs/promises'
|
|
91
|
+
|
|
92
|
+
const [source, name, dev, ino] = process.argv.slice(1)
|
|
93
|
+
const directory = await lstat('.', { bigint: true })
|
|
94
|
+
if (!directory.isDirectory() || directory.isSymbolicLink() || directory.dev !== BigInt(dev) || directory.ino !== BigInt(ino))
|
|
95
|
+
throw new Error('Target root changed during skill linking')
|
|
96
|
+
async function assertExistingMatchesSource() {
|
|
97
|
+
const destination = await lstat(name)
|
|
98
|
+
if (!destination.isSymbolicLink() || (await readlink(name)) !== source)
|
|
99
|
+
throw new Error('Destination already exists: ' + name)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let created = false
|
|
103
|
+
try {
|
|
104
|
+
await assertExistingMatchesSource()
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (error?.code !== 'ENOENT') throw error
|
|
107
|
+
try {
|
|
108
|
+
await symlink(source, name, 'dir')
|
|
109
|
+
created = true
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error?.code === 'EEXIST') {
|
|
112
|
+
await assertExistingMatchesSource()
|
|
113
|
+
} else {
|
|
114
|
+
if (process.platform !== 'win32' || !['EACCES', 'EPERM'].includes(error?.code)) throw error
|
|
115
|
+
try {
|
|
116
|
+
await symlink(source, name, 'junction')
|
|
117
|
+
created = true
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error?.code !== 'EEXIST') throw error
|
|
120
|
+
await assertExistingMatchesSource()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
process.stdout.write(created ? 'created' : 'existing')
|
|
126
|
+
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vouchington-tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Vouchington CLI and extractable tooling libraries.",
|
|
5
5
|
"homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"import": "./dist/index.mjs",
|
|
32
32
|
"default": "./dist/index.mjs"
|
|
33
33
|
},
|
|
34
|
+
"./skill-discovery": {
|
|
35
|
+
"types": "./dist/skill-discovery/index.d.mts",
|
|
36
|
+
"import": "./dist/skill-discovery/index.mjs",
|
|
37
|
+
"default": "./dist/skill-discovery/index.mjs"
|
|
38
|
+
},
|
|
34
39
|
"./runner-port-policy": {
|
|
35
40
|
"types": "./dist/runner-port-policy/index.d.mts",
|
|
36
41
|
"import": "./dist/runner-port-policy/index.mjs",
|
|
@@ -41,6 +46,16 @@
|
|
|
41
46
|
"import": "./dist/retrospective-transcript/index.mjs",
|
|
42
47
|
"default": "./dist/retrospective-transcript/index.mjs"
|
|
43
48
|
},
|
|
49
|
+
"./retrospective-facts": {
|
|
50
|
+
"types": "./dist/retrospective-facts/index.d.mts",
|
|
51
|
+
"import": "./dist/retrospective-facts/index.mjs",
|
|
52
|
+
"default": "./dist/retrospective-facts/index.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./agent-blackboard": {
|
|
55
|
+
"types": "./dist/agent-blackboard/index.d.mts",
|
|
56
|
+
"import": "./dist/agent-blackboard/index.mjs",
|
|
57
|
+
"default": "./dist/agent-blackboard/index.mjs"
|
|
58
|
+
},
|
|
44
59
|
"./session-friction": {
|
|
45
60
|
"types": "./dist/session-friction/index.d.mts",
|
|
46
61
|
"import": "./dist/session-friction/index.mjs",
|
|
@@ -234,7 +249,16 @@
|
|
|
234
249
|
"yaml": "2.9.0"
|
|
235
250
|
},
|
|
236
251
|
"devDependencies": {
|
|
237
|
-
"@types/picomatch": "^4.0.3"
|
|
252
|
+
"@types/picomatch": "^4.0.3",
|
|
253
|
+
"agent-blackboard": "^0.3.1"
|
|
254
|
+
},
|
|
255
|
+
"peerDependencies": {
|
|
256
|
+
"agent-blackboard": "^0.3.1"
|
|
257
|
+
},
|
|
258
|
+
"peerDependenciesMeta": {
|
|
259
|
+
"agent-blackboard": {
|
|
260
|
+
"optional": true
|
|
261
|
+
}
|
|
238
262
|
},
|
|
239
263
|
"optionalDependencies": {
|
|
240
264
|
"@libpg-query/parser": "^18.0.0"
|
package/scripts/build.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process'
|
|
2
2
|
import { chmod, copyFile, cp, mkdir, rm } from 'node:fs/promises'
|
|
3
|
+
import { join } from 'node:path'
|
|
3
4
|
import { fileURLToPath } from 'node:url'
|
|
4
5
|
|
|
6
|
+
import skillManifest from '../skill-manifest.json' with { type: 'json' }
|
|
7
|
+
|
|
5
8
|
const packageRoot = new URL('..', import.meta.url)
|
|
6
9
|
const dist = new URL('../dist', import.meta.url)
|
|
7
10
|
|
|
@@ -16,9 +19,18 @@ await copyFile(
|
|
|
16
19
|
new URL('../src/runner-port-policy/runner-port-policy.json', import.meta.url),
|
|
17
20
|
new URL('../dist/runner-port-policy/runner-port-policy.json', import.meta.url),
|
|
18
21
|
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const pluginRoot = fileURLToPath(new URL('../../../plugins', import.meta.url))
|
|
23
|
+
const skillsRoot = fileURLToPath(new URL('../skills/', import.meta.url))
|
|
24
|
+
const seenSkills = new Set()
|
|
25
|
+
for (const skill of skillManifest.skills) {
|
|
26
|
+
if (seenSkills.has(skill.name)) throw new Error(`Duplicate skill: ${skill.name}`)
|
|
27
|
+
seenSkills.add(skill.name)
|
|
28
|
+
await cp(join(pluginRoot, skill.plugin, 'skills', skill.name), join(skillsRoot, skill.name), {
|
|
29
|
+
recursive: true,
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
await copyFile(
|
|
33
|
+
new URL('../skill-manifest.json', import.meta.url),
|
|
34
|
+
new URL('../skills/manifest.json', import.meta.url),
|
|
23
35
|
)
|
|
24
36
|
await chmod(new URL('../dist/cli/index.mjs', import.meta.url), 0o755)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [ "${#}" -ne 1 ]; then
|
|
5
|
+
echo "usage: harness-admission-lane.sh <lanes>" >&2
|
|
6
|
+
exit 2
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
if [ -z "${GITHUB_OUTPUT:-}" ]; then
|
|
10
|
+
echo 'GITHUB_OUTPUT must be set' >&2
|
|
11
|
+
exit 2
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
LANES="$1"
|
|
15
|
+
if ! [[ "$LANES" =~ ^[1-9][0-9]*$ ]]; then
|
|
16
|
+
echo "::error::admission lane count must be a positive integer, got: '$LANES'"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
RUN_ID="${GITHUB_RUN_ID:-}"
|
|
21
|
+
if ! [[ "$RUN_ID" =~ ^[0-9]+$ ]]; then
|
|
22
|
+
echo "::error::GITHUB_RUN_ID must be a non-negative integer, got: '${RUN_ID}'"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo "lane=$(( RUN_ID % LANES ))" >> "$GITHUB_OUTPUT"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [ "$#" -eq 0 ]; then
|
|
5
|
+
echo "usage: harness-assert-gates.sh <gate>..." >&2
|
|
6
|
+
exit 2
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
for gate in "$@"; do
|
|
10
|
+
if ! [[ "$gate" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
|
|
11
|
+
echo "::error::invalid gate name: '$gate'"
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
done
|
|
15
|
+
|
|
16
|
+
for gate in "$@"; do
|
|
17
|
+
value="${!gate:-}"
|
|
18
|
+
if [ "$value" = "true" ]; then
|
|
19
|
+
echo "::error::$gate must be disabled but is enabled"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
exit 0
|
|
@@ -23,5 +23,10 @@ branching, review, and release policy.
|
|
|
23
23
|
6. Review the diff for accidental files, secrets, generated output, broken documentation links,
|
|
24
24
|
and assumptions that belong in local instructions instead.
|
|
25
25
|
|
|
26
|
+
For portable implementation and review checks, read [implementation](references/implementation.md),
|
|
27
|
+
[review](references/review.md), and [evidence sweep](references/evidence-sweep.md). The older
|
|
28
|
+
[implementation and review](references/implementation-and-review.md) remains a compact overview.
|
|
29
|
+
Local instructions remain authoritative for commands, commits, review systems, and release policy.
|
|
30
|
+
|
|
26
31
|
Do not invent a default branch, runner class, documentation root, review system, merge policy, or
|
|
27
32
|
command catalog. A consumer wrapper or local instruction file owns those choices.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Evidence sweep
|
|
2
|
+
|
|
3
|
+
Map every acceptance criterion to a focused test, inspection, or manual verification with a concrete
|
|
4
|
+
result. Run the required broader checks after focused validation. Treat skipped validation as a
|
|
5
|
+
finding: state the blocker, affected surface, and remaining risk.
|
|
6
|
+
|
|
7
|
+
Before handoff, compare the final diff to the accepted decision ledger and verify documentation,
|
|
8
|
+
generated output, and public contracts agree with the implementation.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Implementation and review
|
|
2
|
+
|
|
3
|
+
Before editing, map callers, tests, configuration, and documentation that own the behavior. Keep the
|
|
4
|
+
change within the accepted boundary; record a new dependency or product decision before widening it.
|
|
5
|
+
|
|
6
|
+
After focused validation, inspect the complete diff for accidental generated files, secret exposure,
|
|
7
|
+
dead paths, and documentation drift. Validate the public interface and failure paths, not only the
|
|
8
|
+
happy path. Before a reviewable commit, run the repository-required checks and state any skipped
|
|
9
|
+
checks with their concrete blocker.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Implementation
|
|
2
|
+
|
|
3
|
+
Keep an accepted-decision ledger for interfaces, data boundaries, validation, and ownership choices
|
|
4
|
+
that could otherwise be lost during coding. Start from a failing behavioral test when practical and
|
|
5
|
+
complete the real path rather than adding placeholders or compatibility shims without a requirement.
|
|
6
|
+
|
|
7
|
+
When behavior changes, update the public contract, documentation, fixtures, and generated artifacts
|
|
8
|
+
that describe it. Keep local commands, branch policy, and release mechanics in the consumer wrapper.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Review
|
|
2
|
+
|
|
3
|
+
Review the complete diff, not only changed implementation lines. Check premise and scope, public
|
|
4
|
+
contract compatibility, failure paths, authorization, untrusted input, secrets, and security
|
|
5
|
+
boundaries. Remove dead paths and stale documentation rather than labeling them as legacy.
|
|
6
|
+
|
|
7
|
+
Record unresolved risk as an explicit accepted decision or follow-up, never as an unnoticed gap.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-vitest-test-authoring
|
|
3
|
+
description: Apply backend Vitest patterns for service, provider, persistence, and queue boundaries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Backend Vitest test authoring
|
|
7
|
+
|
|
8
|
+
Apply [vitest-test-authoring](../vitest-test-authoring/SKILL.md) first. Exercise real integration
|
|
9
|
+
boundaries only when their lifecycle is controlled by the test environment; otherwise mock the
|
|
10
|
+
network or provider edge. Randomize fixture identities where shared stores can collide, assert
|
|
11
|
+
authorization and retry behavior at boundaries, and clean up resources deterministically.
|
|
12
|
+
|
|
13
|
+
Consumer wrappers own database setup, queue providers, test projects, and rate-limit policy.
|
|
14
|
+
|
|
15
|
+
Read [integration boundaries](references/integration-boundaries.md) for fixture and collision safety.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Integration boundaries
|
|
2
|
+
|
|
3
|
+
Use real persistence, queue, and internal-service boundaries when the test environment controls
|
|
4
|
+
their lifecycle. Mock only external provider edges. Create collision-safe fixture identities and
|
|
5
|
+
register event listeners before the mutation that produces them. Cleanup must be ownership-scoped;
|
|
6
|
+
never broadly reset shared state used by concurrent tests.
|
|
7
|
+
|
|
8
|
+
Assert persisted state, emitted work, or externally visible results at the boundary. A mock-only
|
|
9
|
+
test is insufficient when import wiring, serialization, transaction behavior, or retries are part
|
|
10
|
+
of the contract.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dotnet-test-authoring
|
|
3
|
+
description: Add maintainable .NET tests with appropriate unit, app, and integration boundaries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# .NET test authoring
|
|
7
|
+
|
|
8
|
+
Place tests at the narrowest layer that proves the behavior. Batch native or external selection
|
|
9
|
+
where the project requires it, isolate process and filesystem state, and assert serialized contracts
|
|
10
|
+
instead of private implementation details. Keep test helpers typed and reusable only when they remove
|
|
11
|
+
repeated setup without hiding important expectations.
|
|
12
|
+
|
|
13
|
+
Consumer wrappers own solution layout, test frameworks, native dependencies, and coverage policy.
|
|
14
|
+
|
|
15
|
+
Keep portable library tests separate from rendered application tests; batch compatible native targets
|
|
16
|
+
in one selection pass so a shared build validates the same source set.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"skills": [
|
|
4
|
+
{
|
|
5
|
+
"name": "agent-workflow",
|
|
6
|
+
"plugin": "vouchington-workflow",
|
|
7
|
+
"pluginVersion": "0.3.0",
|
|
8
|
+
"path": "agent-workflow/SKILL.md"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "backend-vitest-test-authoring",
|
|
12
|
+
"plugin": "vouchington-testing",
|
|
13
|
+
"pluginVersion": "0.1.0",
|
|
14
|
+
"path": "backend-vitest-test-authoring/SKILL.md",
|
|
15
|
+
"prerequisites": ["vitest-test-authoring"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "blackboard",
|
|
19
|
+
"plugin": "vouchington-workflow",
|
|
20
|
+
"pluginVersion": "0.3.0",
|
|
21
|
+
"path": "blackboard/SKILL.md"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "dotnet-test-authoring",
|
|
25
|
+
"plugin": "vouchington-testing",
|
|
26
|
+
"pluginVersion": "0.1.0",
|
|
27
|
+
"path": "dotnet-test-authoring/SKILL.md"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "git-commit-checklist",
|
|
31
|
+
"plugin": "vouchington-workflow",
|
|
32
|
+
"pluginVersion": "0.3.0",
|
|
33
|
+
"path": "git-commit-checklist/SKILL.md"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "github-actions-checklist",
|
|
37
|
+
"plugin": "vouchington-workflow",
|
|
38
|
+
"pluginVersion": "0.3.0",
|
|
39
|
+
"path": "github-actions-checklist/SKILL.md"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "github-issue",
|
|
43
|
+
"plugin": "vouchington-workflow",
|
|
44
|
+
"pluginVersion": "0.3.0",
|
|
45
|
+
"path": "github-issue/SKILL.md"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "nextjs-vitest-test-authoring",
|
|
49
|
+
"plugin": "vouchington-testing",
|
|
50
|
+
"pluginVersion": "0.1.0",
|
|
51
|
+
"path": "nextjs-vitest-test-authoring/SKILL.md",
|
|
52
|
+
"prerequisites": ["vitest-test-authoring"]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "organize-github-issues",
|
|
56
|
+
"plugin": "vouchington-workflow",
|
|
57
|
+
"pluginVersion": "0.3.0",
|
|
58
|
+
"path": "organize-github-issues/SKILL.md"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "package-json-checklist",
|
|
62
|
+
"plugin": "vouchington-workflow",
|
|
63
|
+
"pluginVersion": "0.3.0",
|
|
64
|
+
"path": "package-json-checklist/SKILL.md"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "planning",
|
|
68
|
+
"plugin": "vouchington-workflow",
|
|
69
|
+
"pluginVersion": "0.3.0",
|
|
70
|
+
"path": "planning/SKILL.md"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "playwright-authoring",
|
|
74
|
+
"plugin": "vouchington-testing",
|
|
75
|
+
"pluginVersion": "0.1.0",
|
|
76
|
+
"path": "playwright-authoring/SKILL.md"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "postgres-node-performance-tuning",
|
|
80
|
+
"plugin": "vouchington-database",
|
|
81
|
+
"pluginVersion": "0.1.0",
|
|
82
|
+
"path": "postgres-node-performance-tuning/SKILL.md"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "postgres-partitioning-uuid-v7",
|
|
86
|
+
"plugin": "vouchington-database",
|
|
87
|
+
"pluginVersion": "0.1.0",
|
|
88
|
+
"path": "postgres-partitioning-uuid-v7/SKILL.md"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "pr-description",
|
|
92
|
+
"plugin": "vouchington-workflow",
|
|
93
|
+
"pluginVersion": "0.3.0",
|
|
94
|
+
"path": "pr-description/SKILL.md"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"name": "retrospective",
|
|
98
|
+
"plugin": "vouchington-workflow",
|
|
99
|
+
"pluginVersion": "0.3.0",
|
|
100
|
+
"path": "retrospective/SKILL.md"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "retrospective-distill",
|
|
104
|
+
"plugin": "vouchington-workflow",
|
|
105
|
+
"pluginVersion": "0.3.0",
|
|
106
|
+
"path": "retrospective-distill/SKILL.md"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "review-ci-logs",
|
|
110
|
+
"plugin": "vouchington-workflow",
|
|
111
|
+
"pluginVersion": "0.3.0",
|
|
112
|
+
"path": "review-ci-logs/SKILL.md"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "review-github-issue-taxonomy",
|
|
116
|
+
"plugin": "vouchington-workflow",
|
|
117
|
+
"pluginVersion": "0.3.0",
|
|
118
|
+
"path": "review-github-issue-taxonomy/SKILL.md"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "revisit-followups",
|
|
122
|
+
"plugin": "vouchington-workflow",
|
|
123
|
+
"pluginVersion": "0.3.0",
|
|
124
|
+
"path": "revisit-followups/SKILL.md"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "static-analysis-checklist",
|
|
128
|
+
"plugin": "vouchington-workflow",
|
|
129
|
+
"pluginVersion": "0.3.0",
|
|
130
|
+
"path": "static-analysis-checklist/SKILL.md"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "storybook-authoring",
|
|
134
|
+
"plugin": "vouchington-testing",
|
|
135
|
+
"pluginVersion": "0.1.0",
|
|
136
|
+
"path": "storybook-authoring/SKILL.md"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "swift-test-authoring",
|
|
140
|
+
"plugin": "vouchington-testing",
|
|
141
|
+
"pluginVersion": "0.1.0",
|
|
142
|
+
"path": "swift-test-authoring/SKILL.md"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "test-authoring",
|
|
146
|
+
"plugin": "vouchington-testing",
|
|
147
|
+
"pluginVersion": "0.1.0",
|
|
148
|
+
"path": "test-authoring/SKILL.md"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "vitest-test-authoring",
|
|
152
|
+
"plugin": "vouchington-testing",
|
|
153
|
+
"pluginVersion": "0.1.0",
|
|
154
|
+
"path": "vitest-test-authoring/SKILL.md",
|
|
155
|
+
"prerequisites": ["test-authoring"]
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nextjs-vitest-test-authoring
|
|
3
|
+
description: Apply Vitest patterns for Next.js components, routes, and server-side modules.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Next.js Vitest test authoring
|
|
7
|
+
|
|
8
|
+
Apply [vitest-test-authoring](../vitest-test-authoring/SKILL.md) first. Mock framework navigation,
|
|
9
|
+
headers, and server-only boundaries at the framework edge, then test component behavior through
|
|
10
|
+
rendered output and user-visible state. Keep API-response fixtures representative and avoid testing
|
|
11
|
+
framework internals. Use browser tests for behavior that cannot be represented in the test runtime.
|
|
12
|
+
|
|
13
|
+
Consumer wrappers own framework mock helpers, render libraries, and route fixture conventions.
|
|
14
|
+
|
|
15
|
+
Read [framework boundaries](references/framework-boundaries.md) for module shape and server-only cases.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Framework boundaries
|
|
2
|
+
|
|
3
|
+
Mock framework navigation, headers, cookies, and server-only APIs at the framework edge, not inside
|
|
4
|
+
the component or route under test. Preserve typed module shape and use the consumer's shared mocks
|
|
5
|
+
when they exist. Build API responses with typed factories rather than inline partial objects.
|
|
6
|
+
|
|
7
|
+
Use direct rendering for component behavior. If request scope, hydration, browser APIs, or server
|
|
8
|
+
module resolution cannot be represented faithfully, move the assertion to an integration or browser
|
|
9
|
+
test instead of widening a unit-test mock.
|
package/skills/planning/SKILL.md
CHANGED
|
@@ -19,5 +19,8 @@ Use before implementation work that needs a durable plan. Repository-local `AGEN
|
|
|
19
19
|
5. Validate and save the plan using the repository's required issue or document workflow before
|
|
20
20
|
implementation when local policy requires one.
|
|
21
21
|
|
|
22
|
+
For cross-cutting changes, read [impact discovery](references/impact-discovery.md) before selecting
|
|
23
|
+
tests or concluding that a surface has no dependents.
|
|
24
|
+
|
|
22
25
|
Do not invent a plan template, default repository, issue taxonomy, dependency graph tool, or
|
|
23
26
|
approval workflow. A consumer wrapper owns those choices.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Impact discovery
|
|
2
|
+
|
|
3
|
+
Start from the changed surface and trace imports, callers, configuration, generated artifacts, and
|
|
4
|
+
tests. Use the repository's graph or search tools where available; otherwise record the evidence
|
|
5
|
+
used and the uncertainty that remains. Select focused tests from real dependents, then include
|
|
6
|
+
broader validation when a shared contract, package boundary, or generated artifact changes.
|
|
7
|
+
|
|
8
|
+
Do not treat a tool's incomplete graph as proof that no dependent exists. Escalate uncertain
|
|
9
|
+
high-risk boundaries for independent review or a broader test selection.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-authoring
|
|
3
|
+
description: Author reliable Playwright browser tests, fixtures, selectors, and user flows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Playwright authoring
|
|
7
|
+
|
|
8
|
+
Use stable, accessible locators and assert user-observable outcomes. Establish data, authentication,
|
|
9
|
+
and server state through supported fixtures or APIs; do not rely on test ordering or arbitrary waits.
|
|
10
|
+
Keep each scenario independently repeatable, use auto-waiting assertions, and capture diagnostics on
|
|
11
|
+
failure. Prefer browser coverage for real browser interactions rather than duplicating unit tests.
|
|
12
|
+
|
|
13
|
+
Consumer wrappers own environments, credentials, personas, fixtures, and suite commands.
|
|
14
|
+
|
|
15
|
+
Read [browser reliability](references/browser-reliability.md) for locator, waiting, state, and network rules.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Browser reliability
|
|
2
|
+
|
|
3
|
+
Use the browser only for browser-owned behavior. Prefer stable accessibility or test-id locators,
|
|
4
|
+
scope repeated content, and assert visible outcomes. Never use arbitrary sleeps; wait for a precise
|
|
5
|
+
URL, request, response, DOM state, or user-visible completion signal.
|
|
6
|
+
|
|
7
|
+
Seed deterministic data and establish authentication through supported fixtures. Mock network only
|
|
8
|
+
for third-party behavior, fault injection, streaming, or conditions impossible to seed. Register
|
|
9
|
+
response waits before triggering mutations, and make each scenario independent of prior state.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: postgres-node-performance-tuning
|
|
3
|
+
description: Diagnose and improve PostgreSQL performance in Node.js applications with large data volumes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PostgreSQL and Node.js performance
|
|
7
|
+
|
|
8
|
+
Measure query plans and workload shape before changing code. Select only required columns, bound
|
|
9
|
+
result sets, paginate or stream large reads, batch writes within explicit transaction limits, and
|
|
10
|
+
keep connection-pool usage bounded. Validate query changes with representative cardinality and
|
|
11
|
+
watch latency, memory, lock time, and connection pressure together.
|
|
12
|
+
|
|
13
|
+
Consumer wrappers own schema ownership, operational thresholds, pooling configuration, and rollout.
|
|
14
|
+
|
|
15
|
+
Read [performance patterns](references/performance-patterns.md) before changing high-volume paths.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Performance patterns
|
|
2
|
+
|
|
3
|
+
Use pools and release checked-out clients in `finally`, especially for cursors, streams, and COPY.
|
|
4
|
+
Route ordinary reads to a replica when its lag is acceptable; route read-after-write, locking, and
|
|
5
|
+
transaction-consistent reads to the writer. Do not hold a client across unrelated application work.
|
|
6
|
+
|
|
7
|
+
For large reads, use keyset pagination, cursors, or streams with cancellation and bounded batches.
|
|
8
|
+
For writes, prefer set-based batches such as UNNEST or COPY when they preserve validation and error
|
|
9
|
+
handling. Measure query plans with representative cardinality before changing an index or query.
|
|
10
|
+
|
|
11
|
+
Check query predicates, joins, ordering, and selected columns against index shape. Use EXPLAIN
|
|
12
|
+
evidence to confirm planner behavior. Add extended statistics only when observed estimates show a
|
|
13
|
+
correlation problem; verify the statistics are collected and used. Partitioning can reduce scanned
|
|
14
|
+
data, but it does not replace suitable local indexes or predicates that permit pruning.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: postgres-partitioning-uuid-v7
|
|
3
|
+
description: Design PostgreSQL partitions and indexes that use time-ordered UUIDv7 identifiers efficiently.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PostgreSQL partitioning with UUIDv7
|
|
7
|
+
|
|
8
|
+
Partition only after confirming lifecycle, retention, and query predicates benefit from it. Treat a
|
|
9
|
+
UUIDv7 as time ordered but not as a replacement for explicit business timestamps where semantics
|
|
10
|
+
matter. Align partition keys, primary keys, indexes, constraints, and query predicates so partition
|
|
11
|
+
pruning is observable. Plan creation, retention, migration, and verification as one deployable
|
|
12
|
+
lifecycle, including rollback and independent-reader compatibility.
|
|
13
|
+
|
|
14
|
+
Consumer wrappers own partition intervals, migration tooling, retention policy, and deploy sequencing.
|
|
15
|
+
|
|
16
|
+
Read [partition lifecycle](references/partition-lifecycle.md) before a schema or retention migration.
|