@cat-factory/prompt-fragments 0.16.0 → 1.0.1

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 CHANGED
@@ -4,7 +4,7 @@ The **built-in tier** of best-practice prompt fragments: small, curated guidance
4
4
  snippets that get folded into an agent's system prompt at run time
5
5
  (`composeSystemPrompt`). This package is **plain, build-static data**: no I/O, no
6
6
  framework. It is the source of truth for the shipped defaults and the seed for the
7
- tenant-scoped [prompt-fragment library](../../docs/adr/0006-prompt-fragment-library.md).
7
+ tenant-scoped [prompt-fragment library](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/adr/0006-prompt-fragment-library.md).
8
8
 
9
9
  ## What's here
10
10
 
@@ -13,7 +13,7 @@ tenant-scoped [prompt-fragment library](../../docs/adr/0006-prompt-fragment-libr
13
13
  - `src/index.ts`: merges the collections into a single `FRAGMENTS` registry plus
14
14
  `FRAGMENTS_BY_ID` and `getFragment(id)` for O(1) lookup during composition.
15
15
 
16
- A `PromptFragment` (shape defined in [`@cat-factory/contracts`](../contracts))
16
+ A `PromptFragment` (shape defined in [`@cat-factory/contracts`](https://github.com/kibertoad/cat-factory/tree/main/backend/packages/contracts))
17
17
  carries an `id`, `version`, `title`, optional `category`, a `summary` (used by the
18
18
  relevance selector), the `body` (injected text), an optional condensed `brief`
19
19
  (see below), and an optional `appliesTo` hint (`blockTypes` / `agentKinds`).
@@ -32,7 +32,7 @@ relevance selector), the `body` (injected text), an optional condensed `brief`
32
32
  - When the optional library is enabled, this becomes the **built-in tier** of a
33
33
  three-tier merge (built-in ∪ account ∪ workspace); ids here can be shadowed or
34
34
  suppressed by higher tiers. See
35
- [ADR 0006](../../docs/adr/0006-prompt-fragment-library.md).
35
+ [ADR 0006](https://github.com/kibertoad/cat-factory/blob/main/backend/docs/adr/0006-prompt-fragment-library.md).
36
36
 
37
37
  ### Two-tier bodies: `body` and `brief`
38
38
 
@@ -61,7 +61,7 @@ by hand when a built-in grows past ~1,500 characters.
61
61
  ### Where a brief comes from at run time
62
62
 
63
63
  The built-in `brief` above is only the first of three answers. For a fragment resolved through
64
- the tenant library ([ADR 0006](../../docs/adr/0006-prompt-fragment-library.md)) the resolution
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
65
  order is:
66
66
 
67
67
  1. **The winning tier's linked `brief`**: a built-in's, or the one a tenant authored on its own
@@ -75,44 +75,60 @@ order is:
75
75
  that path lands (no model wired, an unreadable store, a refused condensation).
76
76
 
77
77
  Design, decisions and gotchas:
78
- [`docs/initiatives/auto-generated-fragment-briefs.md`](../../../docs/initiatives/auto-generated-fragment-briefs.md).
78
+ [`docs/initiatives/auto-generated-fragment-briefs.md`](https://github.com/kibertoad/cat-factory/blob/main/docs/initiatives/auto-generated-fragment-briefs.md).
79
79
 
80
80
  ## Programmatic deployment seams (custom fragments + per-task-type defaults)
81
81
 
82
- Two **module-global** registration seams let a deployment (local **or** hosted) extend
83
- the fragment behaviour at startup: an import side effect from the deployment entry, run
84
- **once before** `start()` / `startLocal()`, mirroring `registerAgentKind`. No fork, no
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
85
84
  rebuild, no per-workspace UI.
86
85
 
87
- - **Add custom fragments to the universal pool**: `registerPromptFragment(fragment)` /
88
- `registerPromptFragments(fragments)`. Every `GET /prompt-fragments` catalog read and
89
- every run-time body lookup then sees them; re-registering an id overrides the built-in
90
- of that id. (`universalFragments()` is the merged built-in ∪ registered pool.)
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.
91
103
  - **Mark fragments as the default for a BUILT-IN task type**:
92
- `registerTaskTypeDefaultFragments(taskType, fragmentIds)`. Every **new** task of that
93
- type (`document`, `review`, `feature`, …) is then seeded with those fragments onto its
94
- own `fragmentIds` at creation (unioned with the built-in defaults and whatever it
95
- inherits from its service). The board resolves a new task's seed set through
96
- `defaultFragmentIdsForTaskType(taskType)`; the only built-in per-type default is the
97
- document writing-style set (`DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS`), which registered
98
- ids augment rather than replace. Seeding is server-side and authoritative: it applies
99
- even for tasks created via the public API with no create-form picker.
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.
100
113
 
101
114
  **A deployment's OWN (namespaced) task type does not use this seam.** It declares
102
- `defaultFragmentIds` on its own registration instead, where boot validation can see the
103
- ids and warn on one the code pool does not resolve; this module-global exists for the
104
- built-in types, which have no descriptor to carry them. That declaration is one third of
105
- a **reusable operation**: see
106
- [`backend/docs/reusable-operations.md`](../../docs/reusable-operations.md).
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.
107
125
 
108
126
  ```ts
109
127
  // deployment entry, before start()/startLocal()
110
- import {
111
- registerPromptFragments,
112
- registerTaskTypeDefaultFragments,
113
- } from '@cat-factory/prompt-fragments'
128
+ import { promptFragmentRegistryWithBuiltins } from '@cat-factory/prompt-fragments'
114
129
 
115
- registerPromptFragments([
130
+ const promptFragmentRegistry = promptFragmentRegistryWithBuiltins()
131
+ promptFragmentRegistry.registerAll([
116
132
  {
117
133
  id: 'org.review-checklist',
118
134
  version: '1.0.0',
@@ -122,9 +138,18 @@ registerPromptFragments([
122
138
  },
123
139
  ])
124
140
  // every new REVIEW task starts with this guidance
125
- registerTaskTypeDefaultFragments('review', ['org.review-checklist'])
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 */ })
126
145
  ```
127
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
+
128
153
  ## Adding a collection
129
154
 
130
155
  1. Create `src/collections/<topic>.ts` and export an array of `PromptFragment`.
package/dist/index.d.ts CHANGED
@@ -1,27 +1,39 @@
1
1
  import type { PromptFragment } from '@cat-factory/contracts';
2
+ import { PromptFragmentRegistry } from '@cat-factory/kernel';
2
3
  export type { PromptFragment } from '@cat-factory/contracts';
3
4
  export declare const FRAGMENTS: PromptFragment[];
4
5
  export { styleFragments, DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
5
- export { registerTaskTypeDefaultFragments, clearRegisteredTaskTypeDefaultFragments, defaultFragmentIdsForTaskType, } from './task-type-defaults.js';
6
+ export { BUILTIN_TASK_TYPE_DEFAULTS } from './task-type-defaults.js';
6
7
  export { MIGRATION_FRAGMENT_IDS, migrationFragmentIdsFor } from './collections/migration.js';
7
8
  export { DESIGN_CONTEXT_FRAGMENT_ID, withDesignContextFragment } from './collections/design.js';
8
9
  /** Fragments keyed by id for O(1) lookup during prompt composition. */
9
10
  export declare const FRAGMENTS_BY_ID: ReadonlyMap<string, PromptFragment>;
10
- /** Register a custom prompt fragment into the universal pool. Re-registering an id replaces it. */
11
- export declare function registerPromptFragment(fragment: PromptFragment): void;
12
- /** Register several custom prompt fragments at once. */
13
- export declare function registerPromptFragments(fragments: Iterable<PromptFragment>): void;
14
- /** Drop all registered fragments. Intended for tests that exercise registration. */
15
- export declare function clearRegisteredPromptFragments(): void;
16
11
  /**
17
- * The universal fragment pool: the built-in catalog plus any deployment-registered
18
- * fragments, with a registered id shadowing the built-in of the same id. This is what
19
- * the catalog endpoint serves and what a service's fragment selection is drawn from.
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.
20
27
  */
21
- export declare function universalFragments(): PromptFragment[];
28
+ export declare function promptFragmentRegistryWithBuiltins(): PromptFragmentRegistry;
22
29
  /**
23
- * Resolve a fragment by id, or `undefined` if no such fragment exists. Checks the
24
- * deployment-registered fragments first (override-by-id) then the built-in catalog.
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.
25
37
  */
26
38
  export declare function getFragment(id: string): PromptFragment | undefined;
27
39
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAiB5D,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;AAI5F,OAAO,EACL,gCAAgC,EAChC,uCAAuC,EACvC,6BAA6B,GAC9B,MAAM,yBAAyB,CAAA;AAKhC,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;AAYD,mGAAmG;AACnG,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAErE;AAED,wDAAwD;AACxD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,IAAI,CAEjF;AAED,oFAAoF;AACpF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,cAAc,EAAE,CAMrD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAElE"}
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 CHANGED
@@ -1,3 +1,5 @@
1
+ import { PromptFragmentRegistry, defaultPromptFragmentRegistry } from '@cat-factory/kernel';
2
+ import { BUILTIN_TASK_TYPE_DEFAULTS } from './task-type-defaults.js';
1
3
  import { acceptanceFragments } from './collections/acceptance.js';
2
4
  import { designFragments } from './collections/design.js';
3
5
  import { migrationFragments } from './collections/migration.js';
@@ -16,10 +18,9 @@ export const FRAGMENTS = [
16
18
  // board service seeding a new document task's fragments, the docs-refresh preset building its
17
19
  // `styleFragments` form options) draws on the same source of truth the catalog is built from.
18
20
  export { styleFragments, DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
19
- // The per-task-type default-fragments seam: a deployment registers the fragments every new task
20
- // of a given type (documentation/review/…) starts with; the board service resolves a new task's
21
- // seed set through `defaultFragmentIdsForTaskType`.
22
- export { registerTaskTypeDefaultFragments, clearRegisteredTaskTypeDefaultFragments, defaultFragmentIdsForTaskType, } from './task-type-defaults.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';
23
24
  // Re-export the migration fragment ids so the `preset_tech_migration` preset draws its default
24
25
  // fragment set from the same source of truth the catalog is built from: `MIGRATION_FRAGMENT_IDS`
25
26
  // (T8's descriptor `defaultFragmentIds`) + `migrationFragmentIdsFor` (T7's `seedMigrationPlan`,
@@ -31,48 +32,42 @@ export { MIGRATION_FRAGMENT_IDS, migrationFragmentIdsFor } from './collections/m
31
32
  export { DESIGN_CONTEXT_FRAGMENT_ID, withDesignContextFragment } from './collections/design.js';
32
33
  /** Fragments keyed by id for O(1) lookup during prompt composition. */
33
34
  export const FRAGMENTS_BY_ID = new Map(FRAGMENTS.map((fragment) => [fragment.id, fragment]));
34
- // Installation-level extension point for the universal fragment pool, mirroring the
35
- // custom-agent (`registerAgentKind`) and model-provider registry seams. A deployment —
36
- // e.g. a proprietary org package — adds extra best-practice fragments once at startup
37
- // (an import side effect); every `getFragment` lookup and the `GET /prompt-fragments`
38
- // catalog then see them, so a service's fragment selection can draw on them without the
39
- // core packages knowing they exist. Registering an id that already exists in the
40
- // built-in catalog overrides it (later registration wins), so a deployment can refine a
41
- // shipped fragment's body in place.
42
- const registered = new Map();
43
- /** Register a custom prompt fragment into the universal pool. Re-registering an id replaces it. */
44
- export function registerPromptFragment(fragment) {
45
- registered.set(fragment.id, fragment);
46
- }
47
- /** Register several custom prompt fragments at once. */
48
- export function registerPromptFragments(fragments) {
49
- for (const fragment of fragments)
50
- registerPromptFragment(fragment);
51
- }
52
- /** Drop all registered fragments. Intended for tests that exercise registration. */
53
- export function clearRegisteredPromptFragments() {
54
- registered.clear();
55
- }
56
35
  /**
57
- * The universal fragment pool: the built-in catalog plus any deployment-registered
58
- * fragments, with a registered id shadowing the built-in of the same id. This is what
59
- * the catalog endpoint serves and what a service's fragment selection is drawn from.
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.
60
51
  */
61
- export function universalFragments() {
62
- if (registered.size === 0)
63
- return [...FRAGMENTS];
64
- const byId = new Map();
65
- for (const fragment of FRAGMENTS)
66
- byId.set(fragment.id, fragment);
67
- for (const fragment of registered.values())
68
- byId.set(fragment.id, fragment);
69
- return [...byId.values()];
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;
70
60
  }
71
61
  /**
72
- * Resolve a fragment by id, or `undefined` if no such fragment exists. Checks the
73
- * deployment-registered fragments first (override-by-id) then the built-in catalog.
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.
74
69
  */
75
70
  export function getFragment(id) {
76
- return registered.get(id) ?? FRAGMENTS_BY_ID.get(id);
71
+ return FRAGMENTS_BY_ID.get(id);
77
72
  }
78
73
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,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,gGAAgG;AAChG,gGAAgG;AAChG,oDAAoD;AACpD,OAAO,EACL,gCAAgC,EAChC,uCAAuC,EACvC,6BAA6B,GAC9B,MAAM,yBAAyB,CAAA;AAChC,+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,oFAAoF;AACpF,uFAAuF;AACvF,sFAAsF;AACtF,sFAAsF;AACtF,wFAAwF;AACxF,iFAAiF;AACjF,wFAAwF;AACxF,oCAAoC;AACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAA;AAEpD,mGAAmG;AACnG,MAAM,UAAU,sBAAsB,CAAC,QAAwB;IAC7D,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;AACvC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,uBAAuB,CAAC,SAAmC;IACzE,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;AACpE,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,8BAA8B;IAC5C,UAAU,CAAC,KAAK,EAAE,CAAA;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAA0B,CAAA;IAC9C,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;IACjE,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;IAC3E,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACtD,CAAC"}
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"}
@@ -1,21 +1,4 @@
1
1
  import type { TaskType } from '@cat-factory/contracts';
2
- /**
3
- * Register the default fragment ids for a task type. Every NEW task of `taskType` created
4
- * on the board then starts with these fragments (unioned with the built-in defaults and
5
- * whatever the task inherits). Re-registering the same task type REPLACES its registered
6
- * set. The ids reference the universal fragment pool (built-in catalog plus any
7
- * `registerPromptFragment`-registered fragments); an unresolvable id is simply skipped
8
- * when bodies are composed at run time, so registration order with `registerPromptFragment`
9
- * does not matter.
10
- */
11
- export declare function registerTaskTypeDefaultFragments(taskType: TaskType, fragmentIds: Iterable<string>): void;
12
- /** Drop all registered per-task-type defaults. Intended for tests that exercise registration. */
13
- export declare function clearRegisteredTaskTypeDefaultFragments(): void;
14
- /**
15
- * The effective default fragment ids a new task of `taskType` is seeded with: the built-in
16
- * defaults for the type (the document writing-style set, else none) unioned with any
17
- * deployment-registered ids, deduped and order-stable (built-ins first). Empty when the
18
- * type has no built-in and nothing is registered.
19
- */
20
- export declare function defaultFragmentIdsForTaskType(taskType: TaskType): string[];
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[]>>;
21
4
  //# sourceMappingURL=task-type-defaults.d.ts.map
@@ -1 +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;AAkCtD;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC5B,IAAI,CAEN;AAED,iGAAiG;AACjG,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAK1E"}
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"}
@@ -1,59 +1,28 @@
1
1
  import { DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS } from './collections/style.js';
2
2
  // ---------------------------------------------------------------------------
3
- // Per-TASK-TYPE default best-practice fragment ids.
3
+ // The BUILT-IN per-task-type default best-practice fragment ids.
4
4
  //
5
- // The fragments a NEW task of a given type (`document`, `review`, `feature`, …) is
6
- // pre-seeded with at creation. The board service unions these onto a task's
7
- // `fragmentIds` when it is created (alongside whatever the task inherits from its
8
- // service or an explicit create-form pick), so every new task of that type starts with
9
- // the guidance without any per-block or per-workspace configuration.
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
10
  //
11
- // This is the deployment-level PROGRAMMATIC seam — a module-global registry mirroring
12
- // `registerPromptFragment` and `registerDocTemplate`. A deployment adds its own custom
13
- // fragments via `registerPromptFragments(...)` (universal pool) and then declares them as
14
- // the default for a task type via `registerTaskTypeDefaultFragments('review', [...ids])`,
15
- // so e.g. every new documentation or review task starts with that org's guidance. The
16
- // call happens once at startup (an import side effect in the deployment entry, before
17
- // `start()` / `startLocal()`), exactly like `registerPromptFragments`.
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.
18
17
  //
19
- // The shipped `document` writing-style defaults (`DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS`)
20
- // are the ONLY built-in per-type default; they are always applied for a document task and
21
- // union with any registered ids, so registering document defaults augments (never wipes)
22
- // the writing-style guidance. When nothing is registered, behaviour is unchanged.
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
23
  // ---------------------------------------------------------------------------
24
24
  /** The built-in per-task-type defaults shipped with the catalog (today: document only). */
25
- const BUILTIN_TASK_TYPE_DEFAULTS = {
25
+ export const BUILTIN_TASK_TYPE_DEFAULTS = {
26
26
  document: DEFAULT_DOCUMENT_STYLE_FRAGMENT_IDS,
27
27
  };
28
- /** Deployment-registered per-task-type default fragment ids (added to the built-ins). */
29
- const registered = new Map();
30
- /**
31
- * Register the default fragment ids for a task type. Every NEW task of `taskType` created
32
- * on the board then starts with these fragments (unioned with the built-in defaults and
33
- * whatever the task inherits). Re-registering the same task type REPLACES its registered
34
- * set. The ids reference the universal fragment pool (built-in catalog plus any
35
- * `registerPromptFragment`-registered fragments); an unresolvable id is simply skipped
36
- * when bodies are composed at run time, so registration order with `registerPromptFragment`
37
- * does not matter.
38
- */
39
- export function registerTaskTypeDefaultFragments(taskType, fragmentIds) {
40
- registered.set(taskType, [...fragmentIds]);
41
- }
42
- /** Drop all registered per-task-type defaults. Intended for tests that exercise registration. */
43
- export function clearRegisteredTaskTypeDefaultFragments() {
44
- registered.clear();
45
- }
46
- /**
47
- * The effective default fragment ids a new task of `taskType` is seeded with: the built-in
48
- * defaults for the type (the document writing-style set, else none) unioned with any
49
- * deployment-registered ids, deduped and order-stable (built-ins first). Empty when the
50
- * type has no built-in and nothing is registered.
51
- */
52
- export function defaultFragmentIdsForTaskType(taskType) {
53
- const builtin = BUILTIN_TASK_TYPE_DEFAULTS[taskType] ?? [];
54
- const custom = registered.get(taskType) ?? [];
55
- if (custom.length === 0)
56
- return [...builtin];
57
- return [...new Set([...builtin, ...custom])];
58
- }
59
28
  //# sourceMappingURL=task-type-defaults.js.map
@@ -1 +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,oDAAoD;AACpD,EAAE;AACF,mFAAmF;AACnF,4EAA4E;AAC5E,kFAAkF;AAClF,uFAAuF;AACvF,qEAAqE;AACrE,EAAE;AACF,sFAAsF;AACtF,uFAAuF;AACvF,0FAA0F;AAC1F,0FAA0F;AAC1F,sFAAsF;AACtF,sFAAsF;AACtF,uEAAuE;AACvE,EAAE;AACF,wFAAwF;AACxF,0FAA0F;AAC1F,yFAAyF;AACzF,kFAAkF;AAClF,8EAA8E;AAE9E,2FAA2F;AAC3F,MAAM,0BAA0B,GAAiD;IAC/E,QAAQ,EAAE,mCAAmC;CAC9C,CAAA;AAED,yFAAyF;AACzF,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAA;AAEzD;;;;;;;;GAQG;AACH,MAAM,UAAU,gCAAgC,CAC9C,QAAkB,EAClB,WAA6B;IAE7B,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAA;AAC5C,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,uCAAuC;IACrD,UAAU,CAAC,KAAK,EAAE,CAAA;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAkB;IAC9D,MAAM,OAAO,GAAG,0BAA0B,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAA;IAC5C,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;AAC9C,CAAC"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/prompt-fragments",
3
- "version": "0.16.0",
3
+ "version": "1.0.1",
4
4
  "description": "Curated, versioned best-practice prompt fragments injected into agent system prompts.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,8 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@cat-factory/contracts": "0.253.0"
27
+ "@cat-factory/contracts": "0.255.0",
28
+ "@cat-factory/kernel": "0.254.0"
28
29
  },
29
30
  "devDependencies": {
30
31
  "typescript": "7.0.2",