@cat-factory/agents 0.95.1 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/kinds/traits.d.ts +22 -0
- package/dist/agents/kinds/traits.d.ts.map +1 -1
- package/dist/agents/kinds/traits.js +42 -3
- package/dist/agents/kinds/traits.js.map +1 -1
- package/dist/foundationalServices/FoundationalServiceCatalogService.d.ts +65 -0
- package/dist/foundationalServices/FoundationalServiceCatalogService.d.ts.map +1 -0
- package/dist/foundationalServices/FoundationalServiceCatalogService.js +284 -0
- package/dist/foundationalServices/FoundationalServiceCatalogService.js.map +1 -0
- package/dist/foundationalServices/FoundationalServiceRunResolver.d.ts +37 -0
- package/dist/foundationalServices/FoundationalServiceRunResolver.d.ts.map +1 -0
- package/dist/foundationalServices/FoundationalServiceRunResolver.js +92 -0
- package/dist/foundationalServices/FoundationalServiceRunResolver.js.map +1 -0
- package/dist/foundationalServices/FoundationalServiceSourceService.d.ts +86 -0
- package/dist/foundationalServices/FoundationalServiceSourceService.d.ts.map +1 -0
- package/dist/foundationalServices/FoundationalServiceSourceService.js +346 -0
- package/dist/foundationalServices/FoundationalServiceSourceService.js.map +1 -0
- package/dist/foundationalServices/contract-validation.d.ts +8 -0
- package/dist/foundationalServices/contract-validation.d.ts.map +1 -0
- package/dist/foundationalServices/contract-validation.js +43 -0
- package/dist/foundationalServices/contract-validation.js.map +1 -0
- package/dist/foundationalServices/foundational-catalog.d.ts +22 -0
- package/dist/foundationalServices/foundational-catalog.d.ts.map +1 -0
- package/dist/foundationalServices/foundational-catalog.js +58 -0
- package/dist/foundationalServices/foundational-catalog.js.map +1 -0
- package/dist/foundationalServices/foundational-source.logic.d.ts +51 -0
- package/dist/foundationalServices/foundational-source.logic.d.ts.map +1 -0
- package/dist/foundationalServices/foundational-source.logic.js +109 -0
- package/dist/foundationalServices/foundational-source.logic.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -59,6 +59,28 @@ export declare const INTERVIEW_GATE_TRAIT: AgentTrait;
|
|
|
59
59
|
* so the trait only affects kinds whose standards are folded into the prompt.
|
|
60
60
|
*/
|
|
61
61
|
export declare const BRIEF_STANDARDS_TRAIT: AgentTrait;
|
|
62
|
+
/**
|
|
63
|
+
* DESIGN-time kinds that choose which shared FOUNDATIONAL SERVICES a solution consumes. The
|
|
64
|
+
* engine injects the workspace's catalog (identity + capabilities + operation names, never a
|
|
65
|
+
* contract document) as `.cat-context/foundational-services/catalog.md`, and the guidance below
|
|
66
|
+
* requires the kind to declare the ids it designed against in a machine-readable block. That
|
|
67
|
+
* declaration is what the downstream `foundational-contracts` kinds' lazy read keys off — the
|
|
68
|
+
* whole point of splitting the two traits is that a design step pays for the cheap catalog and
|
|
69
|
+
* only the services it actually picked cost anyone a document.
|
|
70
|
+
*/
|
|
71
|
+
export declare const FOUNDATIONAL_CATALOG_TRAIT: AgentTrait;
|
|
72
|
+
/**
|
|
73
|
+
* CONSUMER kinds that need the API details of the services the design declared. The engine
|
|
74
|
+
* resolves those ids to their full contract documents and injects one file per service. The
|
|
75
|
+
* guidance points at the index rather than restating the catalog: a consumer must not be
|
|
76
|
+
* choosing services, and handing it the whole catalog is how a coder ends up adopting a shared
|
|
77
|
+
* service the design deliberately rejected.
|
|
78
|
+
*/
|
|
79
|
+
export declare const FOUNDATIONAL_CONTRACTS_TRAIT: AgentTrait;
|
|
80
|
+
/** The guidance a design-time kind gets: consult the catalog, then DECLARE what it used. */
|
|
81
|
+
export declare const FOUNDATIONAL_CATALOG_GUIDANCE: string;
|
|
82
|
+
/** The guidance a consumer kind gets: the contracts are files, and they are authoritative. */
|
|
83
|
+
export declare const FOUNDATIONAL_CONTRACTS_GUIDANCE: string;
|
|
62
84
|
/** The guidance appended to a spec-aware kind's system prompt — explains the spec format. */
|
|
63
85
|
export declare const SPEC_AWARE_GUIDANCE: string;
|
|
64
86
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traits.d.ts","sourceRoot":"","sources":["../../../src/agents/kinds/traits.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"traits.d.ts","sourceRoot":"","sources":["../../../src/agents/kinds/traits.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,SAAS,EAOf,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAetD,yFAAyF;AACzF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAA;AAE/B;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAAyB,CAAA;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,UAAwB,CAAA;AAEtD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAAyB,CAAA;AAExD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAA6B,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAA6B,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAA8B,CAAA;AAElE;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,UAAmC,CAAA;AAE5E;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,UAAqC,CAAA;AAEhF,4FAA4F;AAC5F,eAAO,MAAM,6BAA6B,QAK9B,CAAA;AAEZ,8FAA8F;AAC9F,eAAO,MAAM,+BAA+B,QAIhC,CAAA;AAEZ,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,QAWpB,CAAA;AAEZ;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAmC1E,CAAA;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,EAAE,EAAE,UAAU,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC,CAAA;CAClD;AAED;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,oBAAoB,EAQrE,CAAA;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,GAAG,GAAG,CAAC,UAAU,CAAC,CAKvF;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAEjG;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,GAAG,OAAO,CAElB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAQvF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SPEC_FEATURES_DIR, SPEC_MODULES_DIR, SPEC_OVERVIEW_PATH } from '@cat-factory/contracts';
|
|
2
|
-
import { DOC_INTERVIEWER_AGENT_KIND, INITIATIVE_INTERVIEWER_AGENT_KIND, } from '@cat-factory/kernel';
|
|
2
|
+
import { DOC_INTERVIEWER_AGENT_KIND, FOUNDATIONAL_CATALOG_FILE, FOUNDATIONAL_CONTEXT_DIR, FOUNDATIONAL_DECLARATION_TAG, FOUNDATIONAL_INDEX_FILE, INITIATIVE_INTERVIEWER_AGENT_KIND, } from '@cat-factory/kernel';
|
|
3
3
|
/**
|
|
4
4
|
* Code-aware kinds read and/or change the service's code. The service's selected
|
|
5
5
|
* best-practice / guideline fragments (Node, Fastify, performance, …) are folded into
|
|
@@ -57,6 +57,37 @@ export const INTERVIEW_GATE_TRAIT = 'interview-gate';
|
|
|
57
57
|
* so the trait only affects kinds whose standards are folded into the prompt.
|
|
58
58
|
*/
|
|
59
59
|
export const BRIEF_STANDARDS_TRAIT = 'brief-standards';
|
|
60
|
+
/**
|
|
61
|
+
* DESIGN-time kinds that choose which shared FOUNDATIONAL SERVICES a solution consumes. The
|
|
62
|
+
* engine injects the workspace's catalog (identity + capabilities + operation names, never a
|
|
63
|
+
* contract document) as `.cat-context/foundational-services/catalog.md`, and the guidance below
|
|
64
|
+
* requires the kind to declare the ids it designed against in a machine-readable block. That
|
|
65
|
+
* declaration is what the downstream `foundational-contracts` kinds' lazy read keys off — the
|
|
66
|
+
* whole point of splitting the two traits is that a design step pays for the cheap catalog and
|
|
67
|
+
* only the services it actually picked cost anyone a document.
|
|
68
|
+
*/
|
|
69
|
+
export const FOUNDATIONAL_CATALOG_TRAIT = 'foundational-catalog';
|
|
70
|
+
/**
|
|
71
|
+
* CONSUMER kinds that need the API details of the services the design declared. The engine
|
|
72
|
+
* resolves those ids to their full contract documents and injects one file per service. The
|
|
73
|
+
* guidance points at the index rather than restating the catalog: a consumer must not be
|
|
74
|
+
* choosing services, and handing it the whole catalog is how a coder ends up adopting a shared
|
|
75
|
+
* service the design deliberately rejected.
|
|
76
|
+
*/
|
|
77
|
+
export const FOUNDATIONAL_CONTRACTS_TRAIT = 'foundational-contracts';
|
|
78
|
+
/** The guidance a design-time kind gets: consult the catalog, then DECLARE what it used. */
|
|
79
|
+
export const FOUNDATIONAL_CATALOG_GUIDANCE = [
|
|
80
|
+
`This deployment runs shared FOUNDATIONAL SERVICES — capabilities such as file storage, notifications or audit that already exist and that new systems are expected to CONSUME rather than rebuild. The catalog of what is available is provided to you as \`.cat-context/${FOUNDATIONAL_CATALOG_FILE}\`; read it before you settle on a design.`,
|
|
81
|
+
`Prefer an existing foundational service over designing your own equivalent. When you reject one that looks applicable, say why — "we already have this" is the single most common avoidable finding in a design review.`,
|
|
82
|
+
`The catalog lists each service's operations but NOT its full API documents. Design against the operations you can see; do not invent endpoints, fields or semantics the catalog does not show. The implementation steps get the full contracts.`,
|
|
83
|
+
`END your reply with a fenced \`\`\`${FOUNDATIONAL_DECLARATION_TAG} block listing the service ids your design consumes, one per line, and nothing else in the block. Write \`none\` when your design consumes no foundational service. This block is machine-read: the ids you list are what the later implementation steps are handed the API contracts for, so a service you omit is one nobody downstream will have the interface to, and an id you invent will be reported as unavailable.`,
|
|
84
|
+
].join('\n');
|
|
85
|
+
/** The guidance a consumer kind gets: the contracts are files, and they are authoritative. */
|
|
86
|
+
export const FOUNDATIONAL_CONTRACTS_GUIDANCE = [
|
|
87
|
+
`The FOUNDATIONAL SERVICES the design chose for this task — shared capabilities such as file storage, notifications or audit — have their API contracts provided to you under \`.cat-context/${FOUNDATIONAL_CONTEXT_DIR}/\`. Start at \`.cat-context/${FOUNDATIONAL_INDEX_FILE}\`, which names each one and states anything the design asked for that could not be provided.`,
|
|
88
|
+
`Treat those contracts as the authoritative interface: call the operations they declare, with the shapes they declare. Do not invent an endpoint or a field, and do not reimplement a capability one of these services already provides.`,
|
|
89
|
+
`If the work needs something the provided contracts do not cover, say so in your report rather than guessing at the missing API.`,
|
|
90
|
+
].join('\n');
|
|
60
91
|
/** The guidance appended to a spec-aware kind's system prompt — explains the spec format. */
|
|
61
92
|
export const SPEC_AWARE_GUIDANCE = [
|
|
62
93
|
`This repository may contain a prescriptive SPECIFICATION for the service under the \`spec/\` directory — the source of truth for what the service must do. It is sharded by a module (domain) → feature (group) taxonomy. When it is present, read it before doing the work:`,
|
|
@@ -83,8 +114,14 @@ export const SPEC_AWARE_GUIDANCE = [
|
|
|
83
114
|
* `reviewer` companion is a built-in listed here while the coder declares its own).
|
|
84
115
|
*/
|
|
85
116
|
export const STANDARD_AGENT_TRAITS = {
|
|
86
|
-
architect
|
|
87
|
-
coder
|
|
117
|
+
// The architect DESIGNS, so it is the one built-in kind that chooses foundational services
|
|
118
|
+
// and declares them; `researcher` and `coder` CONSUME that declaration.
|
|
119
|
+
architect: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT, FOUNDATIONAL_CATALOG_TRAIT],
|
|
120
|
+
coder: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT, BRIEF_STANDARDS_TRAIT, FOUNDATIONAL_CONTRACTS_TRAIT],
|
|
121
|
+
// The researcher plans the solution against the design, so it needs the same contracts the
|
|
122
|
+
// coder will build to — investigating prior art for a capability the org already runs, from
|
|
123
|
+
// the catalog entry alone, is how a plan ends up proposing a library beside a shared service.
|
|
124
|
+
researcher: [FOUNDATIONAL_CONTRACTS_TRAIT],
|
|
88
125
|
reviewer: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT],
|
|
89
126
|
'ci-fixer': [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT, BRIEF_STANDARDS_TRAIT],
|
|
90
127
|
fixer: [CODE_AWARE_TRAIT, SPEC_AWARE_TRAIT, BRIEF_STANDARDS_TRAIT],
|
|
@@ -124,6 +161,8 @@ export const STANDARD_TRAIT_DEFINITIONS = [
|
|
|
124
161
|
{ id: SPEC_AWARE_TRAIT, guidance: SPEC_AWARE_GUIDANCE },
|
|
125
162
|
{ id: INTERVIEW_GATE_TRAIT },
|
|
126
163
|
{ id: BRIEF_STANDARDS_TRAIT },
|
|
164
|
+
{ id: FOUNDATIONAL_CATALOG_TRAIT, guidance: FOUNDATIONAL_CATALOG_GUIDANCE },
|
|
165
|
+
{ id: FOUNDATIONAL_CONTRACTS_TRAIT, guidance: FOUNDATIONAL_CONTRACTS_GUIDANCE },
|
|
127
166
|
];
|
|
128
167
|
/**
|
|
129
168
|
* The traits a kind carries: its built-in set ({@link STANDARD_AGENT_TRAITS}) unioned with a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traits.js","sourceRoot":"","sources":["../../../src/agents/kinds/traits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChG,OAAO,EAEL,0BAA0B,EAC1B,iCAAiC,GAClC,MAAM,qBAAqB,CAAA;AAmB5B;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAe,YAAY,CAAA;AAExD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAe,WAAW,CAAA;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAe,YAAY,CAAA;AAExD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAe,gBAAgB,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAe,gBAAgB,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAe,iBAAiB,CAAA;AAElE,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,8QAA8Q;IAC9Q,OAAO,kBAAkB,0GAA0G;IACnI,OAAO,gBAAgB,mHAAmH;IAC1I,OAAO,gBAAgB,0IAA0I;IACjK,OAAO,iBAAiB,uFAAuF;IAC/G,2FAA2F;IAC3F,uFAAuF;IACvF,2FAA2F;IAC3F,kCAAkC,kBAAkB,oQAAoQ;IACxT,8MAA8M;CAC/M,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA6C;IAC7E,SAAS,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"traits.js","sourceRoot":"","sources":["../../../src/agents/kinds/traits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ApiContractDocument, CreateFoundationalServiceInput, FoundationalService, FoundationalServiceOwnerKind, ResolvedFoundationalService, UpdateFoundationalServiceInput } from '@cat-factory/contracts';
|
|
2
|
+
import type { ApiContractRepository, Clock, FoundationalServiceRepository, GroupCacheHandle, WorkspaceRepository } from '@cat-factory/kernel';
|
|
3
|
+
export interface FoundationalServiceCatalogDependencies {
|
|
4
|
+
foundationalServiceRepository: FoundationalServiceRepository;
|
|
5
|
+
apiContractRepository: ApiContractRepository;
|
|
6
|
+
workspaceRepository: WorkspaceRepository;
|
|
7
|
+
clock: Clock;
|
|
8
|
+
/** The merged per-workspace catalog cache. Absent (tests) ⇒ every resolve reads through. */
|
|
9
|
+
catalogCache?: GroupCacheHandle<ResolvedFoundationalService[]>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The foundational-services catalog (docs/initiatives/foundational-services.md): per-tier CRUD
|
|
13
|
+
* plus the merged account ⊕ workspace resolve every design dispatch reads.
|
|
14
|
+
*
|
|
15
|
+
* Two properties are load-bearing and are why this is a service rather than a repository call:
|
|
16
|
+
*
|
|
17
|
+
* - **The catalog never carries a contract BODY.** `listTier` and `resolve` join the contract
|
|
18
|
+
* MANIFEST (id, format, title, byte size, operation names) onto each service in ONE extra
|
|
19
|
+
* query for the whole tier. The documents are read only by {@link contractsFor}, and only for
|
|
20
|
+
* the ids a caller asks for.
|
|
21
|
+
* - **A workspace row wins over an account row of the same id, and a workspace TOMBSTONE
|
|
22
|
+
* suppresses one.** That is what lets a board opt out of an org-wide service without an
|
|
23
|
+
* account admin, and it is why the merge reads the workspace tier `includeDeleted`.
|
|
24
|
+
*/
|
|
25
|
+
export declare class FoundationalServiceCatalogService {
|
|
26
|
+
private readonly deps;
|
|
27
|
+
constructor(deps: FoundationalServiceCatalogDependencies);
|
|
28
|
+
/** One tier's registered services, contract manifests joined on. Raw — not merged. */
|
|
29
|
+
listTier(ownerKind: FoundationalServiceOwnerKind, ownerId: string): Promise<FoundationalService[]>;
|
|
30
|
+
/** Register a service at a tier. */
|
|
31
|
+
create(ownerKind: FoundationalServiceOwnerKind, ownerId: string, input: CreateFoundationalServiceInput): Promise<FoundationalService>;
|
|
32
|
+
/** Patch a registered service. `contracts`, when present, replaces the whole set. */
|
|
33
|
+
update(ownerKind: FoundationalServiceOwnerKind, ownerId: string, serviceId: string, input: UpdateFoundationalServiceInput): Promise<FoundationalService>;
|
|
34
|
+
/**
|
|
35
|
+
* Remove a service from a tier. A WORKSPACE removal writes a tombstone (which is also how a
|
|
36
|
+
* board suppresses an inherited account service); an ACCOUNT removal drops the row and its
|
|
37
|
+
* documents outright, since there is no higher tier for it to shadow.
|
|
38
|
+
*/
|
|
39
|
+
remove(ownerKind: FoundationalServiceOwnerKind, ownerId: string, serviceId: string): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Suppress an ACCOUNT service for one workspace by writing a workspace-tier tombstone. The
|
|
42
|
+
* row carries no content of its own — it exists only to lose the merge — so it is written
|
|
43
|
+
* here rather than through {@link create}, which would demand a name and summary for
|
|
44
|
+
* something that is never rendered.
|
|
45
|
+
*/
|
|
46
|
+
suppressForWorkspace(workspaceId: string, serviceId: string): Promise<void>;
|
|
47
|
+
/** The merged catalog a workspace's agents see, cached per workspace. */
|
|
48
|
+
resolve(workspaceId: string): Promise<ResolvedFoundationalService[]>;
|
|
49
|
+
/**
|
|
50
|
+
* The LAZY contract read: full documents for the named services, resolved against the same
|
|
51
|
+
* account ⊕ workspace precedence the catalog uses. One batched query per tier — never a
|
|
52
|
+
* per-service read — and an empty `serviceIds` returns `[]` without touching the store.
|
|
53
|
+
*
|
|
54
|
+
* Precedence matters here as much as in the catalog: a workspace that overrode a service
|
|
55
|
+
* must hand out ITS documents, or the design would be reviewed against the org's spec while
|
|
56
|
+
* the code is written against the board's.
|
|
57
|
+
*/
|
|
58
|
+
contractsFor(workspaceId: string, serviceIds: string[]): Promise<Map<string, ApiContractDocument[]>>;
|
|
59
|
+
/** Drop a tier's cached catalog. An account write invalidates every workspace's. */
|
|
60
|
+
invalidate(ownerKind: FoundationalServiceOwnerKind, ownerId: string): Promise<void>;
|
|
61
|
+
private loadCatalog;
|
|
62
|
+
private require;
|
|
63
|
+
private buildUploadedContracts;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=FoundationalServiceCatalogService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FoundationalServiceCatalogService.d.ts","sourceRoot":"","sources":["../../src/foundationalServices/FoundationalServiceCatalogService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,8BAA8B,EAC9B,mBAAmB,EACnB,4BAA4B,EAC5B,2BAA2B,EAC3B,8BAA8B,EAC/B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAGV,qBAAqB,EACrB,KAAK,EAEL,6BAA6B,EAC7B,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAU5B,MAAM,WAAW,sCAAsC;IACrD,6BAA6B,EAAE,6BAA6B,CAAA;IAC5D,qBAAqB,EAAE,qBAAqB,CAAA;IAC5C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,KAAK,EAAE,KAAK,CAAA;IACZ,4FAA4F;IAC5F,YAAY,CAAC,EAAE,gBAAgB,CAAC,2BAA2B,EAAE,CAAC,CAAA;CAC/D;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,iCAAiC;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,sCAAsC,EAAI;IAE7E,sFAAsF;IAChF,QAAQ,CACZ,SAAS,EAAE,4BAA4B,EACvC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAOhC;IAED,oCAAoC;IAC9B,MAAM,CACV,SAAS,EAAE,4BAA4B,EACvC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,mBAAmB,CAAC,CAsC9B;IAED,qFAAqF;IAC/E,MAAM,CACV,SAAS,EAAE,4BAA4B,EACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,mBAAmB,CAAC,CAmC9B;IAED;;;;OAIG;IACG,MAAM,CACV,SAAS,EAAE,4BAA4B,EACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAKf;IAED;;;;;OAKG;IACG,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhF;IAED,yEAAyE;IACnE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAGzE;IAED;;;;;;;;OAQG;IACG,YAAY,CAChB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC,CA0B7C;IAED,oFAAoF;IAC9E,UAAU,CAAC,SAAS,EAAE,4BAA4B,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF;YAEa,WAAW;YAoBX,OAAO;IAUrB,OAAO,CAAC,sBAAsB;CAyC/B"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { ConflictError, NotFoundError, ValidationError, summarizeContract, } from '@cat-factory/kernel';
|
|
2
|
+
import { mergeFoundationalTiers, toWire } from './foundational-catalog.js';
|
|
3
|
+
import { validateUploadedContract } from './contract-validation.js';
|
|
4
|
+
/**
|
|
5
|
+
* The foundational-services catalog (docs/initiatives/foundational-services.md): per-tier CRUD
|
|
6
|
+
* plus the merged account ⊕ workspace resolve every design dispatch reads.
|
|
7
|
+
*
|
|
8
|
+
* Two properties are load-bearing and are why this is a service rather than a repository call:
|
|
9
|
+
*
|
|
10
|
+
* - **The catalog never carries a contract BODY.** `listTier` and `resolve` join the contract
|
|
11
|
+
* MANIFEST (id, format, title, byte size, operation names) onto each service in ONE extra
|
|
12
|
+
* query for the whole tier. The documents are read only by {@link contractsFor}, and only for
|
|
13
|
+
* the ids a caller asks for.
|
|
14
|
+
* - **A workspace row wins over an account row of the same id, and a workspace TOMBSTONE
|
|
15
|
+
* suppresses one.** That is what lets a board opt out of an org-wide service without an
|
|
16
|
+
* account admin, and it is why the merge reads the workspace tier `includeDeleted`.
|
|
17
|
+
*/
|
|
18
|
+
export class FoundationalServiceCatalogService {
|
|
19
|
+
deps;
|
|
20
|
+
constructor(deps) {
|
|
21
|
+
this.deps = deps;
|
|
22
|
+
}
|
|
23
|
+
/** One tier's registered services, contract manifests joined on. Raw — not merged. */
|
|
24
|
+
async listTier(ownerKind, ownerId) {
|
|
25
|
+
const [records, manifest] = await Promise.all([
|
|
26
|
+
this.deps.foundationalServiceRepository.listByOwner(ownerKind, ownerId),
|
|
27
|
+
this.deps.apiContractRepository.listManifestByOwner(ownerKind, ownerId),
|
|
28
|
+
]);
|
|
29
|
+
const byService = indexManifest(manifest);
|
|
30
|
+
return records.map((record) => toWire(record, byService.get(record.serviceId) ?? []));
|
|
31
|
+
}
|
|
32
|
+
/** Register a service at a tier. */
|
|
33
|
+
async create(ownerKind, ownerId, input) {
|
|
34
|
+
const existing = await this.deps.foundationalServiceRepository.get(ownerKind, ownerId, input.id);
|
|
35
|
+
// A LIVE row is a conflict; a tombstoned one is revived by this write. Refusing the
|
|
36
|
+
// revival would leave an id permanently unusable after one delete.
|
|
37
|
+
if (existing && !existing.deletedAt) {
|
|
38
|
+
throw new ConflictError(`Foundational service '${input.id}' already exists at this scope`, 'foundational_service_exists', { serviceId: input.id });
|
|
39
|
+
}
|
|
40
|
+
const now = this.deps.clock.now();
|
|
41
|
+
const record = {
|
|
42
|
+
serviceId: input.id,
|
|
43
|
+
ownerKind,
|
|
44
|
+
ownerId,
|
|
45
|
+
name: input.name,
|
|
46
|
+
summary: input.summary,
|
|
47
|
+
description: input.description,
|
|
48
|
+
capabilities: input.capabilities ?? [],
|
|
49
|
+
sourceId: null,
|
|
50
|
+
sourcePath: null,
|
|
51
|
+
pinnedCommit: null,
|
|
52
|
+
createdAt: existing?.createdAt ?? now,
|
|
53
|
+
updatedAt: now,
|
|
54
|
+
deletedAt: null,
|
|
55
|
+
};
|
|
56
|
+
await this.deps.foundationalServiceRepository.upsert(record);
|
|
57
|
+
const contracts = this.buildUploadedContracts(ownerKind, ownerId, input.id, input.contracts, now);
|
|
58
|
+
await this.deps.apiContractRepository.replaceForService(ownerKind, ownerId, input.id, contracts);
|
|
59
|
+
await this.invalidate(ownerKind, ownerId);
|
|
60
|
+
return toWire(record, contracts.map(manifestOf));
|
|
61
|
+
}
|
|
62
|
+
/** Patch a registered service. `contracts`, when present, replaces the whole set. */
|
|
63
|
+
async update(ownerKind, ownerId, serviceId, input) {
|
|
64
|
+
const existing = await this.require(ownerKind, ownerId, serviceId);
|
|
65
|
+
const now = this.deps.clock.now();
|
|
66
|
+
const record = {
|
|
67
|
+
...existing,
|
|
68
|
+
name: input.name ?? existing.name,
|
|
69
|
+
summary: input.summary ?? existing.summary,
|
|
70
|
+
description: input.description ?? existing.description,
|
|
71
|
+
capabilities: input.capabilities ?? existing.capabilities,
|
|
72
|
+
updatedAt: now,
|
|
73
|
+
};
|
|
74
|
+
await this.deps.foundationalServiceRepository.upsert(record);
|
|
75
|
+
let manifest;
|
|
76
|
+
if (input.contracts) {
|
|
77
|
+
const contracts = this.buildUploadedContracts(ownerKind, ownerId, serviceId, input.contracts, now);
|
|
78
|
+
await this.deps.apiContractRepository.replaceForService(ownerKind, ownerId, serviceId, contracts);
|
|
79
|
+
manifest = contracts.map(manifestOf);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
manifest = (await this.deps.apiContractRepository.listManifestByOwner(ownerKind, ownerId)).filter((entry) => entry.serviceId === serviceId);
|
|
83
|
+
}
|
|
84
|
+
await this.invalidate(ownerKind, ownerId);
|
|
85
|
+
return toWire(record, manifest);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Remove a service from a tier. A WORKSPACE removal writes a tombstone (which is also how a
|
|
89
|
+
* board suppresses an inherited account service); an ACCOUNT removal drops the row and its
|
|
90
|
+
* documents outright, since there is no higher tier for it to shadow.
|
|
91
|
+
*/
|
|
92
|
+
async remove(ownerKind, ownerId, serviceId) {
|
|
93
|
+
const now = this.deps.clock.now();
|
|
94
|
+
await this.deps.foundationalServiceRepository.softDelete(ownerKind, ownerId, serviceId, now);
|
|
95
|
+
await this.deps.apiContractRepository.deleteForService(ownerKind, ownerId, serviceId);
|
|
96
|
+
await this.invalidate(ownerKind, ownerId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Suppress an ACCOUNT service for one workspace by writing a workspace-tier tombstone. The
|
|
100
|
+
* row carries no content of its own — it exists only to lose the merge — so it is written
|
|
101
|
+
* here rather than through {@link create}, which would demand a name and summary for
|
|
102
|
+
* something that is never rendered.
|
|
103
|
+
*/
|
|
104
|
+
async suppressForWorkspace(workspaceId, serviceId) {
|
|
105
|
+
const now = this.deps.clock.now();
|
|
106
|
+
await this.deps.foundationalServiceRepository.upsert({
|
|
107
|
+
serviceId,
|
|
108
|
+
ownerKind: 'workspace',
|
|
109
|
+
ownerId: workspaceId,
|
|
110
|
+
name: '',
|
|
111
|
+
summary: '',
|
|
112
|
+
description: '',
|
|
113
|
+
capabilities: [],
|
|
114
|
+
sourceId: null,
|
|
115
|
+
sourcePath: null,
|
|
116
|
+
pinnedCommit: null,
|
|
117
|
+
createdAt: now,
|
|
118
|
+
updatedAt: now,
|
|
119
|
+
deletedAt: now,
|
|
120
|
+
});
|
|
121
|
+
await this.invalidate('workspace', workspaceId);
|
|
122
|
+
}
|
|
123
|
+
/** The merged catalog a workspace's agents see, cached per workspace. */
|
|
124
|
+
async resolve(workspaceId) {
|
|
125
|
+
if (!this.deps.catalogCache)
|
|
126
|
+
return this.loadCatalog(workspaceId);
|
|
127
|
+
return this.deps.catalogCache.get(workspaceId, workspaceId, () => this.loadCatalog(workspaceId));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The LAZY contract read: full documents for the named services, resolved against the same
|
|
131
|
+
* account ⊕ workspace precedence the catalog uses. One batched query per tier — never a
|
|
132
|
+
* per-service read — and an empty `serviceIds` returns `[]` without touching the store.
|
|
133
|
+
*
|
|
134
|
+
* Precedence matters here as much as in the catalog: a workspace that overrode a service
|
|
135
|
+
* must hand out ITS documents, or the design would be reviewed against the org's spec while
|
|
136
|
+
* the code is written against the board's.
|
|
137
|
+
*/
|
|
138
|
+
async contractsFor(workspaceId, serviceIds) {
|
|
139
|
+
const wanted = [...new Set(serviceIds)].filter(Boolean);
|
|
140
|
+
if (wanted.length === 0)
|
|
141
|
+
return new Map();
|
|
142
|
+
const accountId = await this.deps.workspaceRepository.accountOf(workspaceId);
|
|
143
|
+
const [workspaceDocs, accountDocs] = await Promise.all([
|
|
144
|
+
this.deps.apiContractRepository.listByServiceIds('workspace', workspaceId, wanted),
|
|
145
|
+
accountId
|
|
146
|
+
? this.deps.apiContractRepository.listByServiceIds('account', accountId, wanted)
|
|
147
|
+
: Promise.resolve([]),
|
|
148
|
+
]);
|
|
149
|
+
// Which TIER won for each id is decided by the catalog merge, not by which tier happens to
|
|
150
|
+
// hold documents: a workspace row that overrides an account one but ships no contract of
|
|
151
|
+
// its own must NOT silently inherit the account's documents, or the override reads as
|
|
152
|
+
// partially applied. So resolve the winning tier first, then take that tier's documents.
|
|
153
|
+
const catalog = await this.resolve(workspaceId);
|
|
154
|
+
const tierById = new Map(catalog.map((entry) => [entry.id, entry.tier]));
|
|
155
|
+
const out = new Map();
|
|
156
|
+
for (const id of wanted) {
|
|
157
|
+
const tier = tierById.get(id);
|
|
158
|
+
if (!tier)
|
|
159
|
+
continue;
|
|
160
|
+
const docs = (tier === 'workspace' ? workspaceDocs : accountDocs).filter((doc) => doc.serviceId === id);
|
|
161
|
+
out.set(id, docs.map(documentOf));
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/** Drop a tier's cached catalog. An account write invalidates every workspace's. */
|
|
166
|
+
async invalidate(ownerKind, ownerId) {
|
|
167
|
+
if (!this.deps.catalogCache)
|
|
168
|
+
return;
|
|
169
|
+
// A workspace write affects exactly one group; an account write affects every workspace in
|
|
170
|
+
// the account, and enumerating them would be a read per invalidation — over-invalidation is
|
|
171
|
+
// always safe, so the account path drops everything (the same call `FragmentLibraryService`
|
|
172
|
+
// makes for the same reason).
|
|
173
|
+
if (ownerKind === 'workspace')
|
|
174
|
+
await this.deps.catalogCache.invalidateGroup(ownerId);
|
|
175
|
+
else
|
|
176
|
+
await this.deps.catalogCache.invalidateAll();
|
|
177
|
+
}
|
|
178
|
+
async loadCatalog(workspaceId) {
|
|
179
|
+
const accountId = await this.deps.workspaceRepository.accountOf(workspaceId);
|
|
180
|
+
const [workspaceRows, accountRows, workspaceManifest, accountManifest] = await Promise.all([
|
|
181
|
+
this.deps.foundationalServiceRepository.listByOwner('workspace', workspaceId, true),
|
|
182
|
+
accountId
|
|
183
|
+
? this.deps.foundationalServiceRepository.listByOwner('account', accountId)
|
|
184
|
+
: Promise.resolve([]),
|
|
185
|
+
this.deps.apiContractRepository.listManifestByOwner('workspace', workspaceId),
|
|
186
|
+
accountId
|
|
187
|
+
? this.deps.apiContractRepository.listManifestByOwner('account', accountId)
|
|
188
|
+
: Promise.resolve([]),
|
|
189
|
+
]);
|
|
190
|
+
return mergeFoundationalTiers({
|
|
191
|
+
accountRows,
|
|
192
|
+
workspaceRows,
|
|
193
|
+
accountManifest: indexManifest(accountManifest),
|
|
194
|
+
workspaceManifest: indexManifest(workspaceManifest),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
async require(ownerKind, ownerId, serviceId) {
|
|
198
|
+
const record = await this.deps.foundationalServiceRepository.get(ownerKind, ownerId, serviceId);
|
|
199
|
+
if (!record || record.deletedAt)
|
|
200
|
+
throw new NotFoundError('FoundationalService', serviceId);
|
|
201
|
+
return record;
|
|
202
|
+
}
|
|
203
|
+
buildUploadedContracts(ownerKind, ownerId, serviceId, uploads, now) {
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
return (uploads ?? []).map((upload) => {
|
|
206
|
+
if (seen.has(upload.contractId)) {
|
|
207
|
+
throw new ValidationError(`Duplicate contract id '${upload.contractId}'`, {
|
|
208
|
+
reason: 'duplicate_contract_id',
|
|
209
|
+
contractId: upload.contractId,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
seen.add(upload.contractId);
|
|
213
|
+
validateUploadedContract(upload);
|
|
214
|
+
const summary = summarizeContract({
|
|
215
|
+
contractId: upload.contractId,
|
|
216
|
+
format: upload.format,
|
|
217
|
+
title: upload.title,
|
|
218
|
+
path: null,
|
|
219
|
+
body: upload.body,
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
ownerKind,
|
|
223
|
+
ownerId,
|
|
224
|
+
serviceId,
|
|
225
|
+
contractId: upload.contractId,
|
|
226
|
+
format: upload.format,
|
|
227
|
+
title: upload.title,
|
|
228
|
+
body: upload.body,
|
|
229
|
+
operations: summary.operations,
|
|
230
|
+
omittedOperations: summary.omittedOperations,
|
|
231
|
+
sourcePath: null,
|
|
232
|
+
sourceSha: null,
|
|
233
|
+
createdAt: now,
|
|
234
|
+
updatedAt: now,
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function indexManifest(entries) {
|
|
240
|
+
const map = new Map();
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
const list = map.get(entry.serviceId);
|
|
243
|
+
if (list)
|
|
244
|
+
list.push(entry);
|
|
245
|
+
else
|
|
246
|
+
map.set(entry.serviceId, [entry]);
|
|
247
|
+
}
|
|
248
|
+
return map;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* A just-written contract record → its manifest entry. The operation index is recomputed from
|
|
252
|
+
* the body here rather than read back, so a create/update response describes exactly what was
|
|
253
|
+
* stored without a second round trip.
|
|
254
|
+
*/
|
|
255
|
+
function manifestOf(record) {
|
|
256
|
+
return {
|
|
257
|
+
serviceId: record.serviceId,
|
|
258
|
+
contractId: record.contractId,
|
|
259
|
+
format: record.format,
|
|
260
|
+
title: record.title,
|
|
261
|
+
size: record.body.length,
|
|
262
|
+
operations: record.operations,
|
|
263
|
+
omittedOperations: record.omittedOperations,
|
|
264
|
+
sourcePath: record.sourcePath,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* A stored record → the wire document. The operation index is read off the ROW rather than
|
|
269
|
+
* recomputed: it is the same index the catalog showed, so a consumer can never see a document
|
|
270
|
+
* whose operation list disagrees with the one the design was chosen from.
|
|
271
|
+
*/
|
|
272
|
+
function documentOf(record) {
|
|
273
|
+
return {
|
|
274
|
+
contractId: record.contractId,
|
|
275
|
+
format: record.format,
|
|
276
|
+
title: record.title,
|
|
277
|
+
size: record.body.length,
|
|
278
|
+
path: record.sourcePath,
|
|
279
|
+
operations: record.operations,
|
|
280
|
+
omittedOperations: record.omittedOperations,
|
|
281
|
+
body: record.body,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=FoundationalServiceCatalogService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FoundationalServiceCatalogService.js","sourceRoot":"","sources":["../../src/foundationalServices/FoundationalServiceCatalogService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { FoundationalServiceSelection } from '@cat-factory/contracts';
|
|
2
|
+
import type { FoundationalCatalogView, InjectedContextFile } from '@cat-factory/kernel';
|
|
3
|
+
import type { FoundationalServiceCatalogService } from './FoundationalServiceCatalogService.js';
|
|
4
|
+
/**
|
|
5
|
+
* The engine-facing seam over the foundational-services catalog
|
|
6
|
+
* (docs/initiatives/foundational-services.md). Two reads, deliberately separate, because they
|
|
7
|
+
* serve the two halves of the feature:
|
|
8
|
+
*
|
|
9
|
+
* - {@link catalogFor} is the DESIGN-time read: identity, capabilities and operation names for
|
|
10
|
+
* every registered service, no document bodies. Folded into the Architect's prompt.
|
|
11
|
+
* - {@link contextFilesFor} is the CONSUMER-time read: the full contract documents, for exactly
|
|
12
|
+
* the ids the design declared, materialised as `.cat-context/foundational-services/*` files.
|
|
13
|
+
*
|
|
14
|
+
* Implemented against the catalog SERVICE rather than the repositories so both reads go through
|
|
15
|
+
* the same tier merge and the same cache — a consumer can never be handed the account's
|
|
16
|
+
* document for a service the design chose at the workspace tier.
|
|
17
|
+
*/
|
|
18
|
+
export declare class FoundationalServiceRunResolver {
|
|
19
|
+
private readonly catalog;
|
|
20
|
+
constructor(catalog: FoundationalServiceCatalogService);
|
|
21
|
+
/** The catalog the design step is shown. Empty array when nothing is registered. */
|
|
22
|
+
catalogFor(workspaceId: string): Promise<FoundationalCatalogView[]>;
|
|
23
|
+
/** Just the ids in the merged catalog — the check a settled design's declaration runs against. */
|
|
24
|
+
catalogIdsFor(workspaceId: string): Promise<string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* The injected context files a consumer kind receives for a design's declared services: one
|
|
27
|
+
* markdown file per service carrying its contract documents, plus an index.
|
|
28
|
+
*
|
|
29
|
+
* The INDEX is always produced, even when nothing was declared and nothing resolved. That is
|
|
30
|
+
* the "degrade loudly" half: a coder handed no foundational context cannot otherwise tell
|
|
31
|
+
* "the design decided none apply" from "the design step never ran" from "the design named a
|
|
32
|
+
* service this deployment does not have", and those need three different reactions.
|
|
33
|
+
*/
|
|
34
|
+
contextFilesFor(workspaceId: string, selection: FoundationalServiceSelection | undefined): Promise<InjectedContextFile[]>;
|
|
35
|
+
private hasCatalog;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=FoundationalServiceRunResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FoundationalServiceRunResolver.d.ts","sourceRoot":"","sources":["../../src/foundationalServices/FoundationalServiceRunResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAA;AAC1E,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAOvF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAA;AAE/F;;;;;;;;;;;;;GAaG;AACH,qBAAa,8BAA8B;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAApC,YAA6B,OAAO,EAAE,iCAAiC,EAAI;IAE3E,oFAAoF;IAC9E,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAUxE;IAED,kGAAkG;IAC5F,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAE1D;IAED;;;;;;;;OAQG;IACG,eAAe,CACnB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,4BAA4B,GAAG,SAAS,GAClD,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAyChC;YAEa,UAAU;CAGzB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { FOUNDATIONAL_INDEX_FILE, contextFileFor, renderContractDocument, renderFoundationalIndex, } from '@cat-factory/kernel';
|
|
2
|
+
/**
|
|
3
|
+
* The engine-facing seam over the foundational-services catalog
|
|
4
|
+
* (docs/initiatives/foundational-services.md). Two reads, deliberately separate, because they
|
|
5
|
+
* serve the two halves of the feature:
|
|
6
|
+
*
|
|
7
|
+
* - {@link catalogFor} is the DESIGN-time read: identity, capabilities and operation names for
|
|
8
|
+
* every registered service, no document bodies. Folded into the Architect's prompt.
|
|
9
|
+
* - {@link contextFilesFor} is the CONSUMER-time read: the full contract documents, for exactly
|
|
10
|
+
* the ids the design declared, materialised as `.cat-context/foundational-services/*` files.
|
|
11
|
+
*
|
|
12
|
+
* Implemented against the catalog SERVICE rather than the repositories so both reads go through
|
|
13
|
+
* the same tier merge and the same cache — a consumer can never be handed the account's
|
|
14
|
+
* document for a service the design chose at the workspace tier.
|
|
15
|
+
*/
|
|
16
|
+
export class FoundationalServiceRunResolver {
|
|
17
|
+
catalog;
|
|
18
|
+
constructor(catalog) {
|
|
19
|
+
this.catalog = catalog;
|
|
20
|
+
}
|
|
21
|
+
/** The catalog the design step is shown. Empty array when nothing is registered. */
|
|
22
|
+
async catalogFor(workspaceId) {
|
|
23
|
+
const resolved = await this.catalog.resolve(workspaceId);
|
|
24
|
+
return resolved.map((service) => ({
|
|
25
|
+
id: service.id,
|
|
26
|
+
name: service.name,
|
|
27
|
+
summary: service.summary,
|
|
28
|
+
description: service.description,
|
|
29
|
+
capabilities: service.capabilities,
|
|
30
|
+
contracts: service.contracts,
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
/** Just the ids in the merged catalog — the check a settled design's declaration runs against. */
|
|
34
|
+
async catalogIdsFor(workspaceId) {
|
|
35
|
+
return (await this.catalog.resolve(workspaceId)).map((service) => service.id);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The injected context files a consumer kind receives for a design's declared services: one
|
|
39
|
+
* markdown file per service carrying its contract documents, plus an index.
|
|
40
|
+
*
|
|
41
|
+
* The INDEX is always produced, even when nothing was declared and nothing resolved. That is
|
|
42
|
+
* the "degrade loudly" half: a coder handed no foundational context cannot otherwise tell
|
|
43
|
+
* "the design decided none apply" from "the design step never ran" from "the design named a
|
|
44
|
+
* service this deployment does not have", and those need three different reactions.
|
|
45
|
+
*/
|
|
46
|
+
async contextFilesFor(workspaceId, selection) {
|
|
47
|
+
const declared = selection?.declared ?? [];
|
|
48
|
+
const unknown = selection?.unknown ?? [];
|
|
49
|
+
const noDeclaration = selection === undefined;
|
|
50
|
+
// Nothing to say and nothing to warn about: a run in a deployment that registers no
|
|
51
|
+
// foundational services at all would otherwise pay for an index file on every dispatch
|
|
52
|
+
// saying so. A declaration that resolved to nothing is DIFFERENT and does get the file.
|
|
53
|
+
if (noDeclaration && unknown.length === 0 && !(await this.hasCatalog(workspaceId)))
|
|
54
|
+
return [];
|
|
55
|
+
const documents = await this.catalog.contractsFor(workspaceId, declared);
|
|
56
|
+
const resolved = await this.catalog.resolve(workspaceId);
|
|
57
|
+
const byId = new Map(resolved.map((service) => [service.id, service]));
|
|
58
|
+
const bundles = declared
|
|
59
|
+
.map((id) => {
|
|
60
|
+
const service = byId.get(id);
|
|
61
|
+
if (!service)
|
|
62
|
+
return null;
|
|
63
|
+
return {
|
|
64
|
+
id: service.id,
|
|
65
|
+
name: service.name,
|
|
66
|
+
summary: service.summary,
|
|
67
|
+
description: service.description,
|
|
68
|
+
contracts: (documents.get(id) ?? []).map((doc) => ({
|
|
69
|
+
contractId: doc.contractId,
|
|
70
|
+
format: doc.format,
|
|
71
|
+
title: doc.title,
|
|
72
|
+
body: doc.body,
|
|
73
|
+
})),
|
|
74
|
+
};
|
|
75
|
+
})
|
|
76
|
+
.filter((bundle) => bundle !== null);
|
|
77
|
+
const files = [
|
|
78
|
+
{
|
|
79
|
+
path: FOUNDATIONAL_INDEX_FILE,
|
|
80
|
+
content: renderFoundationalIndex({ bundles, unknown, noDeclaration }),
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
for (const bundle of bundles) {
|
|
84
|
+
files.push({ path: contextFileFor(bundle.id), content: renderContractDocument(bundle) });
|
|
85
|
+
}
|
|
86
|
+
return files;
|
|
87
|
+
}
|
|
88
|
+
async hasCatalog(workspaceId) {
|
|
89
|
+
return (await this.catalog.resolve(workspaceId)).length > 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=FoundationalServiceRunResolver.js.map
|