@jini-ai/daemon 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/agent-executor.d.ts +216 -24
  2. package/dist/agent-executor.d.ts.map +1 -1
  3. package/dist/agent-executor.js +373 -38
  4. package/dist/agent-executor.js.map +1 -1
  5. package/dist/run-lifecycle.d.ts +36 -1
  6. package/dist/run-lifecycle.d.ts.map +1 -1
  7. package/dist/run-lifecycle.js +89 -0
  8. package/dist/run-lifecycle.js.map +1 -1
  9. package/package.json +5 -5
  10. package/dist/artifacts/index.d.ts +0 -14
  11. package/dist/artifacts/index.d.ts.map +0 -1
  12. package/dist/artifacts/index.js +0 -14
  13. package/dist/artifacts/index.js.map +0 -1
  14. package/dist/artifacts/manifest.d.ts +0 -90
  15. package/dist/artifacts/manifest.d.ts.map +0 -1
  16. package/dist/artifacts/manifest.js +0 -229
  17. package/dist/artifacts/manifest.js.map +0 -1
  18. package/dist/artifacts/publication-guard.d.ts +0 -28
  19. package/dist/artifacts/publication-guard.d.ts.map +0 -1
  20. package/dist/artifacts/publication-guard.js +0 -77
  21. package/dist/artifacts/publication-guard.js.map +0 -1
  22. package/dist/artifacts/runtime-compat.d.ts +0 -37
  23. package/dist/artifacts/runtime-compat.d.ts.map +0 -1
  24. package/dist/artifacts/runtime-compat.js +0 -33
  25. package/dist/artifacts/runtime-compat.js.map +0 -1
  26. package/dist/artifacts/store.d.ts +0 -85
  27. package/dist/artifacts/store.d.ts.map +0 -1
  28. package/dist/artifacts/store.js +0 -92
  29. package/dist/artifacts/store.js.map +0 -1
  30. package/dist/artifacts/stub-guard.d.ts +0 -73
  31. package/dist/artifacts/stub-guard.d.ts.map +0 -1
  32. package/dist/artifacts/stub-guard.js +0 -198
  33. package/dist/artifacts/stub-guard.js.map +0 -1
  34. package/dist/artifacts/text-suppression.d.ts +0 -68
  35. package/dist/artifacts/text-suppression.d.ts.map +0 -1
  36. package/dist/artifacts/text-suppression.js +0 -184
  37. package/dist/artifacts/text-suppression.js.map +0 -1
