@cat-factory/kernel 0.300.0 → 0.302.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.
@@ -1 +1 @@
1
- {"version":3,"file":"cache-policy.d.ts","sourceRoot":"","sources":["../../src/domain/cache-policy.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,WAAW,GAInB,aAAa,GAEb,oBAAoB,GAEpB,MAAM,CAAA;AAEV,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAWjE;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE/D"}
1
+ {"version":3,"file":"cache-policy.d.ts","sourceRoot":"","sources":["../../src/domain/cache-policy.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,WAAW,GAInB,aAAa,GAEb,oBAAoB,GAEpB,MAAM,CAAA;AAEV,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAejE;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE/D"}
@@ -15,6 +15,10 @@ export function providerCachePolicy(provider) {
15
15
  case 'openai':
16
16
  case 'deepseek':
17
17
  case 'qwen':
18
+ // xAI caches prompt prefixes automatically and bills the hits at its own published
19
+ // cached-input rate, with no per-request opt-in, so it belongs with the auto-prefix
20
+ // group rather than Anthropic's explicit `cache_control` breakpoints.
21
+ case 'xai':
18
22
  return 'auto-prefix';
19
23
  case 'anthropic':
20
24
  return 'explicit-anthropic';
@@ -1 +1 @@
1
- {"version":3,"file":"cache-policy.js","sourceRoot":"","sources":["../../src/domain/cache-policy.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,qFAAqF;AACrF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,EAAE;AACF,sFAAsF;AACtF,mFAAmF;AACnF,uFAAuF;AACvF,kFAAkF;AAYlF,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,aAAa,CAAA;QACtB,KAAK,WAAW;YACd,OAAO,oBAAoB,CAAA;QAC7B;YACE,OAAO,MAAM,CAAA;IACjB,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAA;AACjD,CAAC"}
1
+ {"version":3,"file":"cache-policy.js","sourceRoot":"","sources":["../../src/domain/cache-policy.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,qFAAqF;AACrF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,oFAAoF;AACpF,EAAE;AACF,sFAAsF;AACtF,mFAAmF;AACnF,uFAAuF;AACvF,kFAAkF;AAYlF,wFAAwF;AACxF,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU,CAAC;QAChB,KAAK,MAAM,CAAC;QACZ,mFAAmF;QACnF,oFAAoF;QACpF,sEAAsE;QACtE,KAAK,KAAK;YACR,OAAO,aAAa,CAAA;QACtB,KAAK,WAAW;YACd,OAAO,oBAAoB,CAAA;QAC7B;YACE,OAAO,MAAM,CAAA;IACjB,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAA;AACjD,CAAC"}
@@ -0,0 +1,77 @@
1
+ import type { EnvironmentFailureReason } from './types.js';
2
+ import { UnavailableError } from './errors.js';
3
+ /**
4
+ * A provisioning failure carrying its machine-readable cause.
5
+ *
6
+ * `UnavailableError` for every class, including the manifest one, because `code` is the STATUS
7
+ * CLASS and the answer is uniformly "this environment could not be stood up"; the cause that
8
+ * differs is `details.reason`. That is the split the domain-error vocabulary asks for, and it is
9
+ * why there is no per-cause error class to choose between.
10
+ *
11
+ * An unclassified failure carries NO reason rather than a null one, so no reader can mistake
12
+ * "this was not classified" for a classification. That distinction is load-bearing: unclassified
13
+ * is not repo-fixable, and a provider that has not adopted this must never be read as having
14
+ * asserted something about its failures.
15
+ */
16
+ export declare function environmentFailure(message: string, reason: EnvironmentFailureReason | null | undefined): UnavailableError;
17
+ /**
18
+ * A `{{placeholder}}` a provider's templated inputs reference but cannot fill.
19
+ *
20
+ * Every built-in provider renders its manifests/compose files through the same lenient
21
+ * substitution, where an unknown key resolves to the empty string. That leniency is deliberate (a
22
+ * template may carry an optional value) and it is also how a correct file becomes an invalid one:
23
+ * `image: "{{image}}"` renders to `image: ""`, and the platform it is submitted to then reports a
24
+ * required field missing on a document whose source says nothing of the kind.
25
+ */
26
+ export interface UnresolvedPlaceholder {
27
+ /** The placeholder key as written, without braces. */
28
+ key: string;
29
+ /**
30
+ * The connection/handler field an operator sets to supply it, for a key the PLATFORM derives
31
+ * from configuration rather than from the run. Absent for a key nothing known fills, which is a
32
+ * template referencing something that was never going to exist and reads differently to whoever
33
+ * has to fix it.
34
+ */
35
+ configField?: string;
36
+ }
37
+ /**
38
+ * The placeholders `text` references that `vars` cannot fill, deduplicated and in order of first
39
+ * appearance.
40
+ *
41
+ * Scans the SOURCE, before substitution, because afterwards the evidence is gone: an empty string
42
+ * in a rendered file is indistinguishable from an empty string its author wrote. A key that is
43
+ * PRESENT but empty counts as unresolved too, since an operator who set the supplying field to a
44
+ * blank string has supplied nothing and the file breaks identically.
45
+ *
46
+ * `configFields` maps a placeholder key to the setting that supplies it, and is the provider's to
47
+ * pass because only the provider knows its own configuration shape (Kubernetes fills `{{image}}`
48
+ * from `imageTemplate`; another backend may fill it from something else, or not at all). Keys the
49
+ * RUN supplies (`blockId`, `branch`, `pullNumber`, …) are deliberately left out of that map: one
50
+ * of those rendering empty is a fact about the run, and naming a config field for it would send an
51
+ * operator to a setting that would not have helped.
52
+ */
53
+ export declare function unresolvedPlaceholders(text: string, vars: Record<string, string>, configFields?: Record<string, string>): UnresolvedPlaceholder[];
54
+ /**
55
+ * The operator-facing refusal for a template the deployment's own CONFIGURATION cannot fill, or
56
+ * `null` when there is nothing an operator could set.
57
+ *
58
+ * Refusing BEFORE submitting is the whole point, and providers should call this rather than
59
+ * rendering empties and letting the platform reject them. The rejection that comes back describes
60
+ * the RESULT and blames the file, which is how a correct `image: "{{image}}"` was reported as a
61
+ * Deployment missing a required image. This names the placeholder, names the field that fills it,
62
+ * and says the repository is not at fault, none of which the platform being deployed to could
63
+ * ever have told anyone.
64
+ *
65
+ * SCOPED to the keys carrying a `configField`, and that scope is the refusal's whole justification
66
+ * rather than a detail of it. A config-backed key is unambiguous: the platform undertook to supply
67
+ * the value, the deployment has not been told how, and the message can name the setting to change.
68
+ * Everything else unresolved is a key the RUN supplies, where absent and empty are the same value
69
+ * and opposite facts: `frontendOrigins` is absent for a service no frontend binds, `peerEnvUrls`
70
+ * for the first frame of a fan-out, `branch` and `pullNumber` for a peer frame that carries no PR
71
+ * context. Each renders empty on purpose, so a template that folds one into a CORS list or a label
72
+ * is CORRECT and refusing it would fail a provision naming no setting anyone could fix. The
73
+ * lenient substitution stays the documented behaviour there; only the class an operator can act on
74
+ * is worth stopping a deployment for.
75
+ */
76
+ export declare function describeUnfilledConfigPlaceholders(missing: UnresolvedPlaceholder[]): string | null;
77
+ //# sourceMappingURL=environment-failure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-failure.d.ts","sourceRoot":"","sources":["../../src/domain/environment-failure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AA4B9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,wBAAwB,GAAG,IAAI,GAAG,SAAS,GAClD,gBAAgB,CAElB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAA;IACX;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACxC,qBAAqB,EAAE,CAYzB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,qBAAqB,EAAE,GAC/B,MAAM,GAAG,IAAI,CAaf"}
@@ -0,0 +1,106 @@
1
+ import { UnavailableError } from './errors.js';
2
+ // ---------------------------------------------------------------------------
3
+ // The PROVIDER-NEUTRAL half of environment-failure classification: what any environment
4
+ // provider — the built-in Kubernetes / compose / Cloudflare backends, and equally a backend a
5
+ // deployment registers into `EnvironmentBackendRegistry` — uses to say WHY a provision failed in
6
+ // a way the engine can act on.
7
+ //
8
+ // It lives in kernel rather than beside the Kubernetes provider precisely because a custom
9
+ // backend must be able to participate. The engine's remediation decision ("may an automated fixer
10
+ // be dispatched at this failure?") is keyed off `EnvironmentFailureReason`, so a provider that
11
+ // cannot state a reason gets the safe answer (never fixable) and is silently excluded from the
12
+ // mechanism. Giving it the same helpers the built-ins use is what makes the classification an
13
+ // extension point instead of a Kubernetes-only feature.
14
+ //
15
+ // A custom provider participates by doing one of two things, both optional and both degrading
16
+ // safely, and WHICH one is decided by how it reports the failure rather than by preference:
17
+ // 1. a provider that THROWS raises {@link environmentFailure} (or any `DomainError` carrying
18
+ // `details.reason`) instead of a bare `Error`, so the engine reads the class off the error
19
+ // rather than out of the prose;
20
+ // 2. a provider that instead returns `status: 'failed'` (a deterministic rejection it did not
21
+ // consider exceptional, and the shape every container-backed provision settles into) has no
22
+ // error to carry a reason, so it states one on `ProvisionedEnvironment.reason`. The engine
23
+ // threads that alongside the handle to the same decision the thrown reason reaches.
24
+ // A provider that does neither behaves exactly as every provider did before this existed: its
25
+ // failures are unclassified, and unclassified is never repo-fixable.
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * A provisioning failure carrying its machine-readable cause.
29
+ *
30
+ * `UnavailableError` for every class, including the manifest one, because `code` is the STATUS
31
+ * CLASS and the answer is uniformly "this environment could not be stood up"; the cause that
32
+ * differs is `details.reason`. That is the split the domain-error vocabulary asks for, and it is
33
+ * why there is no per-cause error class to choose between.
34
+ *
35
+ * An unclassified failure carries NO reason rather than a null one, so no reader can mistake
36
+ * "this was not classified" for a classification. That distinction is load-bearing: unclassified
37
+ * is not repo-fixable, and a provider that has not adopted this must never be read as having
38
+ * asserted something about its failures.
39
+ */
40
+ export function environmentFailure(message, reason) {
41
+ return new UnavailableError(message, reason ?? undefined);
42
+ }
43
+ /**
44
+ * The placeholders `text` references that `vars` cannot fill, deduplicated and in order of first
45
+ * appearance.
46
+ *
47
+ * Scans the SOURCE, before substitution, because afterwards the evidence is gone: an empty string
48
+ * in a rendered file is indistinguishable from an empty string its author wrote. A key that is
49
+ * PRESENT but empty counts as unresolved too, since an operator who set the supplying field to a
50
+ * blank string has supplied nothing and the file breaks identically.
51
+ *
52
+ * `configFields` maps a placeholder key to the setting that supplies it, and is the provider's to
53
+ * pass because only the provider knows its own configuration shape (Kubernetes fills `{{image}}`
54
+ * from `imageTemplate`; another backend may fill it from something else, or not at all). Keys the
55
+ * RUN supplies (`blockId`, `branch`, `pullNumber`, …) are deliberately left out of that map: one
56
+ * of those rendering empty is a fact about the run, and naming a config field for it would send an
57
+ * operator to a setting that would not have helped.
58
+ */
59
+ export function unresolvedPlaceholders(text, vars, configFields = {}) {
60
+ const found = new Map();
61
+ // The same pattern the providers substitute with, so the two cannot disagree about what counts
62
+ // as a placeholder.
63
+ for (const match of text.matchAll(/\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/g)) {
64
+ const key = match[1];
65
+ if (found.has(key))
66
+ continue;
67
+ if ((vars[key] ?? '') !== '')
68
+ continue;
69
+ const configField = configFields[key];
70
+ found.set(key, { key, ...(configField ? { configField } : {}) });
71
+ }
72
+ return [...found.values()];
73
+ }
74
+ /**
75
+ * The operator-facing refusal for a template the deployment's own CONFIGURATION cannot fill, or
76
+ * `null` when there is nothing an operator could set.
77
+ *
78
+ * Refusing BEFORE submitting is the whole point, and providers should call this rather than
79
+ * rendering empties and letting the platform reject them. The rejection that comes back describes
80
+ * the RESULT and blames the file, which is how a correct `image: "{{image}}"` was reported as a
81
+ * Deployment missing a required image. This names the placeholder, names the field that fills it,
82
+ * and says the repository is not at fault, none of which the platform being deployed to could
83
+ * ever have told anyone.
84
+ *
85
+ * SCOPED to the keys carrying a `configField`, and that scope is the refusal's whole justification
86
+ * rather than a detail of it. A config-backed key is unambiguous: the platform undertook to supply
87
+ * the value, the deployment has not been told how, and the message can name the setting to change.
88
+ * Everything else unresolved is a key the RUN supplies, where absent and empty are the same value
89
+ * and opposite facts: `frontendOrigins` is absent for a service no frontend binds, `peerEnvUrls`
90
+ * for the first frame of a fan-out, `branch` and `pullNumber` for a peer frame that carries no PR
91
+ * context. Each renders empty on purpose, so a template that folds one into a CORS list or a label
92
+ * is CORRECT and refusing it would fail a provision naming no setting anyone could fix. The
93
+ * lenient substitution stays the documented behaviour there; only the class an operator can act on
94
+ * is worth stopping a deployment for.
95
+ */
96
+ export function describeUnfilledConfigPlaceholders(missing) {
97
+ const blocking = missing.filter((m) => m.configField);
98
+ if (blocking.length === 0)
99
+ return null;
100
+ const items = blocking.map((m) => `'{{${m.key}}}' (supplied by this environment connection's '${m.configField}' setting, which is not set)`);
101
+ return (`The deployment files could not be rendered: ${items.join('; ')}. ` +
102
+ 'The repository is not at fault here and editing these files is the wrong fix: the ' +
103
+ 'placeholder exists so the value can vary per environment, and hard-coding it would defeat ' +
104
+ 'that. Set the missing configuration on the environment connection and retry.');
105
+ }
106
+ //# sourceMappingURL=environment-failure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-failure.js","sourceRoot":"","sources":["../../src/domain/environment-failure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,8EAA8E;AAC9E,wFAAwF;AACxF,8FAA8F;AAC9F,iGAAiG;AACjG,+BAA+B;AAC/B,EAAE;AACF,2FAA2F;AAC3F,kGAAkG;AAClG,+FAA+F;AAC/F,+FAA+F;AAC/F,8FAA8F;AAC9F,wDAAwD;AACxD,EAAE;AACF,8FAA8F;AAC9F,4FAA4F;AAC5F,+FAA+F;AAC/F,gGAAgG;AAChG,qCAAqC;AACrC,gGAAgG;AAChG,iGAAiG;AACjG,gGAAgG;AAChG,yFAAyF;AACzF,8FAA8F;AAC9F,qEAAqE;AACrE,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,MAAmD;IAEnD,OAAO,IAAI,gBAAgB,CAAC,OAAO,EAAE,MAAM,IAAI,SAAS,CAAC,CAAA;AAC3D,CAAC;AAuBD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,IAA4B,EAC5B,YAAY,GAA2B,EAAE;IAEzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiC,CAAA;IACtD,+FAA+F;IAC/F,oBAAoB;IACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,iCAAiC,CAAC,EAAE,CAAC;QACrE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE;YAAE,SAAQ;QACtC,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;QACrC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,kCAAkC,CAChD,OAAgC;IAEhC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CACxB,CAAC,CAAC,EAAE,EAAE,CACJ,MAAM,CAAC,CAAC,GAAG,mDAAmD,CAAC,CAAC,WAAW,8BAA8B,CAC5G,CAAA;IACD,OAAO,CACL,+CAA+C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QACnE,oFAAoF;QACpF,4FAA4F;QAC5F,8EAA8E,CAC/E,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SelectableModel } from './models.js';
2
+ export declare const MODEL_CATALOG: SelectableModel[];
3
+ //# sourceMappingURL=model-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../../src/domain/model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAiClD,eAAO,MAAM,aAAa,EAAE,eAAe,EAkkB1C,CAAA"}