@cat-factory/prompt-fragments 1.0.0 → 1.0.2
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/LICENSE +21 -21
- package/README.md +163 -42
- package/dist/collections/acceptance.d.ts +3 -0
- package/dist/collections/acceptance.d.ts.map +1 -0
- package/dist/collections/acceptance.js +63 -0
- package/dist/collections/acceptance.js.map +1 -0
- package/dist/collections/design.d.ts +28 -0
- package/dist/collections/design.d.ts.map +1 -0
- package/dist/collections/design.js +65 -0
- package/dist/collections/design.js.map +1 -0
- package/dist/collections/migration.d.ts +20 -0
- package/dist/collections/migration.d.ts.map +1 -0
- package/dist/collections/migration.js +99 -0
- package/dist/collections/migration.js.map +1 -0
- package/dist/collections/node.d.ts +3 -0
- package/dist/collections/node.d.ts.map +1 -0
- package/dist/collections/node.js +40 -0
- package/dist/collections/node.js.map +1 -0
- package/dist/collections/react.d.ts +3 -0
- package/dist/collections/react.d.ts.map +1 -0
- package/dist/collections/react.js +21 -0
- package/dist/collections/react.js.map +1 -0
- package/dist/collections/style.d.ts +11 -0
- package/dist/collections/style.d.ts.map +1 -0
- package/dist/collections/style.js +64 -0
- package/dist/collections/style.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/task-type-defaults.d.ts +4 -0
- package/dist/task-type-defaults.d.ts.map +1 -0
- package/dist/task-type-defaults.js +28 -0
- package/dist/task-type-defaults.js.map +1 -0
- package/package.json +14 -5
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Igor Savin
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Igor Savin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,42 +1,163 @@
|
|
|
1
|
-
# @cat-factory/prompt-fragments
|
|
2
|
-
|
|
3
|
-
The **built-in tier** of best-practice prompt fragments
|
|
4
|
-
snippets that get folded into an agent's system prompt at run time
|
|
5
|
-
(`composeSystemPrompt`). This package is **plain, build-static data**: no I/O, no
|
|
6
|
-
framework. It is the source of truth for the shipped defaults and the seed for the
|
|
7
|
-
tenant-scoped [prompt-fragment library](
|
|
8
|
-
|
|
9
|
-
## What's here
|
|
10
|
-
|
|
11
|
-
- `src/collections/*.ts
|
|
12
|
-
`acceptance`. Each exports an array of `PromptFragment`.
|
|
13
|
-
- `src/index.ts
|
|
14
|
-
`FRAGMENTS_BY_ID` and `getFragment(id)` for O(1) lookup during composition.
|
|
15
|
-
|
|
16
|
-
A `PromptFragment` (shape defined in [`@cat-factory/contracts`](
|
|
17
|
-
carries an `id`, `version`, `title`, optional `category`, a `summary` (used by the
|
|
18
|
-
relevance selector), the `body` (injected text),
|
|
19
|
-
hint (`blockTypes` / `agentKinds`).
|
|
20
|
-
|
|
21
|
-
## How it's used
|
|
22
|
-
|
|
23
|
-
- The Worker serves this catalog **read-only** at `GET /prompt-fragments`; the SPA
|
|
24
|
-
shows it in the per-block fragment picker.
|
|
25
|
-
- A block stores selected `fragmentIds[]`; at run time core composes the chosen
|
|
26
|
-
bodies into the system prompt.
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
# @cat-factory/prompt-fragments
|
|
2
|
+
|
|
3
|
+
The **built-in tier** of best-practice prompt fragments: small, curated guidance
|
|
4
|
+
snippets that get folded into an agent's system prompt at run time
|
|
5
|
+
(`composeSystemPrompt`). This package is **plain, build-static data**: no I/O, no
|
|
6
|
+
framework. It is the source of truth for the shipped defaults and the seed for the
|
|
7
|
+
tenant-scoped [prompt-fragment library](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/adr/0006-prompt-fragment-library.md).
|
|
8
|
+
|
|
9
|
+
## What's here
|
|
10
|
+
|
|
11
|
+
- `src/collections/*.ts`: fragments authored per topic. Today: `node`, `react`,
|
|
12
|
+
`acceptance`, `design`, `style`, `migration`. Each exports an array of `PromptFragment`.
|
|
13
|
+
- `src/index.ts`: merges the collections into a single `FRAGMENTS` registry plus
|
|
14
|
+
`FRAGMENTS_BY_ID` and `getFragment(id)` for O(1) lookup during composition.
|
|
15
|
+
|
|
16
|
+
A `PromptFragment` (shape defined in [`@cat-factory/contracts`](https://github.com/kibertoad/cat-factory/tree/main/backend/packages/contracts))
|
|
17
|
+
carries an `id`, `version`, `title`, optional `category`, a `summary` (used by the
|
|
18
|
+
relevance selector), the `body` (injected text), an optional condensed `brief`
|
|
19
|
+
(see below), and an optional `appliesTo` hint (`blockTypes` / `agentKinds`).
|
|
20
|
+
|
|
21
|
+
## How it's used
|
|
22
|
+
|
|
23
|
+
- The Worker serves this catalog **read-only** at `GET /prompt-fragments`; the SPA
|
|
24
|
+
shows it in the per-block fragment picker.
|
|
25
|
+
- A block stores selected `fragmentIds[]`; at run time core composes the chosen
|
|
26
|
+
bodies into the system prompt. Each standard is folded as its **own delimited,
|
|
27
|
+
title-labelled block** (`<best-practice-standard id="…" title="…">`) rather than one
|
|
28
|
+
concatenated blob, so an agent can tell the standards apart and cite one by its title
|
|
29
|
+
(`composeSystemPrompt` / `composeBlockSystemPrompt` in `@cat-factory/agents`). The
|
|
30
|
+
code + PR **review** agents additionally report per-standard **adherence** (a 1–10
|
|
31
|
+
rating + related findings) back on the step, surfaced in run details.
|
|
32
|
+
- When the optional library is enabled, this becomes the **built-in tier** of a
|
|
33
|
+
three-tier merge (built-in ∪ account ∪ workspace); ids here can be shadowed or
|
|
34
|
+
suppressed by higher tiers. See
|
|
35
|
+
[ADR 0006](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/adr/0006-prompt-fragment-library.md).
|
|
36
|
+
|
|
37
|
+
### Two-tier bodies: `body` and `brief`
|
|
38
|
+
|
|
39
|
+
An **implementer** kind (`coder` / `fixer` / `ci-fixer` / `conflict-resolver`: the kinds
|
|
40
|
+
carrying the `brief-standards` trait) runs a long agentic loop whose system prompt, standards
|
|
41
|
+
included, is re-sent on **every turn**. Those kinds fold a fragment's optional `brief` (the
|
|
42
|
+
same standard stated tersely) instead of its full `body`. Reviewer / planner / investigator
|
|
43
|
+
kinds keep the full text: they run few turns and benefit from it when judging built work.
|
|
44
|
+
|
|
45
|
+
Two rules govern authoring one:
|
|
46
|
+
|
|
47
|
+
- **A `brief` must not drop a rule, only its elaboration.** It is the same standard compressed,
|
|
48
|
+
not a subset: an agent folding the brief is held to everything the body demands.
|
|
49
|
+
- **`brief` travels WITH the body it condenses** and is never re-resolved by id downstream. A
|
|
50
|
+
higher tier that overrides a built-in id supplies its OWN brief (or none), so the override's
|
|
51
|
+
own text is folded, never the built-in's condensed text over a tenant's standard.
|
|
52
|
+
|
|
53
|
+
Omitting `brief` is always safe: the full `body` is used for every kind, unchanged. Fragments
|
|
54
|
+
that can reach an implementer kind carry one; the ones scoped to `spec-writer` / `playwright` /
|
|
55
|
+
document-authoring kinds (which are not implementers) deliberately do not.
|
|
56
|
+
|
|
57
|
+
Every fragment in **this** package is comfortably under `FRAGMENT_BRIEF_MIN_BODY_CHARS`, so the
|
|
58
|
+
auto-condensation below never acts on the shipped catalog: keep it that way by writing a brief
|
|
59
|
+
by hand when a built-in grows past ~1,500 characters.
|
|
60
|
+
|
|
61
|
+
### Where a brief comes from at run time
|
|
62
|
+
|
|
63
|
+
The built-in `brief` above is only the first of three answers. For a fragment resolved through
|
|
64
|
+
the tenant library ([ADR 0006](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/adr/0006-prompt-fragment-library.md)) the resolution
|
|
65
|
+
order is:
|
|
66
|
+
|
|
67
|
+
1. **The winning tier's linked `brief`**: a built-in's, or the one a tenant authored on its own
|
|
68
|
+
managed row (the library editor's short-version field, or a repo-sourced guideline file's
|
|
69
|
+
`brief:` frontmatter key).
|
|
70
|
+
2. **A model-GENERATED condensation**, for a body over `FRAGMENT_BRIEF_MIN_BODY_CHARS` that has
|
|
71
|
+
no linked brief. Produced once on the first implementer dispatch that folds it, persisted, and
|
|
72
|
+
**regenerated whenever the body changes**: a library edit, a repo resync, or a living
|
|
73
|
+
document re-resolved at run time.
|
|
74
|
+
3. **Nothing**: the full `body` is folded for every kind, which is also where every failure on
|
|
75
|
+
that path lands (no model wired, an unreadable store, a refused condensation).
|
|
76
|
+
|
|
77
|
+
Design, decisions and gotchas:
|
|
78
|
+
[`docs/initiatives/auto-generated-fragment-briefs.md`](https://github.com/kibertoad/cat-factory/blob/main/docs/initiatives/auto-generated-fragment-briefs.md).
|
|
79
|
+
|
|
80
|
+
## Programmatic deployment seams (custom fragments + per-task-type defaults)
|
|
81
|
+
|
|
82
|
+
A deployment (local **or** hosted) extends the fragment behaviour through the app-owned
|
|
83
|
+
`PromptFragmentRegistry` (kernel), injected BY REFERENCE into the facade it builds. No fork, no
|
|
84
|
+
rebuild, no per-workspace UI.
|
|
85
|
+
|
|
86
|
+
> **This replaced two MODULE GLOBALS** (`registerPromptFragment` and
|
|
87
|
+
> `registerTaskTypeDefaultFragments`), and the reason is worth stating because it is invisible from
|
|
88
|
+
> inside this repo. Their correctness depended on every reader resolving the same physical copy of
|
|
89
|
+
> this package. A `workspace:*` dependency publishes as an EXACT version, so a consumer floating the
|
|
90
|
+
> range onto a newer patch gets TWO copies: the registration lands in one, the server reads the
|
|
91
|
+
> other, and every task of the deployment's operation is seeded with ids that fold nothing. The only
|
|
92
|
+
> signal was one boot warning, which is also the warning a typo produces.
|
|
93
|
+
|
|
94
|
+
- **Build the registry**: `promptFragmentRegistryWithBuiltins()` (this package) news one carrying
|
|
95
|
+
the shipped catalog and its built-in per-type defaults; `defaultPromptFragmentRegistry()` (kernel)
|
|
96
|
+
news an EMPTY one, which is how a deployment says it wants only its own standards. The built-ins
|
|
97
|
+
install through the registry's ordinary public methods, so the platform exercises a consumer's own
|
|
98
|
+
seam on every boot and it cannot rot for consumers only.
|
|
99
|
+
- **Add custom fragments to the universal pool**: `registry.register(fragment)` /
|
|
100
|
+
`registry.registerAll(fragments)`. Every `GET /prompt-fragments` catalog read and every run-time
|
|
101
|
+
body lookup then sees them; re-registering an id REPLACES the entry of that id, so a deployment
|
|
102
|
+
refines a shipped standard in place.
|
|
103
|
+
- **Mark fragments as the default for a BUILT-IN task type**:
|
|
104
|
+
`registry.registerTaskTypeDefaults(taskType, fragmentIds)`. Every **new** task of that type
|
|
105
|
+
(`document`, `review`, `feature`, …) is then seeded with those fragments onto its own
|
|
106
|
+
`fragmentIds` at creation, beside whatever it inherits from its service. Seeding is server-side
|
|
107
|
+
and authoritative: it applies even for tasks created via the public API with no create-form picker.
|
|
108
|
+
|
|
109
|
+
**Registering a type REPLACES its built-in set rather than unioning with it.** The module-global
|
|
110
|
+
seam unioned silently, which meant a deployment could not remove a shipped default however it
|
|
111
|
+
wrote the call. Spread `DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS` into your own list to keep both,
|
|
112
|
+
which says so in the code.
|
|
113
|
+
|
|
114
|
+
**A deployment's OWN (namespaced) task type does not use this seam.** It declares
|
|
115
|
+
`defaultFragmentIds` (and `conditionalFragmentIds`, for standing context that depends on the
|
|
116
|
+
answers a case supplies) on its own registration, where boot validation can see the ids and warn
|
|
117
|
+
on one the code pool does not resolve. That declaration is one third of a **reusable operation**:
|
|
118
|
+
see [`backend/docs/reusable-operations.md`](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/reusable-operations.md).
|
|
119
|
+
|
|
120
|
+
- **A code-registered fragment may NOT carry a `documentRef`.** Every code registration lands on the
|
|
121
|
+
`builtin` tier, whose live resolution needs a connection workspace a deployment-wide registration
|
|
122
|
+
cannot name, so boot REFUSES it (`fragment_document_ref_unsupported`) rather than carrying it,
|
|
123
|
+
rendering it as live in the library UI, and ignoring it at run time (which is what it did).
|
|
124
|
+
Register the body inline, or create the fragment at the ACCOUNT tier with a fetch-via workspace.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
// deployment entry, before start()/startLocal()
|
|
128
|
+
import { promptFragmentRegistryWithBuiltins } from '@cat-factory/prompt-fragments'
|
|
129
|
+
|
|
130
|
+
const promptFragmentRegistry = promptFragmentRegistryWithBuiltins()
|
|
131
|
+
promptFragmentRegistry.registerAll([
|
|
132
|
+
{
|
|
133
|
+
id: 'org.review-checklist',
|
|
134
|
+
version: '1.0.0',
|
|
135
|
+
title: 'Review checklist',
|
|
136
|
+
summary: 'Our PR review bar.',
|
|
137
|
+
body: '- Check error handling…',
|
|
138
|
+
},
|
|
139
|
+
])
|
|
140
|
+
// every new REVIEW task starts with this guidance
|
|
141
|
+
promptFragmentRegistry.registerTaskTypeDefaults('review', ['org.review-checklist'])
|
|
142
|
+
|
|
143
|
+
// …and the SAME instance goes into the facade, which is the whole point.
|
|
144
|
+
start({ promptFragmentRegistry /* …the rest */ })
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**In MOTHERSHIP mode the pool is read from the mothership**, not from the node's own registry: the
|
|
148
|
+
standards are org state, and a node one build behind would otherwise fold different guidance than
|
|
149
|
+
the deployment registered. A failed read THROWS rather than answering with an empty pool, because
|
|
150
|
+
"the mothership is unreachable" and "this deployment registers no standards" are the same value and
|
|
151
|
+
opposite facts. Boot warns and names any fragments registered on a mothership-mode node.
|
|
152
|
+
|
|
153
|
+
## Adding a collection
|
|
154
|
+
|
|
155
|
+
1. Create `src/collections/<topic>.ts` and export an array of `PromptFragment`.
|
|
156
|
+
2. Spread it into `FRAGMENTS` in `src/index.ts`.
|
|
157
|
+
3. Keep ids **globally unique and stable**: blocks persist them, so a renamed id
|
|
158
|
+
silently drops a selection (unknown ids are skipped, never error).
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pnpm --filter @cat-factory/prompt-fragments build # tsc → dist/
|
|
162
|
+
pnpm --filter @cat-factory/prompt-fragments typecheck
|
|
163
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../../src/collections/acceptance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAU5D,eAAO,MAAM,mBAAmB,EAAE,cAAc,EAuD/C,CAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Best-practice fragments for the acceptance-testing track: authoring the
|
|
2
|
+
// structured Given/When/Then acceptance scenarios as part of the service spec (the
|
|
3
|
+
// `spec-writer`), and turning the derived Gherkin into runnable tests (the
|
|
4
|
+
// `playwright` step). The runnable-tests step uses Playwright for user-facing blocks
|
|
5
|
+
// and the project's own test framework for backend blocks, so there is one fragment
|
|
6
|
+
// per surface, scoped by block type. Selected per block, these bodies are injected
|
|
7
|
+
// verbatim into the relevant agents' system prompts.
|
|
8
|
+
export const acceptanceFragments = [
|
|
9
|
+
{
|
|
10
|
+
id: 'acceptance.scenarios',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
title: 'Acceptance scenarios',
|
|
13
|
+
category: 'Acceptance testing',
|
|
14
|
+
summary: 'Given/When/Then scenarios tied to requirements, asserting observable behaviour.',
|
|
15
|
+
body: [
|
|
16
|
+
'Acceptance scenario standards:',
|
|
17
|
+
'- Trace every scenario back to a stated requirement; do not test behaviour nobody asked for.',
|
|
18
|
+
'- Write each scenario as a titled Given / When / Then with a single clear When and concrete, observable Then assertions.',
|
|
19
|
+
'- Cover the happy path, the meaningful alternative flows, error handling and boundary conditions — in that order of priority.',
|
|
20
|
+
'- Keep scenarios independent and deterministic: each sets up its own state and asserts user-visible outcomes, never internals.',
|
|
21
|
+
'- Call out any requirement that is ambiguous or untestable instead of guessing at the intended behaviour.',
|
|
22
|
+
].join('\n'),
|
|
23
|
+
appliesTo: { agentKinds: ['spec-writer'] },
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'playwright.e2e',
|
|
27
|
+
version: '1.0.0',
|
|
28
|
+
title: 'Playwright end-to-end tests',
|
|
29
|
+
category: 'Acceptance testing',
|
|
30
|
+
summary: 'User-facing locators, web-first assertions, isolated and idempotent test files.',
|
|
31
|
+
body: [
|
|
32
|
+
'Playwright end-to-end test standards:',
|
|
33
|
+
'- Map one `test` to one acceptance scenario and name it after the scenario so coverage is traceable.',
|
|
34
|
+
'- Be additive: only add tests for scenarios that lack one; never duplicate or silently rewrite an existing test.',
|
|
35
|
+
'- Select elements by user-facing locators (getByRole, getByLabel, getByText), not brittle CSS or XPath.',
|
|
36
|
+
'- Rely on web-first auto-retrying assertions (expect(locator)…) and await every action; never use fixed sleeps.',
|
|
37
|
+
'- Keep each test isolated and deterministic — fresh state per test, no ordering dependencies between tests.',
|
|
38
|
+
'- Target the environment URL from the run context and read credentials from the harness; never hard-code secrets or hosts.',
|
|
39
|
+
].join('\n'),
|
|
40
|
+
appliesTo: { blockTypes: ['frontend', 'environment'], agentKinds: ['playwright'] },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'acceptance.backend-tests',
|
|
44
|
+
version: '1.0.0',
|
|
45
|
+
title: 'Backend acceptance tests',
|
|
46
|
+
category: 'Acceptance testing',
|
|
47
|
+
summary: "Acceptance tests in the project's own framework, driven through public backend interfaces.",
|
|
48
|
+
body: [
|
|
49
|
+
'Backend acceptance test standards:',
|
|
50
|
+
"- Write the tests with the project's existing test framework — discover it from the repo (test config, dev dependencies, the tests already present); do not introduce a new framework, and do not use Playwright or a browser for behaviour with no UI.",
|
|
51
|
+
'- Map one test to one acceptance scenario and name it after the scenario so coverage is traceable.',
|
|
52
|
+
'- Be additive: only add tests for scenarios that lack one; never duplicate or silently rewrite an existing test.',
|
|
53
|
+
'- Drive the system through its outermost public interface (HTTP/API calls, queue messages, exported functions) and assert on observable behaviour, never on internals.',
|
|
54
|
+
'- Keep each test isolated and deterministic — fresh state per test, no ordering dependencies; await async work instead of fixed sleeps.',
|
|
55
|
+
'- Target the system at the URL / entry point from the run context and read credentials from the harness; never hard-code secrets or hosts.',
|
|
56
|
+
].join('\n'),
|
|
57
|
+
appliesTo: {
|
|
58
|
+
blockTypes: ['service', 'api', 'database', 'queue', 'integration', 'external'],
|
|
59
|
+
agentKinds: ['playwright'],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
//# sourceMappingURL=acceptance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../../src/collections/acceptance.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,mFAAmF;AACnF,2EAA2E;AAC3E,qFAAqF;AACrF,oFAAoF;AACpF,mFAAmF;AACnF,qDAAqD;AAErD,MAAM,CAAC,MAAM,mBAAmB,GAAqB;IACnD;QACE,EAAE,EAAE,sBAAsB;QAC1B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,oBAAoB;QAC9B,OAAO,EAAE,iFAAiF;QAC1F,IAAI,EAAE;YACJ,gCAAgC;YAChC,8FAA8F;YAC9F,0HAA0H;YAC1H,+HAA+H;YAC/H,gIAAgI;YAChI,2GAA2G;SAC5G,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE;KAC3C;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,6BAA6B;QACpC,QAAQ,EAAE,oBAAoB;QAC9B,OAAO,EAAE,iFAAiF;QAC1F,IAAI,EAAE;YACJ,uCAAuC;YACvC,sGAAsG;YACtG,kHAAkH;YAClH,yGAAyG;YACzG,iHAAiH;YACjH,6GAA6G;YAC7G,4HAA4H;SAC7H,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;KACnF;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,0BAA0B;QACjC,QAAQ,EAAE,oBAAoB;QAC9B,OAAO,EACL,4FAA4F;QAC9F,IAAI,EAAE;YACJ,oCAAoC;YACpC,yPAAyP;YACzP,oGAAoG;YACpG,kHAAkH;YAClH,wKAAwK;YACxK,yIAAyI;YACzI,4IAA4I;SAC7I,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,SAAS,EAAE;YACT,UAAU,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC;YAC9E,UAAU,EAAE,CAAC,YAAY,CAAC;SAC3B;KACF;CACF,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PromptFragment } from '@cat-factory/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* The one fragment that tells an agent how to consume materialised design context.
|
|
4
|
+
*
|
|
5
|
+
* Named as a constant because the ENGINE folds it by presence rather than by selection: a run whose
|
|
6
|
+
* resolved context carries a design-origin document gets it automatically
|
|
7
|
+
* ({@link withDesignContextFragment}). Before that it was auto-selected by nothing — the `appliesTo`
|
|
8
|
+
* selector below is a management-surface hint the run path never drove, the fragment is in no seed pin
|
|
9
|
+
* set, and basic mode hides the per-task fragment picker — so the standard case (a designer links a
|
|
10
|
+
* Figma frame and starts a run) executed with a design context file on disk and no instruction
|
|
11
|
+
* anywhere to honour it.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DESIGN_CONTEXT_FRAGMENT_ID = "design.context";
|
|
14
|
+
/**
|
|
15
|
+
* The applicable fragment ids for a run, plus `design.context` when that run actually carries a
|
|
16
|
+
* design document. PURE, and the ONLY place the presence rule lives.
|
|
17
|
+
*
|
|
18
|
+
* A deterministic presence rule at prompt assembly, deliberately NOT a revival of the retired
|
|
19
|
+
* `appliesTo` run-path selector: the trigger is the design document the run resolved, so it cannot
|
|
20
|
+
* drift from what is on disk — whereas a `blockTypes: ['frontend']` selector both misses a design
|
|
21
|
+
* linked to an unlabelled task and fires on a frontend task with no design at all.
|
|
22
|
+
*
|
|
23
|
+
* Appended LAST and only when not already present, so a workspace that pins the fragment explicitly
|
|
24
|
+
* (or overrides it in its own catalog) keeps its position and its single entry.
|
|
25
|
+
*/
|
|
26
|
+
export declare function withDesignContextFragment(ids: readonly string[], hasDesignContext: boolean): string[];
|
|
27
|
+
export declare const designFragments: PromptFragment[];
|
|
28
|
+
//# sourceMappingURL=design.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/collections/design.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAQ5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,0BAA0B,mBAAmB,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,SAAS,MAAM,EAAE,EACtB,gBAAgB,EAAE,OAAO,GACxB,MAAM,EAAE,CAGV;AAED,eAAO,MAAM,eAAe,EAAE,cAAc,EA+B3C,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Best-practice fragment for working from linked design context. Source-neutral: every
|
|
2
|
+
// design document source (Figma, Zeplin, …) materialises its frames/screens, component
|
|
3
|
+
// inventory and design tokens into `.cat-context/*.md` in the SAME shape (`## <block>`
|
|
4
|
+
// blocks, a global `### Components`, `### Design tokens`, optional `### References`), so
|
|
5
|
+
// one fragment serves them all — the agent doesn't need to know which tool authored it.
|
|
6
|
+
/**
|
|
7
|
+
* The one fragment that tells an agent how to consume materialised design context.
|
|
8
|
+
*
|
|
9
|
+
* Named as a constant because the ENGINE folds it by presence rather than by selection: a run whose
|
|
10
|
+
* resolved context carries a design-origin document gets it automatically
|
|
11
|
+
* ({@link withDesignContextFragment}). Before that it was auto-selected by nothing — the `appliesTo`
|
|
12
|
+
* selector below is a management-surface hint the run path never drove, the fragment is in no seed pin
|
|
13
|
+
* set, and basic mode hides the per-task fragment picker — so the standard case (a designer links a
|
|
14
|
+
* Figma frame and starts a run) executed with a design context file on disk and no instruction
|
|
15
|
+
* anywhere to honour it.
|
|
16
|
+
*/
|
|
17
|
+
export const DESIGN_CONTEXT_FRAGMENT_ID = 'design.context';
|
|
18
|
+
/**
|
|
19
|
+
* The applicable fragment ids for a run, plus `design.context` when that run actually carries a
|
|
20
|
+
* design document. PURE, and the ONLY place the presence rule lives.
|
|
21
|
+
*
|
|
22
|
+
* A deterministic presence rule at prompt assembly, deliberately NOT a revival of the retired
|
|
23
|
+
* `appliesTo` run-path selector: the trigger is the design document the run resolved, so it cannot
|
|
24
|
+
* drift from what is on disk — whereas a `blockTypes: ['frontend']` selector both misses a design
|
|
25
|
+
* linked to an unlabelled task and fires on a frontend task with no design at all.
|
|
26
|
+
*
|
|
27
|
+
* Appended LAST and only when not already present, so a workspace that pins the fragment explicitly
|
|
28
|
+
* (or overrides it in its own catalog) keeps its position and its single entry.
|
|
29
|
+
*/
|
|
30
|
+
export function withDesignContextFragment(ids, hasDesignContext) {
|
|
31
|
+
if (!hasDesignContext || ids.includes(DESIGN_CONTEXT_FRAGMENT_ID))
|
|
32
|
+
return [...ids];
|
|
33
|
+
return [...ids, DESIGN_CONTEXT_FRAGMENT_ID];
|
|
34
|
+
}
|
|
35
|
+
export const designFragments = [
|
|
36
|
+
{
|
|
37
|
+
id: DESIGN_CONTEXT_FRAGMENT_ID,
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
title: 'Design context',
|
|
40
|
+
category: 'Design',
|
|
41
|
+
summary: 'Build UI from the linked design (Figma, Zeplin, …): reuse existing components and honour design tokens.',
|
|
42
|
+
body: [
|
|
43
|
+
'A design for this task has been materialised into the `.cat-context/` directory: one or more',
|
|
44
|
+
'`## <frame/screen>` blocks (each with a `### Layout` and/or `### Text content`), a global',
|
|
45
|
+
'`### Components` inventory, and `### Design tokens`. When implementing UI, use it as the source of',
|
|
46
|
+
'truth for structure and styling:',
|
|
47
|
+
'- Read each block’s `### Layout` as the component/element structure to build — follow its nesting and naming.',
|
|
48
|
+
'- Before creating a new component, check the `### Components` inventory against the components that already',
|
|
49
|
+
' exist in this repository and REUSE the existing one when it matches; do not reinvent it.',
|
|
50
|
+
'- Honour the `### Design tokens` values (colours, spacing, typography) instead of hard-coding ad-hoc',
|
|
51
|
+
' values; map them to the project’s existing token/theme system where one exists.',
|
|
52
|
+
'- `### Text content` is the screen’s copy/intent, not markup to paste verbatim.',
|
|
53
|
+
'- Any `### References` URL (e.g. a rendered preview) is reference-only — do not depend on fetching it; the',
|
|
54
|
+
' textual layout/text/tokens above are the authoritative description.',
|
|
55
|
+
].join('\n'),
|
|
56
|
+
brief: 'Design context: build UI from the `.cat-context/` design — follow each block’s `### Layout` for structure; reuse an existing repo component before creating one from the `### Components` inventory; honour `### Design tokens` via the project’s theme system instead of ad-hoc values; `### Text content` is copy, not markup; `### References` URLs are reference-only.',
|
|
57
|
+
// No `appliesTo`. The selector this fragment used to carry (`blockTypes: ['frontend']`) was
|
|
58
|
+
// wrong in both directions (it missed a design linked to an unlabelled task and fired on a
|
|
59
|
+
// frontend task with no design), and {@link withDesignContextFragment} replaced it. Leaving it
|
|
60
|
+
// beside the presence rule would keep the old behaviour alive wherever `appliesTo` is still
|
|
61
|
+
// read (the deterministic selector, the catalog gate, the management surface, which would go on
|
|
62
|
+
// labelling this frontend-only while the engine folds it for any block type carrying a design).
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
//# sourceMappingURL=design.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/collections/design.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,uFAAuF;AACvF,uFAAuF;AACvF,yFAAyF;AACzF,wFAAwF;AAExF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAAsB,EACtB,gBAAyB;IAEzB,IAAI,CAAC,gBAAgB,IAAI,GAAG,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QAAE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAA;IAClF,OAAO,CAAC,GAAG,GAAG,EAAE,0BAA0B,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAqB;IAC/C;QACE,EAAE,EAAE,0BAA0B;QAC9B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,QAAQ;QAClB,OAAO,EACL,yGAAyG;QAC3G,IAAI,EAAE;YACJ,8FAA8F;YAC9F,2FAA2F;YAC3F,oGAAoG;YACpG,kCAAkC;YAClC,+GAA+G;YAC/G,6GAA6G;YAC7G,4FAA4F;YAC5F,sGAAsG;YACtG,mFAAmF;YACnF,iFAAiF;YACjF,4GAA4G;YAC5G,uEAAuE;SACxE,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,4WAA4W;QAC9W,4FAA4F;QAC5F,2FAA2F;QAC3F,+FAA+F;QAC/F,4FAA4F;QAC5F,gGAAgG;QAChG,gGAAgG;KACjG;CACF,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PromptFragment } from '@cat-factory/contracts';
|
|
2
|
+
export declare const migrationFragments: PromptFragment[];
|
|
3
|
+
/**
|
|
4
|
+
* The ids of the migration fragments, in catalog order — the single source of truth for "which
|
|
5
|
+
* best-practice fragments a technological migration applies by default". Derived from
|
|
6
|
+
* {@link migrationFragments} so it can never drift from the definitions. Consumed by the
|
|
7
|
+
* `preset_tech_migration` preset's descriptor `defaultFragmentIds` (T8, the workspace default set).
|
|
8
|
+
*/
|
|
9
|
+
export declare const MIGRATION_FRAGMENT_IDS: readonly string[];
|
|
10
|
+
/**
|
|
11
|
+
* The migration fragment ids that apply to `agentKind`, in catalog order — the subset whose
|
|
12
|
+
* `appliesTo.agentKinds` includes the kind (a fragment with no `appliesTo` restriction applies to
|
|
13
|
+
* all). This RESPECTS each fragment's declared scoping, which the manual per-block `fragmentIds`
|
|
14
|
+
* pin path does NOT (the run-time resolver folds pinned bodies in unconditionally — only the
|
|
15
|
+
* automatic service-fragment selector consults `appliesTo`). `seedMigrationPlan` (T7) stamps this
|
|
16
|
+
* per item keyed off the item's PRIMARY producer (`coder` for coding items, `doc-writer` for the
|
|
17
|
+
* document items), so a doc task no longer receives the coding-only behaviour-preservation standard.
|
|
18
|
+
*/
|
|
19
|
+
export declare function migrationFragmentIdsFor(agentKind: string): string[];
|
|
20
|
+
//# sourceMappingURL=migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/collections/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAsB5D,eAAO,MAAM,kBAAkB,EAAE,cAAc,EA+D9C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAwC,CAAA;AAE5F;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAInE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Best-practice fragments for a TECHNOLOGICAL MIGRATION — swapping a load-bearing
|
|
2
|
+
// technology (a database engine, a framework major, a language runtime, a core
|
|
3
|
+
// library) behind a behaviour-preservation safety net. These are the default
|
|
4
|
+
// fragments the `preset_tech_migration` initiative preset applies to the coding,
|
|
5
|
+
// testing and document agents it spawns, so each body is written to steer WHATEVER
|
|
6
|
+
// agent carries out a slice of a migration — hence the deliberately broad `appliesTo`
|
|
7
|
+
// (a migration touches services, APIs, databases and libraries alike).
|
|
8
|
+
//
|
|
9
|
+
// Three concerns, one fragment each:
|
|
10
|
+
// - `migration.discipline` — the invariant methodology (blast zone →
|
|
11
|
+
// coverage → transition → delivery → decommission; coverage BEFORE delivery).
|
|
12
|
+
// - `migration.behaviour-preservation` — how to pin observable behaviour so the
|
|
13
|
+
// swap is provably behaviour-neutral (outcomes at a seam, never internals).
|
|
14
|
+
// - `migration.confidence-case` — the authoring standard for the
|
|
15
|
+
// evidence-backed coverage/confidence proof a human audits before delivery.
|
|
16
|
+
//
|
|
17
|
+
// The deep, phase-by-phase methodology (what a blast-zone report must enumerate, item
|
|
18
|
+
// granularity) lives code-side in the preset's `promptAdditions`, NOT here — these are
|
|
19
|
+
// the durable standards an agent follows while doing the work.
|
|
20
|
+
export const migrationFragments = [
|
|
21
|
+
{
|
|
22
|
+
id: 'migration.discipline',
|
|
23
|
+
version: '1.0.0',
|
|
24
|
+
title: 'Migration discipline',
|
|
25
|
+
category: 'Migration',
|
|
26
|
+
summary: 'Know the blast zone, pin behaviour before the swap, deliver incrementally, then remove the old path.',
|
|
27
|
+
body: [
|
|
28
|
+
'Technological-migration discipline:',
|
|
29
|
+
'- What makes a migration safe is the discipline around it, not the code change: know the blast zone, pin behaviour, then swap — in that order.',
|
|
30
|
+
'- Establish the full blast zone before touching anything: every directly affected touchpoint AND its transitive reach (callers of callers, config, scheduled jobs, ops tooling, CI).',
|
|
31
|
+
'- Pin observable behaviour with tests BEFORE the swap. Coverage comes before delivery — never migrate code whose behaviour is not already characterised and green on the current technology.',
|
|
32
|
+
'- Decide the degree of backwards compatibility deliberately (big-bang vs dual-run vs adapter layer) and state it; do not let it emerge by accident.',
|
|
33
|
+
'- Deliver in small increments grouped by area, keeping the behaviour suite green on both the old and the new technology throughout — a red suite halts the migration.',
|
|
34
|
+
'- Finish the job: prove parity on the new target, flip the defaults, and REMOVE the old path. A migration that leaves the legacy code and its dependencies behind is not done.',
|
|
35
|
+
'- Record every non-obvious choice (a strategy per object, a retained legacy path, a compat posture) as an explicit decision, not a silent edit.',
|
|
36
|
+
].join('\n'),
|
|
37
|
+
brief: 'Migration discipline: establish the full blast zone (incl. transitive callers, config, jobs, CI) first; pin observable behaviour with green tests BEFORE the swap; state the compatibility posture deliberately; deliver in small increments keeping the suite green on both technologies; finish by proving parity, flipping defaults and REMOVING the old path; record every non-obvious choice as an explicit decision.',
|
|
38
|
+
appliesTo: { agentKinds: ['spec-writer', 'architect', 'coder', 'tester', 'doc-writer'] },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'migration.behaviour-preservation',
|
|
42
|
+
version: '1.0.0',
|
|
43
|
+
title: 'Behaviour preservation',
|
|
44
|
+
category: 'Migration',
|
|
45
|
+
summary: 'Pin observable outcomes at a seam above the swapped layer — never assert internals or vendor mechanics.',
|
|
46
|
+
body: [
|
|
47
|
+
'Behaviour-preservation standards for a migration:',
|
|
48
|
+
'- Write characterization tests at a seam ABOVE the layer being swapped (the API / service / repository boundary) so they survive the swap unchanged and prove the new technology behaves identically.',
|
|
49
|
+
'- Assert observable OUTCOMES, never internals or mechanisms: do not assert raw vendor error codes, implicit result ordering, or locking/isolation mechanics — assert the outcome a caller sees (the mapped error, an explicitly ordered result, the final committed state).',
|
|
50
|
+
'- Preserve the edge-case semantics that silently differ between technologies: NULL vs empty string, numeric/datetime precision and rounding, string collation and case/trailing-space comparison, pagination stability, and any identity/sequence values that leak into responses.',
|
|
51
|
+
'- Keep set-based work set-based. When replacing a set-based operation (a bulk statement, a set-based stored procedure) with application code, express it as one batched operation — NEVER an app-side per-row loop, which is an N+1 regression the old path did not have.',
|
|
52
|
+
'- Establish the baseline first: the behaviour suite must be green on the CURRENT technology before any migration code lands, so a later failure unambiguously means the swap changed behaviour.',
|
|
53
|
+
'- Be additive and traceable: add tests for behaviour that lacks coverage, name each test after the behaviour it pins, and never weaken or delete an existing assertion to make the new target pass.',
|
|
54
|
+
].join('\n'),
|
|
55
|
+
brief: 'Behaviour preservation: characterize at a seam ABOVE the swapped layer so tests survive it; assert observable outcomes, never vendor error codes, implicit ordering or locking mechanics; preserve silently-differing edge semantics (NULL vs empty, precision/rounding, collation, pagination stability, leaked identity values); keep set-based work batched, never an app-side per-row loop; baseline green on the current technology first; be additive — never weaken an assertion to make the new target pass.',
|
|
56
|
+
appliesTo: { agentKinds: ['spec-writer', 'coder', 'tester', 'playwright'] },
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'migration.confidence-case',
|
|
60
|
+
version: '1.0.0',
|
|
61
|
+
title: 'Confidence-case authoring',
|
|
62
|
+
category: 'Migration',
|
|
63
|
+
summary: 'Author the coverage proof as evidence a human audits: per-touchpoint named tests, justified gaps, safety nets.',
|
|
64
|
+
body: [
|
|
65
|
+
'Confidence-case authoring standard:',
|
|
66
|
+
'The confidence case is an evidence-backed proof that coverage is sufficient for delivery — a human reviews and challenges it, they do not re-derive the sweep. Every claim must be grounded; hand-waving is grounds for rejection, not a passing case. Structure it as:',
|
|
67
|
+
'1. Expected blast zone — recap the touchpoint inventory and call out any deltas discovered since it was written.',
|
|
68
|
+
'2. Coverage grounding — a per-touchpoint map: each inventory row to the NAMED tests that cover it and WHAT observable behaviour each test pins. Cite real test names and real touchpoints; a row with no evidence is a gap, not covered.',
|
|
69
|
+
'3. Gaps and waivers — every uncovered or partially-covered touchpoint, each with an explicit justification, bounded by the stated coverage bar (strict = every touchpoint has a named covering test; pragmatic = waivers allowed, each justified).',
|
|
70
|
+
'4. Risk mitigations — what was done to reduce the migration risk (staged rollout, seam isolation, rehearsal).',
|
|
71
|
+
'5. Safety nets and safeguards — the dual-target test harness, the CI legs, the rollback / compatibility posture, and the gated delivery batches.',
|
|
72
|
+
'- Be the single writer of the confidence-case document: append to it, never fork a parallel copy, and keep it the one source of the safety argument.',
|
|
73
|
+
].join('\n'),
|
|
74
|
+
brief: 'Confidence case: an evidence-backed proof a human audits, not a re-derivation — cover (1) expected blast zone plus deltas found since, (2) per-touchpoint coverage grounded in NAMED real tests and what each pins (an ungrounded row is a gap), (3) gaps/waivers each justified against the stated coverage bar, (4) risk mitigations, (5) safety nets (dual-target harness, CI legs, rollback posture, gated batches). Append to the one document; never fork a parallel copy.',
|
|
75
|
+
appliesTo: { agentKinds: ['coder', 'doc-writer'] },
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
/**
|
|
79
|
+
* The ids of the migration fragments, in catalog order — the single source of truth for "which
|
|
80
|
+
* best-practice fragments a technological migration applies by default". Derived from
|
|
81
|
+
* {@link migrationFragments} so it can never drift from the definitions. Consumed by the
|
|
82
|
+
* `preset_tech_migration` preset's descriptor `defaultFragmentIds` (T8, the workspace default set).
|
|
83
|
+
*/
|
|
84
|
+
export const MIGRATION_FRAGMENT_IDS = migrationFragments.map((f) => f.id);
|
|
85
|
+
/**
|
|
86
|
+
* The migration fragment ids that apply to `agentKind`, in catalog order — the subset whose
|
|
87
|
+
* `appliesTo.agentKinds` includes the kind (a fragment with no `appliesTo` restriction applies to
|
|
88
|
+
* all). This RESPECTS each fragment's declared scoping, which the manual per-block `fragmentIds`
|
|
89
|
+
* pin path does NOT (the run-time resolver folds pinned bodies in unconditionally — only the
|
|
90
|
+
* automatic service-fragment selector consults `appliesTo`). `seedMigrationPlan` (T7) stamps this
|
|
91
|
+
* per item keyed off the item's PRIMARY producer (`coder` for coding items, `doc-writer` for the
|
|
92
|
+
* document items), so a doc task no longer receives the coding-only behaviour-preservation standard.
|
|
93
|
+
*/
|
|
94
|
+
export function migrationFragmentIdsFor(agentKind) {
|
|
95
|
+
return migrationFragments
|
|
96
|
+
.filter((f) => !f.appliesTo?.agentKinds || f.appliesTo.agentKinds.includes(agentKind))
|
|
97
|
+
.map((f) => f.id);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/collections/migration.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,+EAA+E;AAC/E,6EAA6E;AAC7E,iFAAiF;AACjF,mFAAmF;AACnF,sFAAsF;AACtF,uEAAuE;AACvE,EAAE;AACF,qCAAqC;AACrC,mFAAmF;AACnF,kFAAkF;AAClF,kFAAkF;AAClF,gFAAgF;AAChF,0EAA0E;AAC1E,gFAAgF;AAChF,EAAE;AACF,sFAAsF;AACtF,uFAAuF;AACvF,+DAA+D;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAqB;IAClD;QACE,EAAE,EAAE,sBAAsB;QAC1B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,WAAW;QACrB,OAAO,EACL,sGAAsG;QACxG,IAAI,EAAE;YACJ,qCAAqC;YACrC,gJAAgJ;YAChJ,sLAAsL;YACtL,8LAA8L;YAC9L,qJAAqJ;YACrJ,uKAAuK;YACvK,gLAAgL;YAChL,iJAAiJ;SAClJ,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,4ZAA4Z;QAC9Z,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE;KACzF;IACD;QACE,EAAE,EAAE,kCAAkC;QACtC,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,WAAW;QACrB,OAAO,EACL,yGAAyG;QAC3G,IAAI,EAAE;YACJ,mDAAmD;YACnD,uMAAuM;YACvM,6QAA6Q;YAC7Q,oRAAoR;YACpR,2QAA2Q;YAC3Q,iMAAiM;YACjM,qMAAqM;SACtM,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,sfAAsf;QACxf,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE;KAC5E;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,WAAW;QACrB,OAAO,EACL,gHAAgH;QAClH,IAAI,EAAE;YACJ,qCAAqC;YACrC,yQAAyQ;YACzQ,kHAAkH;YAClH,0OAA0O;YAC1O,oPAAoP;YACpP,+GAA+G;YAC/G,kJAAkJ;YAClJ,sJAAsJ;SACvJ,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,kdAAkd;QACpd,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE;KACnD;CACF,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AAE5F;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,OAAO,kBAAkB;SACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;SACrF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/collections/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAM5D,eAAO,MAAM,aAAa,EAAE,cAAc,EAqCzC,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Best-practice fragments for Node.js / backend work. Each fragment's `body` is
|
|
2
|
+
// injected verbatim into the agent system prompt when selected, so keep it
|
|
3
|
+
// concise, imperative and standalone.
|
|
4
|
+
export const nodeFragments = [
|
|
5
|
+
{
|
|
6
|
+
id: 'node.performance',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
title: 'Node.js performance',
|
|
9
|
+
category: 'Node',
|
|
10
|
+
summary: 'Avoid event-loop blocking, stream large payloads, cache hot paths.',
|
|
11
|
+
body: [
|
|
12
|
+
'Node.js performance standards:',
|
|
13
|
+
'- Never block the event loop: move CPU-bound work to worker threads or break it into async chunks.',
|
|
14
|
+
'- Prefer streaming (Readable/Writable streams) over buffering large payloads in memory.',
|
|
15
|
+
'- Reuse connections and clients (HTTP agents, DB pools); do not create them per request.',
|
|
16
|
+
'- Cache expensive, idempotent computations and hot lookups; set explicit TTLs.',
|
|
17
|
+
'- Measure before optimising: profile with --prof / clinic and quote concrete numbers, not guesses.',
|
|
18
|
+
].join('\n'),
|
|
19
|
+
brief: 'Node performance: never block the event loop (offload CPU-bound work); stream large payloads instead of buffering; reuse pooled clients/connections; cache hot idempotent lookups with TTLs; profile before optimising.',
|
|
20
|
+
appliesTo: { blockTypes: ['service', 'api', 'queue', 'integration'] },
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'node.best-practices',
|
|
24
|
+
version: '1.0.0',
|
|
25
|
+
title: 'Node.js best practices',
|
|
26
|
+
category: 'Node',
|
|
27
|
+
summary: 'Async/await error handling, config via env, structured logging, graceful shutdown.',
|
|
28
|
+
body: [
|
|
29
|
+
'Node.js best practices:',
|
|
30
|
+
'- Use async/await with explicit try/catch; never leave promises unhandled.',
|
|
31
|
+
'- Read configuration from the environment; never hard-code secrets or hosts.',
|
|
32
|
+
'- Validate all external input at the boundary before it reaches domain logic.',
|
|
33
|
+
'- Emit structured (JSON) logs with correlation ids; do not log secrets.',
|
|
34
|
+
'- Handle SIGTERM/SIGINT for graceful shutdown: stop accepting work, drain, then exit.',
|
|
35
|
+
].join('\n'),
|
|
36
|
+
brief: 'Node best practices: async/await with try/catch (no unhandled promises); config from env, never hard-code secrets; validate external input at the boundary; structured logs with correlation ids, never secrets; graceful SIGTERM/SIGINT shutdown.',
|
|
37
|
+
appliesTo: { blockTypes: ['service', 'api', 'queue', 'integration', 'external'] },
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/collections/node.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,2EAA2E;AAC3E,sCAAsC;AAEtC,MAAM,CAAC,MAAM,aAAa,GAAqB;IAC7C;QACE,EAAE,EAAE,kBAAkB;QACtB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,oEAAoE;QAC7E,IAAI,EAAE;YACJ,gCAAgC;YAChC,oGAAoG;YACpG,yFAAyF;YACzF,0FAA0F;YAC1F,gFAAgF;YAChF,oGAAoG;SACrG,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,yNAAyN;QAC3N,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE;KACtE;IACD;QACE,EAAE,EAAE,qBAAqB;QACzB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,oFAAoF;QAC7F,IAAI,EAAE;YACJ,yBAAyB;YACzB,4EAA4E;YAC5E,8EAA8E;YAC9E,+EAA+E;YAC/E,yEAAyE;YACzE,uFAAuF;SACxF,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,oPAAoP;QACtP,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE;KAClF;CACF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/collections/react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAI5D,eAAO,MAAM,cAAc,EAAE,cAAc,EAmB1C,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Best-practice fragments for React / frontend work.
|
|
2
|
+
export const reactFragments = [
|
|
3
|
+
{
|
|
4
|
+
id: 'react.state-management',
|
|
5
|
+
version: '1.0.0',
|
|
6
|
+
title: 'React state management',
|
|
7
|
+
category: 'React',
|
|
8
|
+
summary: 'Keep state local, lift only when shared, derive instead of duplicating.',
|
|
9
|
+
body: [
|
|
10
|
+
'React state management standards:',
|
|
11
|
+
'- Keep state as local as possible; lift it up only when two components genuinely share it.',
|
|
12
|
+
'- Derive values during render instead of storing duplicated/denormalised state.',
|
|
13
|
+
'- Reach for a global store only for truly cross-cutting state; prefer context/props otherwise.',
|
|
14
|
+
'- Keep server state (fetched data) separate from UI state; use a data-fetching cache for it.',
|
|
15
|
+
'- Make effects depend on exactly what they use, and clean them up to avoid leaks.',
|
|
16
|
+
].join('\n'),
|
|
17
|
+
brief: 'React state: keep it local, lift only when genuinely shared; derive during render instead of duplicating; global store only for cross-cutting state; keep server state separate (data-fetching cache); effects depend on exactly what they use and clean up.',
|
|
18
|
+
appliesTo: { blockTypes: ['frontend'] },
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../../src/collections/react.ts"],"names":[],"mappings":"AAEA,qDAAqD;AAErD,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C;QACE,EAAE,EAAE,wBAAwB;QAC5B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,yEAAyE;QAClF,IAAI,EAAE;YACJ,mCAAmC;YACnC,4FAA4F;YAC5F,iFAAiF;YACjF,gGAAgG;YAChG,8FAA8F;YAC9F,mFAAmF;SACpF,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EACH,8PAA8P;QAChQ,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,UAAU,CAAC,EAAE;KACxC;CACF,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PromptFragment } from '@cat-factory/contracts';
|
|
2
|
+
export declare const styleFragments: PromptFragment[];
|
|
3
|
+
/**
|
|
4
|
+
* The style fragments a NEW document task is pre-seeded with (default-on, user-removable
|
|
5
|
+
* like any block pin). The source of truth for "which style fragments a document task
|
|
6
|
+
* starts with" — the board service seeds these onto a document task's `fragmentIds` at
|
|
7
|
+
* creation, so the `doc-aware` authoring/review kinds fold them in without the prompt
|
|
8
|
+
* hard-coding the guidance.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS: readonly string[];
|
|
11
|
+
//# sourceMappingURL=style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/collections/style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAY5D,eAAO,MAAM,cAAc,EAAE,cAAc,EA4C1C,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,EAAE,SAAS,MAAM,EAGhE,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Universal WRITING-STYLE fragments for the document-authoring track. Unlike the
|
|
2
|
+
// technical collections (node/react/acceptance/design), these are source- and
|
|
3
|
+
// stack-neutral: they govern HOW prose is written, not what a service is built with.
|
|
4
|
+
// They fold into the document-authoring kinds via the `doc-aware` trait (the same
|
|
5
|
+
// engine path `code-aware` uses for the technical fragments), and are pre-selected by
|
|
6
|
+
// default on a document task (see `DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS`), user-removable
|
|
7
|
+
// like any block pin. Because the `doc-reviewer` companion also carries `doc-aware`, the
|
|
8
|
+
// SAME bodies reach it as review criteria — style guidance is both an instruction to the
|
|
9
|
+
// writer and a check by the reviewer.
|
|
10
|
+
export const styleFragments = [
|
|
11
|
+
{
|
|
12
|
+
id: 'style.anti-llmisms',
|
|
13
|
+
version: '1.0.0',
|
|
14
|
+
title: 'Avoid LLM tells',
|
|
15
|
+
category: 'Writing style',
|
|
16
|
+
summary: 'Cut the machine-written tells: filler adverbs, hedging, throat-clearing, bullet inflation.',
|
|
17
|
+
body: [
|
|
18
|
+
'Write like a human editor, not a language model. Avoid the tells that mark machine-written prose:',
|
|
19
|
+
'- Drop filler intensifiers and cliches: "delve", "crucial", "vital", "seamless", "robust",',
|
|
20
|
+
' "leverage", "utilize" (write "use"), "in the realm of", "navigate the landscape",',
|
|
21
|
+
' "it is important to note", "it is worth noting", "when it comes to".',
|
|
22
|
+
'- Cut throat-clearing and hedging: "In today\'s fast-paced world", "As we all know",',
|
|
23
|
+
' "It goes without saying", "Needless to say", "Arguably", "In conclusion". State the point.',
|
|
24
|
+
'- No summary that merely restates what was just said, and no section that only previews',
|
|
25
|
+
' the next one. Every paragraph must add information.',
|
|
26
|
+
'- Do not inflate into bullet lists what is a sentence, and do not end every bullet with a',
|
|
27
|
+
' parallel flourish. Use a list only for genuinely enumerable items.',
|
|
28
|
+
'- Do not overuse em-dashes, rhetorical questions, or the "It\'s not just X, it\'s Y" frame.',
|
|
29
|
+
'- Prefer plain, specific words over vague grandeur. Concrete nouns and real numbers beat',
|
|
30
|
+
' adjectives. If a sentence survives deletion with no loss of meaning, delete it.',
|
|
31
|
+
].join('\n'),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'style.concise-actionable',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
title: 'Concise and actionable',
|
|
37
|
+
category: 'Writing style',
|
|
38
|
+
summary: 'Lead with the point, active voice, one idea per paragraph; every recommendation names an actor and an action.',
|
|
39
|
+
body: [
|
|
40
|
+
'Write to be read fast and acted on:',
|
|
41
|
+
'- Lead with the conclusion. Put the answer, decision, or recommendation in the first',
|
|
42
|
+
' sentence of a section, then support it. Do not build up to it.',
|
|
43
|
+
'- Active voice, present tense, second person where you address the reader. Name the actor:',
|
|
44
|
+
' "the operator restarts the worker", not "the worker should be restarted".',
|
|
45
|
+
'- One idea per paragraph; one job per sentence. Break a long sentence into short ones.',
|
|
46
|
+
'- Every recommendation is actionable: it names WHO does WHAT, and when it applies. Replace',
|
|
47
|
+
' "consideration should be given to caching" with "cache the catalog response for 60s".',
|
|
48
|
+
'- Prefer concrete examples, commands, and tables over abstract description.',
|
|
49
|
+
'- Cut ruthlessly. Say it once, in the fewest words that stay precise. Length is not thoroughness.',
|
|
50
|
+
].join('\n'),
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* The style fragments a NEW document task is pre-seeded with (default-on, user-removable
|
|
55
|
+
* like any block pin). The source of truth for "which style fragments a document task
|
|
56
|
+
* starts with" — the board service seeds these onto a document task's `fragmentIds` at
|
|
57
|
+
* creation, so the `doc-aware` authoring/review kinds fold them in without the prompt
|
|
58
|
+
* hard-coding the guidance.
|
|
59
|
+
*/
|
|
60
|
+
export const DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS = [
|
|
61
|
+
'style.anti-llmisms',
|
|
62
|
+
'style.concise-actionable',
|
|
63
|
+
];
|
|
64
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/collections/style.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,8EAA8E;AAC9E,qFAAqF;AACrF,kFAAkF;AAClF,sFAAsF;AACtF,yFAAyF;AACzF,yFAAyF;AACzF,yFAAyF;AACzF,sCAAsC;AAEtC,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C;QACE,EAAE,EAAE,oBAAoB;QACxB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,eAAe;QACzB,OAAO,EACL,4FAA4F;QAC9F,IAAI,EAAE;YACJ,mGAAmG;YACnG,4FAA4F;YAC5F,qFAAqF;YACrF,wEAAwE;YACxE,sFAAsF;YACtF,8FAA8F;YAC9F,yFAAyF;YACzF,uDAAuD;YACvD,2FAA2F;YAC3F,sEAAsE;YACtE,6FAA6F;YAC7F,0FAA0F;YAC1F,mFAAmF;SACpF,CAAC,IAAI,CAAC,IAAI,CAAC;KACb;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,eAAe;QACzB,OAAO,EACL,+GAA+G;QACjH,IAAI,EAAE;YACJ,qCAAqC;YACrC,sFAAsF;YACtF,kEAAkE;YAClE,4FAA4F;YAC5F,6EAA6E;YAC7E,wFAAwF;YACxF,4FAA4F;YAC5F,yFAAyF;YACzF,6EAA6E;YAC7E,mGAAmG;SACpG,CAAC,IAAI,CAAC,IAAI,CAAC;KACb;CACF,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAsB;IACpE,oBAAoB;IACpB,0BAA0B;CAC3B,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PromptFragment } from '@cat-factory/contracts';
|
|
2
|
+
import { PromptFragmentRegistry } from '@cat-factory/kernel';
|
|
3
|
+
export type { PromptFragment } from '@cat-factory/contracts';
|
|
4
|
+
export declare const FRAGMENTS: PromptFragment[];
|
|
5
|
+
export { styleFragments, DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
|
|
6
|
+
export { BUILTIN_TASK_TYPE_DEFAULTS } from './task-type-defaults.js';
|
|
7
|
+
export { MIGRATION_FRAGMENT_IDS, migrationFragmentIdsFor } from './collections/migration.js';
|
|
8
|
+
export { DESIGN_CONTEXT_FRAGMENT_ID, withDesignContextFragment } from './collections/design.js';
|
|
9
|
+
/** Fragments keyed by id for O(1) lookup during prompt composition. */
|
|
10
|
+
export declare const FRAGMENTS_BY_ID: ReadonlyMap<string, PromptFragment>;
|
|
11
|
+
/**
|
|
12
|
+
* A {@link PromptFragmentRegistry} carrying the SHIPPED catalog and its built-in per-task-type
|
|
13
|
+
* default sets. Each facade's composition root news one, and a deployment registers its own
|
|
14
|
+
* standards onto the same instance by reference.
|
|
15
|
+
*
|
|
16
|
+
* The built-ins install through the registry's ordinary public methods rather than being baked in,
|
|
17
|
+
* which is the `defaultGateRegistry()` ⇄ `@cat-factory/gates` shape: the platform exercises the
|
|
18
|
+
* consumer's own seam on every boot, so it cannot rot for consumers only. Registration order is
|
|
19
|
+
* what makes a deployment's re-registration of a shipped id an override, so the built-ins go first.
|
|
20
|
+
*
|
|
21
|
+
* This replaced two module globals (`registerPromptFragment`'s map and
|
|
22
|
+
* `registerTaskTypeDefaultFragments`') whose correctness depended on every reader resolving the
|
|
23
|
+
* same physical copy of this package. A `workspace:*` dependency publishes as an EXACT version, so
|
|
24
|
+
* a consumer floating the range onto a newer patch got two copies: the registration landed in one,
|
|
25
|
+
* the server read the other, and every task of the deployment's operation was seeded with ids that
|
|
26
|
+
* folded nothing. Injection by reference makes that unrepresentable.
|
|
27
|
+
*/
|
|
28
|
+
export declare function promptFragmentRegistryWithBuiltins(): PromptFragmentRegistry;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a fragment from the SHIPPED catalog by id, or `undefined`.
|
|
31
|
+
*
|
|
32
|
+
* Strictly the built-ins: a deployment's own fragments live on the injected registry, and the
|
|
33
|
+
* paths still calling this are the ones with no registry in hand (a prompt composed outside a
|
|
34
|
+
* container, a test harness). That narrowing is deliberate rather than a leftover. Before it,
|
|
35
|
+
* this function silently answered from a module global that a second copy of the package would
|
|
36
|
+
* have left empty, which is the whole failure the registry removes.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getFragment(id: string): PromptFragment | undefined;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,sBAAsB,EAAiC,MAAM,qBAAqB,CAAA;AAkB3F,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,eAAO,MAAM,SAAS,EAAE,cAAc,EAOrC,CAAA;AAKD,OAAO,EAAE,cAAc,EAAE,mCAAmC,EAAE,MAAM,wBAAwB,CAAA;AAG5F,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AAKpE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAI5F,OAAO,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAE/F,uEAAuE;AACvE,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAE/D,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kCAAkC,IAAI,sBAAsB,CAO3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAElE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { PromptFragmentRegistry, defaultPromptFragmentRegistry } from '@cat-factory/kernel';
|
|
2
|
+
import { BUILTIN_TASK_TYPE_DEFAULTS } from './task-type-defaults.js';
|
|
3
|
+
import { acceptanceFragments } from './collections/acceptance.js';
|
|
4
|
+
import { designFragments } from './collections/design.js';
|
|
5
|
+
import { migrationFragments } from './collections/migration.js';
|
|
6
|
+
import { nodeFragments } from './collections/node.js';
|
|
7
|
+
import { reactFragments } from './collections/react.js';
|
|
8
|
+
import { styleFragments } from './collections/style.js';
|
|
9
|
+
export const FRAGMENTS = [
|
|
10
|
+
...nodeFragments,
|
|
11
|
+
...reactFragments,
|
|
12
|
+
...acceptanceFragments,
|
|
13
|
+
...designFragments,
|
|
14
|
+
...styleFragments,
|
|
15
|
+
...migrationFragments,
|
|
16
|
+
];
|
|
17
|
+
// Re-export the writing-style collection + the document-task style defaults so a consumer (the
|
|
18
|
+
// board service seeding a new document task's fragments, the docs-refresh preset building its
|
|
19
|
+
// `styleFragments` form options) draws on the same source of truth the catalog is built from.
|
|
20
|
+
export { styleFragments, DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
|
|
21
|
+
// The built-in per-task-type default sets, installed onto a registry by
|
|
22
|
+
// `promptFragmentRegistryWithBuiltins` below.
|
|
23
|
+
export { BUILTIN_TASK_TYPE_DEFAULTS } from './task-type-defaults.js';
|
|
24
|
+
// Re-export the migration fragment ids so the `preset_tech_migration` preset draws its default
|
|
25
|
+
// fragment set from the same source of truth the catalog is built from: `MIGRATION_FRAGMENT_IDS`
|
|
26
|
+
// (T8's descriptor `defaultFragmentIds`) + `migrationFragmentIdsFor` (T7's `seedMigrationPlan`,
|
|
27
|
+
// which stamps the per-agent-kind subset that respects each fragment's `appliesTo`).
|
|
28
|
+
export { MIGRATION_FRAGMENT_IDS, migrationFragmentIdsFor } from './collections/migration.js';
|
|
29
|
+
// The design-context fragment's id + the engine's presence rule for folding it: a run whose resolved
|
|
30
|
+
// context carries a design-origin document reads the guidance automatically, rather than depending on
|
|
31
|
+
// a human having ticked it in a picker basic mode does not show.
|
|
32
|
+
export { DESIGN_CONTEXT_FRAGMENT_ID, withDesignContextFragment } from './collections/design.js';
|
|
33
|
+
/** Fragments keyed by id for O(1) lookup during prompt composition. */
|
|
34
|
+
export const FRAGMENTS_BY_ID = new Map(FRAGMENTS.map((fragment) => [fragment.id, fragment]));
|
|
35
|
+
/**
|
|
36
|
+
* A {@link PromptFragmentRegistry} carrying the SHIPPED catalog and its built-in per-task-type
|
|
37
|
+
* default sets. Each facade's composition root news one, and a deployment registers its own
|
|
38
|
+
* standards onto the same instance by reference.
|
|
39
|
+
*
|
|
40
|
+
* The built-ins install through the registry's ordinary public methods rather than being baked in,
|
|
41
|
+
* which is the `defaultGateRegistry()` ⇄ `@cat-factory/gates` shape: the platform exercises the
|
|
42
|
+
* consumer's own seam on every boot, so it cannot rot for consumers only. Registration order is
|
|
43
|
+
* what makes a deployment's re-registration of a shipped id an override, so the built-ins go first.
|
|
44
|
+
*
|
|
45
|
+
* This replaced two module globals (`registerPromptFragment`'s map and
|
|
46
|
+
* `registerTaskTypeDefaultFragments`') whose correctness depended on every reader resolving the
|
|
47
|
+
* same physical copy of this package. A `workspace:*` dependency publishes as an EXACT version, so
|
|
48
|
+
* a consumer floating the range onto a newer patch got two copies: the registration landed in one,
|
|
49
|
+
* the server read the other, and every task of the deployment's operation was seeded with ids that
|
|
50
|
+
* folded nothing. Injection by reference makes that unrepresentable.
|
|
51
|
+
*/
|
|
52
|
+
export function promptFragmentRegistryWithBuiltins() {
|
|
53
|
+
const registry = defaultPromptFragmentRegistry();
|
|
54
|
+
registry.registerAll(FRAGMENTS);
|
|
55
|
+
for (const [taskType, ids] of Object.entries(BUILTIN_TASK_TYPE_DEFAULTS)) {
|
|
56
|
+
if (ids)
|
|
57
|
+
registry.registerTaskTypeDefaults(taskType, ids);
|
|
58
|
+
}
|
|
59
|
+
return registry;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a fragment from the SHIPPED catalog by id, or `undefined`.
|
|
63
|
+
*
|
|
64
|
+
* Strictly the built-ins: a deployment's own fragments live on the injected registry, and the
|
|
65
|
+
* paths still calling this are the ones with no registry in hand (a prompt composed outside a
|
|
66
|
+
* container, a test harness). That narrowing is deliberate rather than a leftover. Before it,
|
|
67
|
+
* this function silently answered from a module global that a second copy of the package would
|
|
68
|
+
* have left empty, which is the whole failure the registry removes.
|
|
69
|
+
*/
|
|
70
|
+
export function getFragment(id) {
|
|
71
|
+
return FRAGMENTS_BY_ID.get(id);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAA;AAC3F,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAavD,MAAM,CAAC,MAAM,SAAS,GAAqB;IACzC,GAAG,aAAa;IAChB,GAAG,cAAc;IACjB,GAAG,mBAAmB;IACtB,GAAG,eAAe;IAClB,GAAG,cAAc;IACjB,GAAG,kBAAkB;CACtB,CAAA;AAED,+FAA+F;AAC/F,8FAA8F;AAC9F,8FAA8F;AAC9F,OAAO,EAAE,cAAc,EAAE,mCAAmC,EAAE,MAAM,wBAAwB,CAAA;AAC5F,wEAAwE;AACxE,8CAA8C;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AACpE,+FAA+F;AAC/F,iGAAiG;AACjG,gGAAgG;AAChG,qFAAqF;AACrF,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAC5F,qGAAqG;AACrG,sGAAsG;AACtG,iEAAiE;AACjE,OAAO,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAE/F,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAwC,IAAI,GAAG,CACzE,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CACrD,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kCAAkC;IAChD,MAAM,QAAQ,GAAG,6BAA6B,EAAE,CAAA;IAChD,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IAC/B,KAAK,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,EAAE,CAAC;QACzE,IAAI,GAAG;YAAE,QAAQ,CAAC,wBAAwB,CAAC,QAAoB,EAAE,GAAG,CAAC,CAAA;IACvE,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TaskType } from '@cat-factory/contracts';
|
|
2
|
+
/** The built-in per-task-type defaults shipped with the catalog (today: document only). */
|
|
3
|
+
export declare const BUILTIN_TASK_TYPE_DEFAULTS: Partial<Record<TaskType, readonly string[]>>;
|
|
4
|
+
//# sourceMappingURL=task-type-defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-type-defaults.d.ts","sourceRoot":"","sources":["../src/task-type-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AA0BtD,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC,CAEnF,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// The BUILT-IN per-task-type default best-practice fragment ids.
|
|
4
|
+
//
|
|
5
|
+
// The fragments a NEW task of a given type (`document`, `review`, `feature`, …) is pre-seeded
|
|
6
|
+
// with at creation. The board service unions these onto a task's `fragmentIds` when it is created
|
|
7
|
+
// (alongside whatever the task inherits from its service or an explicit create-form pick), so
|
|
8
|
+
// every new task of that type starts with the guidance without any per-block or per-workspace
|
|
9
|
+
// configuration.
|
|
10
|
+
//
|
|
11
|
+
// A DEPLOYMENT declares its own through the app-owned registry
|
|
12
|
+
// (`promptFragmentRegistry.registerTaskTypeDefaults('review', [...ids])`), which is what this
|
|
13
|
+
// module used to hold as a second module global beside the fragment pool, with the identical
|
|
14
|
+
// two-physical-copies hazard. The built-in sets below are installed onto that same registry by
|
|
15
|
+
// `promptFragmentRegistryWithBuiltins()`, through the same public method, so the platform and a
|
|
16
|
+
// consumer exercise one code path.
|
|
17
|
+
//
|
|
18
|
+
// Registering a task type REPLACES its set rather than unioning with these, which is a behaviour
|
|
19
|
+
// change from the module-global seam and the honest one: a deployment's declaration is its final
|
|
20
|
+
// answer, and the previous silent union meant a deployment could not remove a shipped default
|
|
21
|
+
// however it wrote the call. A deployment that wants the writing-style set alongside its own
|
|
22
|
+
// spreads `DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS` into its own list, which says so in the code.
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/** The built-in per-task-type defaults shipped with the catalog (today: document only). */
|
|
25
|
+
export const BUILTIN_TASK_TYPE_DEFAULTS = {
|
|
26
|
+
document: DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS,
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=task-type-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-type-defaults.js","sourceRoot":"","sources":["../src/task-type-defaults.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mCAAmC,EAAE,MAAM,wBAAwB,CAAA;AAE5E,8EAA8E;AAC9E,iEAAiE;AACjE,EAAE;AACF,8FAA8F;AAC9F,kGAAkG;AAClG,8FAA8F;AAC9F,8FAA8F;AAC9F,iBAAiB;AACjB,EAAE;AACF,+DAA+D;AAC/D,8FAA8F;AAC9F,6FAA6F;AAC7F,+FAA+F;AAC/F,gGAAgG;AAChG,mCAAmC;AACnC,EAAE;AACF,iGAAiG;AACjG,iGAAiG;AACjG,8FAA8F;AAC9F,6FAA6F;AAC7F,8FAA8F;AAC9F,8EAA8E;AAE9E,2FAA2F;AAC3F,MAAM,CAAC,MAAM,0BAA0B,GAAiD;IACtF,QAAQ,EAAE,mCAAmC;CAC9C,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/prompt-fragments",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Curated, versioned best-practice prompt fragments injected into agent system prompts.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/kibertoad/cat-factory.git",
|
|
8
|
+
"directory": "backend/packages/prompt-fragments"
|
|
9
|
+
},
|
|
5
10
|
"files": [
|
|
6
11
|
"dist"
|
|
7
12
|
],
|
|
@@ -19,13 +24,17 @@
|
|
|
19
24
|
"access": "public"
|
|
20
25
|
},
|
|
21
26
|
"dependencies": {
|
|
22
|
-
"@cat-factory/contracts": "
|
|
27
|
+
"@cat-factory/contracts": "0.256.0",
|
|
28
|
+
"@cat-factory/kernel": "0.255.0"
|
|
23
29
|
},
|
|
24
30
|
"devDependencies": {
|
|
25
|
-
"typescript": "
|
|
31
|
+
"typescript": "7.0.2",
|
|
32
|
+
"vitest": "^4.1.10"
|
|
26
33
|
},
|
|
27
34
|
"scripts": {
|
|
28
|
-
"build": "tsc -
|
|
29
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
|
+
"build": "tsc -b tsconfig.build.json",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
+
"test": "vitest",
|
|
38
|
+
"test:run": "vitest run"
|
|
30
39
|
}
|
|
31
40
|
}
|