@@ -1,37 +0,0 @@
1
- /**
2
- * @module artifacts/runtime-compat
3
- *
4
- * The runtime-compat injection seam: a hook that gets a chance to rewrite an
5
- * artifact's body before it's served, for CDN/library-loading quirks a host
6
- * knows about but the engine can't. Ported from OD's
7
- * `apps/daemon/src/artifacts/runtime-compat.ts`.
8
- *
9
- * De-branded: the origin, `normalizeArtifactRuntimeImports`, is entirely a
10
- * fix for one specific third-party CDN-bundle bug (the vanilla `dist/
11
- * motion.js` UMD script tag lacking React hooks, rewritten to `dist/
12
- * framer-motion.js`) that OD's own system prompt steers models toward
13
- * hitting. That rewrite rule is product/library-specific knowledge, not a
14
- * generic engine mechanism — per the task brief ("keep OD's specific logic
15
- * as adapter"), it is not ported. What *is* generic and kept is the
16
- * seam itself: a host may need to rewrite an artifact body for any number
17
- * of environment-specific reasons (a different CDN quirk, a different
18
- * runtime library entirely) before it reaches a renderer, so the engine
19
- * defines the hook type and a safe default (identity) rather than hardcode
20
- * any one library's fix.
21
- */
22
- /**
23
- * Rewrites an artifact body before it is served, keyed by the artifact's
24
- * file name (a host typically gates on file extension, as OD's origin did
25
- * with `.html`/`.htm`). Returns the body unchanged when no rewrite applies.
26
- */
27
- export type RuntimeCompatNormalizer = (name: string, body: unknown) => unknown;
28
- /** Applies no rewrite — returns `body` unchanged. Safe default until a host supplies its own normalizer(s). */
29
- export declare const noopRuntimeCompatNormalizer: RuntimeCompatNormalizer;
30
- /**
31
- * Composes several normalizers into one, applying each in order — the
32
- * output of one becomes the input to the next. Lets a host layer multiple
33
- * independent CDN/library fixes without each needing to know about the
34
- * others.
35
- */
36
- export declare function composeRuntimeCompatNormalizers(normalizers: readonly RuntimeCompatNormalizer[]): RuntimeCompatNormalizer;
37
- //# sourceMappingURL=runtime-compat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-compat.d.ts","sourceRoot":"","sources":["../../src/artifacts/runtime-compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;AAE/E,+GAA+G;AAC/G,eAAO,MAAM,2BAA2B,EAAE,uBAA+C,CAAC;AAE1F;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,SAAS,uBAAuB,EAAE,GAC9C,uBAAuB,CAEzB"}
@@ -1,33 +0,0 @@
1
- /**
2
- * @module artifacts/runtime-compat
3
- *
4
- * The runtime-compat injection seam: a hook that gets a chance to rewrite an
5
- * artifact's body before it's served, for CDN/library-loading quirks a host
6
- * knows about but the engine can't. Ported from OD's
7
- * `apps/daemon/src/artifacts/runtime-compat.ts`.
8
- *
9
- * De-branded: the origin, `normalizeArtifactRuntimeImports`, is entirely a
10
- * fix for one specific third-party CDN-bundle bug (the vanilla `dist/
11
- * motion.js` UMD script tag lacking React hooks, rewritten to `dist/
12
- * framer-motion.js`) that OD's own system prompt steers models toward
13
- * hitting. That rewrite rule is product/library-specific knowledge, not a
14
- * generic engine mechanism — per the task brief ("keep OD's specific logic
15
- * as adapter"), it is not ported. What *is* generic and kept is the
16
- * seam itself: a host may need to rewrite an artifact body for any number
17
- * of environment-specific reasons (a different CDN quirk, a different
18
- * runtime library entirely) before it reaches a renderer, so the engine
19
- * defines the hook type and a safe default (identity) rather than hardcode
20
- * any one library's fix.
21
- */
22
- /** Applies no rewrite — returns `body` unchanged. Safe default until a host supplies its own normalizer(s). */
23
- export const noopRuntimeCompatNormalizer = (_name, body) => body;
24
- /**
25
- * Composes several normalizers into one, applying each in order — the
26
- * output of one becomes the input to the next. Lets a host layer multiple
27
- * independent CDN/library fixes without each needing to know about the
28
- * others.
29
- */
30
- export function composeRuntimeCompatNormalizers(normalizers) {
31
- return (name, body) => normalizers.reduce((current, normalize) => normalize(name, current), body);
32
- }
33
- //# sourceMappingURL=runtime-compat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-compat.js","sourceRoot":"","sources":["../../src/artifacts/runtime-compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,+GAA+G;AAC/G,MAAM,CAAC,MAAM,2BAA2B,GAA4B,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC7C,WAA+C;IAE/C,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;AACpG,CAAC"}
@@ -1,85 +0,0 @@
1
- /**
2
- * @module artifacts/store
3
- *
4
- * `ArtifactStore` — the generic artifact-store kernel port. Ported from OD's
5
- * `apps/daemon/src/artifacts/create.ts` create/manifest-resolution flow;
6
- * "artifacts feel like a kernel-adjacent concept tied to runs producing
7
- * output" per this task's brief — homed in `@jini/daemon` alongside
8
- * `EventLog` (same async-port + in-memory-reference-implementation shape as
9
- * `event-log.ts`), not `@jini/core` (which owns pure registries/DI, not
10
- * stateful storage).
11
- *
12
- * De-branded: the origin's `createProjectArtifactFile` took OD's own
13
- * product-shaped workspace/file-tree writer (a function keyed on OD's own
14
- * workspace-root and workspace-id nouns) as its injected dependency, and a
15
- * companion `postCreateArtifactRequest` built a request body for OD's own
16
- * per-workspace HTTP file-upload route. Neither is a generic engine concern
17
- * (a workspace model and an HTTP route shape are product surfaces), so this
18
- * port defines `ArtifactStore.create/get/list` directly against an
19
- * in-memory reference map — the origin's writer/request-builder pair were
20
- * the composition points a real OD adapter would wire against this port
21
- * from, not something to port verbatim. OD's HTML-prototype file-kind
22
- * inference (`inferLegacyManifest`) stays adapter-owned — see
23
- * `manifest.ts`'s `ManifestInferrer` seam.
24
- */
25
- import { type ArtifactManifest, type ArtifactManifestTaxonomy, type ManifestInferrer } from './manifest.js';
26
- export declare class ArtifactManifestRequiredError extends Error {
27
- readonly code: "ARTIFACT_MANIFEST_REQUIRED";
28
- constructor(name: string);
29
- }
30
- export declare class ArtifactManifestInvalidError extends Error {
31
- readonly code: "ARTIFACT_MANIFEST_INVALID";
32
- constructor(message: string);
33
- }
34
- export interface CreateArtifactInput {
35
- readonly name: string;
36
- readonly content: string;
37
- readonly encoding?: 'utf8' | 'base64';
38
- /** Explicit manifest fields, or `undefined` to fall back to the store's {@link ManifestInferrer}. */
39
- readonly artifactManifest?: unknown;
40
- }
41
- export interface ArtifactRecord {
42
- readonly name: string;
43
- readonly content: Buffer;
44
- readonly manifest: ArtifactManifest;
45
- }
46
- /**
47
- * A replayable, ordered artifact-manifest resolver: given a create request,
48
- * either the caller-supplied manifest (validated against `taxonomy`) or the
49
- * result of `inferManifest(name)` (also validated) becomes the record's
50
- * manifest. Throws {@link ArtifactManifestRequiredError} when neither
51
- * source produces one, {@link ArtifactManifestInvalidError} when the
52
- * resolved manifest fails validation.
53
- */
54
- export declare function resolveArtifactManifest(input: CreateArtifactInput, taxonomy: ArtifactManifestTaxonomy, inferManifest: ManifestInferrer): ArtifactManifest;
55
- /**
56
- * A store of named artifacts with validated manifests. Kernel port —
57
- * `@jini/daemon` ships `createInMemoryArtifactStore` as the reference
58
- * implementation; a durable adapter (`@jini/sqlite`) can implement the same
59
- * interface against real persistence.
60
- */
61
- export interface ArtifactStore {
62
- /**
63
- * Creates or overwrites the artifact named `input.name`, resolving its
64
- * manifest per {@link resolveArtifactManifest}.
65
- * @throws {ArtifactManifestRequiredError} No manifest supplied and the inferrer produced none.
66
- * @throws {ArtifactManifestInvalidError} The resolved manifest failed taxonomy validation.
67
- */
68
- create(input: CreateArtifactInput): Promise<ArtifactRecord>;
69
- /** Returns the named artifact, or `null` if it doesn't exist. */
70
- get(name: string): Promise<ArtifactRecord | null>;
71
- /** Returns every stored artifact, most-recently-updated first. */
72
- list(): Promise<ArtifactRecord[]>;
73
- }
74
- export interface InMemoryArtifactStoreOptions {
75
- readonly taxonomy?: ArtifactManifestTaxonomy;
76
- readonly inferManifest?: ManifestInferrer;
77
- }
78
- /**
79
- * Reference `ArtifactStore` implementation: an in-memory `Map` keyed by
80
- * artifact name. No durable persistence — matching this task's scope (a
81
- * real persistent adapter is a future storage task's concern, mirroring
82
- * `event-log.ts`'s own in-memory-only reference implementation).
83
- */
84
- export declare function createInMemoryArtifactStore(options?: InMemoryArtifactStoreOptions): ArtifactStore;
85
- //# sourceMappingURL=store.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/artifacts/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAEvB,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,EAAG,4BAA4B,CAAU;gBAE1C,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,EAAG,2BAA2B,CAAU;gBAEzC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACtC,qGAAqG;IACrG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,wBAAwB,EAClC,aAAa,EAAE,gBAAgB,GAC9B,gBAAgB,CAelB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,iEAAiE;IACjE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAClD,kEAAkE;IAClE,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,aAAa,CA0BrG"}
@@ -1,92 +0,0 @@
1
- /**
2
- * @module artifacts/store
3
- *
4
- * `ArtifactStore` — the generic artifact-store kernel port. Ported from OD's
5
- * `apps/daemon/src/artifacts/create.ts` create/manifest-resolution flow;
6
- * "artifacts feel like a kernel-adjacent concept tied to runs producing
7
- * output" per this task's brief — homed in `@jini/daemon` alongside
8
- * `EventLog` (same async-port + in-memory-reference-implementation shape as
9
- * `event-log.ts`), not `@jini/core` (which owns pure registries/DI, not
10
- * stateful storage).
11
- *
12
- * De-branded: the origin's `createProjectArtifactFile` took OD's own
13
- * product-shaped workspace/file-tree writer (a function keyed on OD's own
14
- * workspace-root and workspace-id nouns) as its injected dependency, and a
15
- * companion `postCreateArtifactRequest` built a request body for OD's own
16
- * per-workspace HTTP file-upload route. Neither is a generic engine concern
17
- * (a workspace model and an HTTP route shape are product surfaces), so this
18
- * port defines `ArtifactStore.create/get/list` directly against an
19
- * in-memory reference map — the origin's writer/request-builder pair were
20
- * the composition points a real OD adapter would wire against this port
21
- * from, not something to port verbatim. OD's HTML-prototype file-kind
22
- * inference (`inferLegacyManifest`) stays adapter-owned — see
23
- * `manifest.ts`'s `ManifestInferrer` seam.
24
- */
25
- import { emptyArtifactManifestTaxonomy, noopManifestInferrer, validateArtifactManifestInput, } from './manifest.js';
26
- export class ArtifactManifestRequiredError extends Error {
27
- code = 'ARTIFACT_MANIFEST_REQUIRED';
28
- constructor(name) {
29
- super(`artifactManifest is required for ${name}; no safe default manifest can be inferred`);
30
- this.name = 'ArtifactManifestRequiredError';
31
- }
32
- }
33
- export class ArtifactManifestInvalidError extends Error {
34
- code = 'ARTIFACT_MANIFEST_INVALID';
35
- constructor(message) {
36
- super(`invalid artifactManifest: ${message}`);
37
- this.name = 'ArtifactManifestInvalidError';
38
- }
39
- }
40
- /**
41
- * A replayable, ordered artifact-manifest resolver: given a create request,
42
- * either the caller-supplied manifest (validated against `taxonomy`) or the
43
- * result of `inferManifest(name)` (also validated) becomes the record's
44
- * manifest. Throws {@link ArtifactManifestRequiredError} when neither
45
- * source produces one, {@link ArtifactManifestInvalidError} when the
46
- * resolved manifest fails validation.
47
- */
48
- export function resolveArtifactManifest(input, taxonomy, inferManifest) {
49
- const manifest = input.artifactManifest !== undefined && input.artifactManifest !== null
50
- ? input.artifactManifest
51
- : inferManifest(input.name);
52
- if (manifest) {
53
- const validated = validateArtifactManifestInput(manifest, input.name, taxonomy);
54
- if (!validated.ok) {
55
- throw new ArtifactManifestInvalidError(validated.error);
56
- }
57
- // `manifest != null` above and `validateArtifactManifestInput` only
58
- // returns `{ ok: true, value: null }` when its own `manifest` param is
59
- // `== null` — so `validated.value` is non-null here.
60
- return validated.value;
61
- }
62
- throw new ArtifactManifestRequiredError(input.name);
63
- }
64
- /**
65
- * Reference `ArtifactStore` implementation: an in-memory `Map` keyed by
66
- * artifact name. No durable persistence — matching this task's scope (a
67
- * real persistent adapter is a future storage task's concern, mirroring
68
- * `event-log.ts`'s own in-memory-only reference implementation).
69
- */
70
- export function createInMemoryArtifactStore(options = {}) {
71
- const taxonomy = options.taxonomy ?? emptyArtifactManifestTaxonomy;
72
- const inferManifest = options.inferManifest ?? noopManifestInferrer;
73
- const records = new Map();
74
- return {
75
- async create(input) {
76
- const manifest = resolveArtifactManifest(input, taxonomy, inferManifest);
77
- const content = input.encoding === 'base64'
78
- ? Buffer.from(input.content, 'base64')
79
- : Buffer.from(input.content, 'utf8');
80
- const record = { name: input.name, content, manifest };
81
- records.set(input.name, record);
82
- return record;
83
- },
84
- async get(name) {
85
- return records.get(name) ?? null;
86
- },
87
- async list() {
88
- return Array.from(records.values()).sort((a, b) => b.manifest.updatedAt.localeCompare(a.manifest.updatedAt));
89
- },
90
- };
91
- }
92
- //# sourceMappingURL=store.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/artifacts/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,6BAA6B,GAI9B,MAAM,eAAe,CAAC;AAEvB,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAC7C,IAAI,GAAG,4BAAqC,CAAC;IAEtD,YAAY,IAAY;QACtB,KAAK,CAAC,oCAAoC,IAAI,4CAA4C,CAAC,CAAC;QAC5F,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,IAAI,GAAG,2BAAoC,CAAC;IAErD,YAAY,OAAe;QACzB,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAgBD;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAA0B,EAC1B,QAAkC,EAClC,aAA+B;IAE/B,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,KAAK,SAAS,IAAI,KAAK,CAAC,gBAAgB,KAAK,IAAI;QACtF,CAAC,CAAC,KAAK,CAAC,gBAAgB;QACxB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,6BAA6B,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAChF,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,4BAA4B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1D,CAAC;QACD,oEAAoE;QACpE,uEAAuE;QACvE,qDAAqD;QACrD,OAAO,SAAS,CAAC,KAAM,CAAC;IAC1B,CAAC;IACD,MAAM,IAAI,6BAA6B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AA2BD;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,UAAwC,EAAE;IACpF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,6BAA6B,CAAC;IACnE,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,oBAAoB,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAElD,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA0B;YACrC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YACzE,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,KAAK,QAAQ;gBACzC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC;gBACtC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvC,MAAM,MAAM,GAAmB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAChC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,IAAY;YACpB,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;QACnC,CAAC;QAED,KAAK,CAAC,IAAI;YACR,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CACnE,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,73 +0,0 @@
1
- export type ArtifactStubGuardMode = 'reject' | 'warn' | 'off';
2
- export interface ArtifactStubGuardConfig {
3
- readonly mode: ArtifactStubGuardMode;
4
- readonly minRetainedRatio: number;
5
- readonly minPriorBytes: number;
6
- /** File-name extensions (including the leading dot) this guard scans for prior siblings, e.g. `['.html', '.htm']`. */
7
- readonly siblingExtensions: readonly string[];
8
- }
9
- export interface PriorArtifactSibling {
10
- readonly name: string;
11
- readonly size: number;
12
- }
13
- export interface ArtifactStubGuardWarning {
14
- readonly code: 'ARTIFACT_REGRESSION';
15
- readonly message: string;
16
- readonly identifier: string;
17
- readonly newSize: number;
18
- readonly priorSize: number;
19
- readonly priorName: string;
20
- }
21
- export interface EvaluateArtifactStubGuardInput {
22
- readonly scanDir: string;
23
- readonly identifier: string;
24
- readonly newSize: number;
25
- readonly config: ArtifactStubGuardConfig;
26
- }
27
- export interface EvaluateArtifactStubGuardResult {
28
- readonly outcome: 'pass' | 'warn' | 'reject';
29
- readonly warning?: ArtifactStubGuardWarning;
30
- }
31
- export declare class ArtifactRegressionError extends Error {
32
- readonly code = "ARTIFACT_REGRESSION";
33
- readonly identifier: string;
34
- readonly newSize: number;
35
- readonly priorSize: number;
36
- readonly priorName: string;
37
- constructor(message: string, details: {
38
- identifier: string;
39
- newSize: number;
40
- priorSize: number;
41
- priorName: string;
42
- });
43
- }
44
- export declare const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG: ArtifactStubGuardConfig;
45
- /** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
46
- export declare function slugifyArtifactIdentifier(value: string): string;
47
- /** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
48
- export declare const EMPTY_SLUG_FALLBACK_NAME = "artifact";
49
- /**
50
- * Two identifiers refer to the same artifact lineage when they're literally
51
- * equal, or one is the canonical slug form of the other (and that slug is
52
- * non-empty). Slug equality alone is not enough: a slugifier that truncates
53
- * at a fixed length would otherwise falsely bridge two distinct identifiers
54
- * that only diverge past that length — requiring one side to *be* the slug
55
- * form of the other avoids that while still bridging e.g. "Landing Page" and
56
- * "landing-page".
57
- */
58
- export declare function artifactIdentifiersMatch(a: string, b: string): boolean;
59
- /**
60
- * Finds prior siblings on disk that share an identifier with a newly-written
61
- * artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
62
- * The scan deliberately includes any file at the same path as the new write
63
- * — when a write overwrites an existing file with the same name, the file
64
- * currently on disk is the prior content (the overwrite happens after this
65
- * scan runs).
66
- */
67
- export declare function findPriorArtifactSiblings(scanDir: string, identifier: string, config: Pick<ArtifactStubGuardConfig, 'siblingExtensions'>): Promise<PriorArtifactSibling[]>;
68
- /** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
69
- export declare function readArtifactStubGuardConfigFromEnv(env?: NodeJS.ProcessEnv, defaults?: ArtifactStubGuardConfig): ArtifactStubGuardConfig;
70
- /** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
71
- export declare function classifyArtifactStubGuard(priors: readonly PriorArtifactSibling[], identifier: string, newSize: number, config: ArtifactStubGuardConfig): EvaluateArtifactStubGuardResult;
72
- export declare function evaluateArtifactStubGuard(input: EvaluateArtifactStubGuardInput): Promise<EvaluateArtifactStubGuardResult>;
73
- //# sourceMappingURL=stub-guard.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stub-guard.d.ts","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sHAAsH;IACtH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;CAC1C;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;CAC7C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAGzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;CASzF;AAED,eAAO,MAAM,kCAAkC,EAAE,uBAKhD,CAAC;AAMF,8GAA8G;AAC9G,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,wHAAwH;AACxH,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAOtE;AA0BD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,GACzD,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA2CjC;AAED,uLAAuL;AACvL,wBAAgB,kCAAkC,CAChD,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,uBAA4D,GACrE,uBAAuB,CAezB;AAiBD,gMAAgM;AAChM,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,uBAAuB,GAC9B,+BAA+B,CAqBjC;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAK1C"}
@@ -1,198 +0,0 @@
1
- import { readFile, readdir, stat } from 'node:fs/promises';
2
- import path from 'node:path';
3
- export class ArtifactRegressionError extends Error {
4
- code = 'ARTIFACT_REGRESSION';
5
- identifier;
6
- newSize;
7
- priorSize;
8
- priorName;
9
- constructor(message, details) {
10
- super(message);
11
- this.name = 'ArtifactRegressionError';
12
- this.identifier = details.identifier;
13
- this.newSize = details.newSize;
14
- this.priorSize = details.priorSize;
15
- this.priorName = details.priorName;
16
- }
17
- }
18
- export const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG = {
19
- mode: 'warn',
20
- minRetainedRatio: 0.2,
21
- minPriorBytes: 4096,
22
- siblingExtensions: ['.html', '.htm'],
23
- };
24
- function escapeRegExp(value) {
25
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
26
- }
27
- /** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
28
- export function slugifyArtifactIdentifier(value) {
29
- return value
30
- .toLowerCase()
31
- .replace(/[^a-z0-9_-]+/g, '-')
32
- .replace(/^-+|-+$/g, '')
33
- .slice(0, 60);
34
- }
35
- /** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
36
- export const EMPTY_SLUG_FALLBACK_NAME = 'artifact';
37
- /**
38
- * Two identifiers refer to the same artifact lineage when they're literally
39
- * equal, or one is the canonical slug form of the other (and that slug is
40
- * non-empty). Slug equality alone is not enough: a slugifier that truncates
41
- * at a fixed length would otherwise falsely bridge two distinct identifiers
42
- * that only diverge past that length — requiring one side to *be* the slug
43
- * form of the other avoids that while still bridging e.g. "Landing Page" and
44
- * "landing-page".
45
- */
46
- export function artifactIdentifiersMatch(a, b) {
47
- if (a === b)
48
- return true;
49
- const slugA = slugifyArtifactIdentifier(a);
50
- if (slugA.length === 0)
51
- return false;
52
- const slugB = slugifyArtifactIdentifier(b);
53
- if (slugA !== slugB)
54
- return false;
55
- return a === slugA || b === slugB;
56
- }
57
- async function readSidecarIdentifier(scanDir, entryName) {
58
- try {
59
- const raw = await readFile(path.join(scanDir, `${entryName}.artifact.json`), 'utf8');
60
- const parsed = JSON.parse(raw);
61
- const id = parsed?.metadata?.identifier;
62
- return typeof id === 'string' && id.length > 0 ? id : null;
63
- }
64
- catch {
65
- return null;
66
- }
67
- }
68
- function extensionAlternation(extensions) {
69
- return extensions.map((ext) => escapeRegExp(ext)).join('|');
70
- }
71
- function legacyCandidateIdentifiers(filename, extensionPattern, suffixPattern) {
72
- const fullBasename = filename.replace(extensionPattern, '');
73
- const stripped = filename.replace(suffixPattern, '');
74
- const candidates = [];
75
- if (fullBasename.length > 0)
76
- candidates.push(fullBasename);
77
- if (stripped.length > 0 && stripped !== fullBasename)
78
- candidates.push(stripped);
79
- return candidates;
80
- }
81
- /**
82
- * Finds prior siblings on disk that share an identifier with a newly-written
83
- * artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
84
- * The scan deliberately includes any file at the same path as the new write
85
- * — when a write overwrites an existing file with the same name, the file
86
- * currently on disk is the prior content (the overwrite happens after this
87
- * scan runs).
88
- */
89
- export async function findPriorArtifactSiblings(scanDir, identifier, config) {
90
- if (identifier.length === 0)
91
- return [];
92
- const extAlternation = extensionAlternation(config.siblingExtensions);
93
- if (!extAlternation)
94
- return [];
95
- const extensionPattern = new RegExp(`(?:${extAlternation})$`, 'i');
96
- const suffixPattern = new RegExp(`(?:-\\d+)?(?:${extAlternation})$`, 'i');
97
- const tokens = new Set();
98
- tokens.add(identifier);
99
- const slug = slugifyArtifactIdentifier(identifier);
100
- if (slug.length > 0)
101
- tokens.add(slug);
102
- else
103
- tokens.add(EMPTY_SLUG_FALLBACK_NAME);
104
- const alternation = Array.from(tokens, escapeRegExp).join('|');
105
- const pattern = new RegExp(`^(?:${alternation})(?:-\\d+)?(?:${extAlternation})$`, 'i');
106
- let entries;
107
- try {
108
- entries = await readdir(scanDir, { withFileTypes: true });
109
- }
110
- catch {
111
- return [];
112
- }
113
- const results = [];
114
- for (const entry of entries) {
115
- if (!entry.isFile())
116
- continue;
117
- if (!pattern.test(entry.name))
118
- continue;
119
- const sidecarIdentifier = await readSidecarIdentifier(scanDir, entry.name);
120
- // `legacyCandidateIdentifiers` always returns at least one non-empty
121
- // candidate here: `entry.name` already matched `pattern` above, which
122
- // requires its basename to start with one of `tokens` (all non-empty),
123
- // so an explicit `candidateIdentifiers.length === 0` guard would be
124
- // dead code — an empty array's `.some()` below already `continue`s.
125
- const candidateIdentifiers = sidecarIdentifier !== null
126
- ? [sidecarIdentifier]
127
- : legacyCandidateIdentifiers(entry.name, extensionPattern, suffixPattern);
128
- if (!candidateIdentifiers.some((c) => artifactIdentifiersMatch(identifier, c)))
129
- continue;
130
- try {
131
- const st = await stat(path.join(scanDir, entry.name));
132
- results.push({ name: entry.name, size: st.size });
133
- }
134
- catch {
135
- // Ignore unreadable entries — they don't influence the guard decision.
136
- }
137
- }
138
- return results;
139
- }
140
- /** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
141
- export function readArtifactStubGuardConfigFromEnv(env = process.env, defaults = DEFAULT_ARTIFACT_STUB_GUARD_CONFIG) {
142
- const rawMode = (env.ARTIFACT_STUB_GUARD ?? '').toLowerCase();
143
- const mode = rawMode === 'reject' || rawMode === 'warn' || rawMode === 'off' ? rawMode : defaults.mode;
144
- const ratioRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_RATIO);
145
- // Accept (0, 1] so a caller can set 1 to reject any shrinkage. Values <=0 or >1 fall back to default.
146
- const minRetainedRatio = Number.isFinite(ratioRaw) && ratioRaw > 0 && ratioRaw <= 1 ? ratioRaw : defaults.minRetainedRatio;
147
- const minPriorBytesRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES);
148
- const minPriorBytes = Number.isInteger(minPriorBytesRaw) && minPriorBytesRaw > 0 ? minPriorBytesRaw : defaults.minPriorBytes;
149
- return { mode, minRetainedRatio, minPriorBytes, siblingExtensions: defaults.siblingExtensions };
150
- }
151
- function buildWarning(identifier, newSize, prior) {
152
- return {
153
- code: 'ARTIFACT_REGRESSION',
154
- message: `New artifact body for identifier "${identifier}" is ${newSize} bytes, ` +
155
- `but the largest prior sibling "${prior.name}" is ${prior.size} bytes. ` +
156
- 'This pattern usually means the write emitted a placeholder instead of the full document. ' +
157
- 'Set the guard mode to "warn" to record the warning without rejecting, or "off" to disable the guard entirely.',
158
- identifier,
159
- newSize,
160
- priorSize: prior.size,
161
- priorName: prior.name,
162
- };
163
- }
164
- /** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
165
- export function classifyArtifactStubGuard(priors, identifier, newSize, config) {
166
- if (config.mode === 'off')
167
- return { outcome: 'pass' };
168
- if (identifier.length === 0)
169
- return { outcome: 'pass' };
170
- if (priors.length === 0)
171
- return { outcome: 'pass' };
172
- let largestSoFar = null;
173
- for (const prior of priors) {
174
- if (largestSoFar === null || prior.size > largestSoFar.size)
175
- largestSoFar = prior;
176
- }
177
- // Non-null assertion, not a runtime guard: `priors.length === 0` already
178
- // returned above, so this loop always runs at least once, and its first
179
- // iteration always satisfies `largestSoFar === null` — it's always
180
- // assigned by the time the loop finishes.
181
- const largest = largestSoFar;
182
- if (largest.size < config.minPriorBytes)
183
- return { outcome: 'pass' };
184
- const threshold = largest.size * config.minRetainedRatio;
185
- if (newSize >= threshold)
186
- return { outcome: 'pass' };
187
- const warning = buildWarning(identifier, newSize, largest);
188
- return { outcome: config.mode === 'reject' ? 'reject' : 'warn', warning };
189
- }
190
- export async function evaluateArtifactStubGuard(input) {
191
- if (input.config.mode === 'off')
192
- return { outcome: 'pass' };
193
- if (input.identifier.length === 0)
194
- return { outcome: 'pass' };
195
- const priors = await findPriorArtifactSiblings(input.scanDir, input.identifier, input.config);
196
- return classifyArtifactStubGuard(priors, input.identifier, input.newSize, input.config);
197
- }
198
- //# sourceMappingURL=stub-guard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stub-guard.js","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"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"}
@@ -1,68 +0,0 @@
1
- /**
2
- * @module artifacts/text-suppression
3
- *
4
- * A streaming-text state machine that suppresses a tagged block (matched by
5
- * caller-supplied open/close patterns) from user-visible output while it's
6
- * still arriving — used to hide an artifact's raw markup from chat prose
7
- * while it streams in, without buffering the whole response first. Ported
8
- * from OD's `apps/daemon/src/artifacts/text-suppression.ts`.
9
- *
10
- * The core (`createTaggedTextSuppressor`) was already fully generic in the
11
- * origin — it takes its open/close regexes and open/close prefix-match
12
- * predicates as parameters, no product coupling. What needed de-branding
13
- * were the origin's two pre-built instances: `createDsmlArtifactTextSuppressor`
14
- * hardcoded OD's own "DSML" markup-language tag name family
15
- * (`<|DSML artifact>`/`<artifact>`) as its open/close patterns.
16
- * `createXmlTagTextSuppressor` below replaces it — a generic factory taking
17
- * the caller's own tag-name list instead of a hardcoded vocabulary. The
18
- * `tool_call`/`edit` pairing the origin's other instance
19
- * (`createToolCallTextSuppressor`) suppressed is a generic agent-protocol
20
- * convention, not OD-branded, and is kept as a named default instance.
21
- */
22
- export type StreamTextEvent = {
23
- readonly type: 'text_delta';
24
- readonly delta: string;
25
- };
26
- export type StreamEventSink = (event: StreamTextEvent) => void;
27
- export interface ArtifactTextSuppressor {
28
- strip(text: string): string;
29
- flush(): string;
30
- isSuppressing(): boolean;
31
- hasPendingCandidate(): boolean;
32
- stats(): ArtifactTextSuppressorStats;
33
- }
34
- export interface ArtifactTextSuppressorStats {
35
- readonly suppressedChars: number;
36
- readonly suppressedChunks: number;
37
- readonly openedBlocks: number;
38
- readonly closedBlocks: number;
39
- readonly pendingCandidateChars: number;
40
- readonly suppressing: boolean;
41
- }
42
- /**
43
- * Builds a suppressor for a tagged block delimited by `openRe`/`closeRe`.
44
- * `isPossibleOpen`/`isPossibleClose` decide whether a trailing `<...`
45
- * fragment (with no closing `>` yet) *could* still become a match once more
46
- * text arrives — this is what lets the suppressor hold back a
47
- * not-yet-decidable tail across streaming chunk boundaries instead of
48
- * either emitting a tag fragment early or hanging indefinitely on a `<` that
49
- * turns out to be unrelated text.
50
- */
51
- export declare function createTaggedTextSuppressor(args: {
52
- openRe: RegExp;
53
- closeRe: RegExp;
54
- isPossibleOpen: (text: string) => boolean;
55
- isPossibleClose: (text: string) => boolean;
56
- }): ArtifactTextSuppressor;
57
- /** Feeds `text` through `suppressor` and emits a `text_delta` on `onEvent` only when something survives. Returns whether an event was emitted. */
58
- export declare function emitWithTextSuppressor(suppressor: ArtifactTextSuppressor, onEvent: StreamEventSink, text: string): boolean;
59
- /**
60
- * Builds a suppressor for an XML-like `<tagName ...>...</tagName>` block (or
61
- * a bracket-pipe variant `<|tagName ...>...<|/tagName|>`), matched
62
- * case-insensitively against any of `tagNames`. Replaces the origin's
63
- * hardcoded "DSML" tag-name family with a caller-supplied vocabulary.
64
- */
65
- export declare function createXmlTagTextSuppressor(tagNames: readonly string[]): ArtifactTextSuppressor;
66
- /** Suppresses a `<tool_call>...</tool_call>` or `<edit>...</edit>` block — a generic agent-protocol convention, not product-branded. */
67
- export declare function createToolCallTextSuppressor(): ArtifactTextSuppressor;
68
- //# sourceMappingURL=text-suppression.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text-suppression.d.ts","sourceRoot":"","sources":["../../src/artifacts/text-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,KAAK,IAAI,MAAM,CAAC;IAChB,aAAa,IAAI,OAAO,CAAC;IACzB,mBAAmB,IAAI,OAAO,CAAC;IAC/B,KAAK,IAAI,2BAA2B,CAAC;CACtC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAID;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,GAAG,sBAAsB,CAgFzB;AAED,kJAAkJ;AAClJ,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAKT;AAqBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,sBAAsB,CAmB9F;AAoBD,wIAAwI;AACxI,wBAAgB,4BAA4B,IAAI,sBAAsB,CAOrE"}