@thinkingsage/kanon 0.8.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.
Files changed (199) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -0
  4. package/bridge/mcp-server.cjs +14171 -0
  5. package/package.json +98 -0
  6. package/src/adapters/capabilities.ts +178 -0
  7. package/src/adapters/claude-code.ts +110 -0
  8. package/src/adapters/cline.ts +98 -0
  9. package/src/adapters/codex.ts +173 -0
  10. package/src/adapters/copilot.ts +106 -0
  11. package/src/adapters/cursor.ts +97 -0
  12. package/src/adapters/degradation.ts +95 -0
  13. package/src/adapters/index.ts +324 -0
  14. package/src/adapters/kiro-frontmatter.ts +139 -0
  15. package/src/adapters/kiro-inclusion.ts +86 -0
  16. package/src/adapters/kiro.ts +412 -0
  17. package/src/adapters/qdeveloper.ts +115 -0
  18. package/src/adapters/types.ts +81 -0
  19. package/src/adapters/windsurf.ts +96 -0
  20. package/src/admin.ts +283 -0
  21. package/src/asset-conventions.ts +118 -0
  22. package/src/attribution-backfill.ts +319 -0
  23. package/src/attribution-report.ts +95 -0
  24. package/src/attribution.ts +239 -0
  25. package/src/backends/github.ts +194 -0
  26. package/src/backends/http.ts +122 -0
  27. package/src/backends/index.ts +39 -0
  28. package/src/backends/local.ts +47 -0
  29. package/src/backends/s3.ts +157 -0
  30. package/src/backends/types.ts +59 -0
  31. package/src/base-cache.ts +270 -0
  32. package/src/browse-ui.ts +3754 -0
  33. package/src/browse.ts +1038 -0
  34. package/src/build.ts +1108 -0
  35. package/src/catalog.ts +204 -0
  36. package/src/cli-deprecated.ts +29 -0
  37. package/src/cli.ts +773 -0
  38. package/src/collection-admin.ts +287 -0
  39. package/src/collection-builder.ts +464 -0
  40. package/src/collections.ts +116 -0
  41. package/src/compatibility.ts +105 -0
  42. package/src/config.ts +743 -0
  43. package/src/eval/rubrics/kiro-progressive-steering.ts +841 -0
  44. package/src/eval.ts +1169 -0
  45. package/src/file-writer.ts +61 -0
  46. package/src/format-registry.ts +141 -0
  47. package/src/guild/auto-updater.ts +163 -0
  48. package/src/guild/backend-resolver.ts +49 -0
  49. package/src/guild/cli.ts +592 -0
  50. package/src/guild/collection-expander.ts +47 -0
  51. package/src/guild/global-cache.ts +247 -0
  52. package/src/guild/hook-generator.ts +100 -0
  53. package/src/guild/manifest.ts +154 -0
  54. package/src/guild/path-utils.ts +12 -0
  55. package/src/guild/sync.ts +622 -0
  56. package/src/guild/version-resolver.ts +42 -0
  57. package/src/help/metadata.ts +445 -0
  58. package/src/help/renderer.ts +265 -0
  59. package/src/help/typo-suggester.ts +25 -0
  60. package/src/hooks/expression.ts +493 -0
  61. package/src/hooks/pipeline.ts +141 -0
  62. package/src/import.ts +773 -0
  63. package/src/importers/claude-code.ts +134 -0
  64. package/src/importers/cline.ts +103 -0
  65. package/src/importers/codex.ts +140 -0
  66. package/src/importers/copilot.ts +103 -0
  67. package/src/importers/cursor.ts +105 -0
  68. package/src/importers/index.ts +390 -0
  69. package/src/importers/kiro.ts +110 -0
  70. package/src/importers/qdeveloper.ts +103 -0
  71. package/src/importers/types.ts +54 -0
  72. package/src/importers/windsurf.ts +104 -0
  73. package/src/install.ts +1005 -0
  74. package/src/manifest-admin.ts +306 -0
  75. package/src/mcp-bridge.ts +240 -0
  76. package/src/mutation/delta.ts +50 -0
  77. package/src/mutation/history.ts +66 -0
  78. package/src/mutation/operators.ts +524 -0
  79. package/src/mutation/runner.ts +332 -0
  80. package/src/new.ts +106 -0
  81. package/src/outcomes/collision.ts +127 -0
  82. package/src/outcomes/normalize.ts +208 -0
  83. package/src/outcomes/registry.ts +173 -0
  84. package/src/parser.ts +446 -0
  85. package/src/provenance-backfill-cli.ts +319 -0
  86. package/src/provenance-backfill.ts +520 -0
  87. package/src/publish.ts +354 -0
  88. package/src/reconcile-orchestrator.ts +502 -0
  89. package/src/reconcile-report-renderer.ts +176 -0
  90. package/src/resolve-body.ts +15 -0
  91. package/src/rosetta/builtins/compatibility-profiles.ts +297 -0
  92. package/src/rosetta/builtins/contracts.ts +1033 -0
  93. package/src/rosetta/builtins/pretty-printers/claude-code-native.ts +122 -0
  94. package/src/rosetta/builtins/pretty-printers/cline-native.ts +50 -0
  95. package/src/rosetta/builtins/pretty-printers/codex-native.ts +127 -0
  96. package/src/rosetta/builtins/pretty-printers/copilot-native.ts +50 -0
  97. package/src/rosetta/builtins/pretty-printers/cursor-native.ts +50 -0
  98. package/src/rosetta/builtins/pretty-printers/index.ts +81 -0
  99. package/src/rosetta/builtins/pretty-printers/kiro-native.ts +166 -0
  100. package/src/rosetta/builtins/pretty-printers/kiro-power.ts +108 -0
  101. package/src/rosetta/builtins/pretty-printers/kiro-skill.ts +88 -0
  102. package/src/rosetta/builtins/pretty-printers/qdeveloper-native.ts +51 -0
  103. package/src/rosetta/builtins/pretty-printers/superpowers.ts +97 -0
  104. package/src/rosetta/builtins/pretty-printers/windsurf-native.ts +50 -0
  105. package/src/rosetta/builtins/sources/claude-code-native.ts +348 -0
  106. package/src/rosetta/builtins/sources/cline-native.ts +176 -0
  107. package/src/rosetta/builtins/sources/codex-native.ts +343 -0
  108. package/src/rosetta/builtins/sources/copilot-native.ts +178 -0
  109. package/src/rosetta/builtins/sources/cursor-native.ts +176 -0
  110. package/src/rosetta/builtins/sources/index.ts +95 -0
  111. package/src/rosetta/builtins/sources/kiro-native.ts +462 -0
  112. package/src/rosetta/builtins/sources/kiro-power.ts +285 -0
  113. package/src/rosetta/builtins/sources/kiro-skill.ts +230 -0
  114. package/src/rosetta/builtins/sources/qdeveloper-native.ts +181 -0
  115. package/src/rosetta/builtins/sources/superpowers.ts +240 -0
  116. package/src/rosetta/builtins/sources/windsurf-native.ts +176 -0
  117. package/src/rosetta/builtins/targets/claude-code.ts +181 -0
  118. package/src/rosetta/builtins/targets/cline.ts +87 -0
  119. package/src/rosetta/builtins/targets/codex.ts +226 -0
  120. package/src/rosetta/builtins/targets/copilot.ts +103 -0
  121. package/src/rosetta/builtins/targets/cursor.ts +87 -0
  122. package/src/rosetta/builtins/targets/index.ts +60 -0
  123. package/src/rosetta/builtins/targets/kiro.ts +278 -0
  124. package/src/rosetta/builtins/targets/qdeveloper.ts +103 -0
  125. package/src/rosetta/builtins/targets/windsurf.ts +87 -0
  126. package/src/rosetta/canonical.ts +729 -0
  127. package/src/rosetta/compatibility.ts +432 -0
  128. package/src/rosetta/contracts.ts +329 -0
  129. package/src/rosetta/detector.ts +724 -0
  130. package/src/rosetta/diagnostics.ts +630 -0
  131. package/src/rosetta/engine-bootstrap.ts +103 -0
  132. package/src/rosetta/engine.ts +744 -0
  133. package/src/rosetta/index.ts +381 -0
  134. package/src/rosetta/inspection.ts +530 -0
  135. package/src/rosetta/plan.ts +448 -0
  136. package/src/rosetta/provenance-digest.ts +369 -0
  137. package/src/rosetta/reconcile.ts +812 -0
  138. package/src/rosetta/redaction.ts +467 -0
  139. package/src/rosetta/registry.ts +712 -0
  140. package/src/rosetta/renderers.ts +571 -0
  141. package/src/rosetta/request-guard.ts +335 -0
  142. package/src/rosetta/resolution.ts +419 -0
  143. package/src/rosetta/source-accounting.ts +233 -0
  144. package/src/rosetta/templates.ts +129 -0
  145. package/src/rosetta-cli.ts +717 -0
  146. package/src/rosetta-docs-generator.ts +793 -0
  147. package/src/rosetta-profiles-cli.ts +367 -0
  148. package/src/schemas.ts +1712 -0
  149. package/src/spec-coordination.ts +1141 -0
  150. package/src/temper.ts +747 -0
  151. package/src/template-bundle-loader.ts +312 -0
  152. package/src/template-engine.ts +53 -0
  153. package/src/translation-application-policy.ts +496 -0
  154. package/src/translation-orchestrator.ts +1013 -0
  155. package/src/translation-plan-applier.ts +473 -0
  156. package/src/tutorial.ts +305 -0
  157. package/src/validate.ts +1093 -0
  158. package/src/versioning.ts +553 -0
  159. package/src/wizard.ts +660 -0
  160. package/src/workspace.ts +237 -0
  161. package/templates/eval-contexts/claude-code.md.njk +6 -0
  162. package/templates/eval-contexts/cline.md.njk +6 -0
  163. package/templates/eval-contexts/copilot.md.njk +6 -0
  164. package/templates/eval-contexts/cursor.md.njk +6 -0
  165. package/templates/eval-contexts/kiro.md.njk +10 -0
  166. package/templates/eval-contexts/qdeveloper.md.njk +6 -0
  167. package/templates/eval-contexts/windsurf.md.njk +6 -0
  168. package/templates/harness-adapters/_base/attribution-footer.md.njk +17 -0
  169. package/templates/harness-adapters/_base/base.md.njk +16 -0
  170. package/templates/harness-adapters/claude-code/claude.md.njk +1 -0
  171. package/templates/harness-adapters/claude-code/mcp.json.njk +1 -0
  172. package/templates/harness-adapters/claude-code/settings.json.njk +1 -0
  173. package/templates/harness-adapters/claude-code/skill-library-index.md.njk +13 -0
  174. package/templates/harness-adapters/claude-code/skill.md.njk +19 -0
  175. package/templates/harness-adapters/cline/hook.sh.njk +4 -0
  176. package/templates/harness-adapters/cline/mcp.json.njk +1 -0
  177. package/templates/harness-adapters/cline/rule.md.njk +1 -0
  178. package/templates/harness-adapters/codex/agents-md.md.njk +6 -0
  179. package/templates/harness-adapters/codex/agents-pointer.md.njk +16 -0
  180. package/templates/harness-adapters/codex/skill.md.njk +27 -0
  181. package/templates/harness-adapters/copilot/agents.md.njk +1 -0
  182. package/templates/harness-adapters/copilot/instructions.md.njk +1 -0
  183. package/templates/harness-adapters/copilot/scoped.md.njk +6 -0
  184. package/templates/harness-adapters/cursor/mcp.json.njk +1 -0
  185. package/templates/harness-adapters/cursor/rule.md.njk +6 -0
  186. package/templates/harness-adapters/kiro/hook.json.njk +1 -0
  187. package/templates/harness-adapters/kiro/mcp.json.njk +1 -0
  188. package/templates/harness-adapters/kiro/power-steering.md.njk +3 -0
  189. package/templates/harness-adapters/kiro/power.md.njk +12 -0
  190. package/templates/harness-adapters/kiro/steering.md.njk +16 -0
  191. package/templates/harness-adapters/qdeveloper/agent.md.njk +1 -0
  192. package/templates/harness-adapters/qdeveloper/mcp.json.njk +1 -0
  193. package/templates/harness-adapters/qdeveloper/rule.md.njk +1 -0
  194. package/templates/harness-adapters/windsurf/mcp.json.njk +1 -0
  195. package/templates/harness-adapters/windsurf/rule.md.njk +1 -0
  196. package/templates/harness-adapters/windsurf/workflow.md.njk +1 -0
  197. package/templates/knowledge/hooks.yaml.njk +4 -0
  198. package/templates/knowledge/knowledge.md.njk +53 -0
  199. package/templates/knowledge/mcp-servers.yaml.njk +2 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Base-Artifact Cache and Import-Time Provenance (Orchestration Shell)
3
+ *
4
+ * ORCHESTRATION LAYER — this module performs filesystem IO and reads the clock,
5
+ * so it deliberately lives OUTSIDE `src/rosetta/**` (the Pure_Translation_Boundary
6
+ * enforced by `rosetta-architecture-boundary.test.ts`). It consumes the pure
7
+ * Rosetta Stone helpers rather than duplicating them:
8
+ *
9
+ * - `computeBaseDigest` (src/rosetta/provenance-digest.ts) computes the
10
+ * deterministic `sha256:<hex>` fingerprint of the normalized Theirs_Artifact.
11
+ * - `serializeCanonical` (src/rosetta/canonical.ts) renders the deterministic
12
+ * canonical byte plan that is written to the base cache.
13
+ *
14
+ * Two responsibilities, both invoked by the import/acquisition path
15
+ * (ADR-0049 / ADR-RS-007):
16
+ *
17
+ * 1. `buildProvenanceRecord` — a PURE builder that assembles a
18
+ * `ProvenanceRecord` from the acquired revision plus a computed
19
+ * `baseDigest`. It takes `importedAt` as an explicit argument so the clock
20
+ * stays in the orchestration caller (Requirement 18.1).
21
+ *
22
+ * 2. `writeBaseArtifact` — the impure cache writer. It serializes the
23
+ * normalized Base_Artifact and writes it to a git-ignored cache at
24
+ * `upstream/.kanon-base/<upstream>/<name>@<digest>` so that a later re-sync
25
+ * can reconstruct the common ancestor for three-way reconciliation
26
+ * (Requirement 18.2). On a cache miss the reconciler degrades to a two-way
27
+ * merge; this writer is what populates the cache to avoid that degradation.
28
+ *
29
+ * Requirements: 18.1, 18.2
30
+ */
31
+
32
+ import { mkdir, writeFile } from "node:fs/promises";
33
+ import { dirname, join } from "node:path";
34
+ import type { CanonicalSerializerOptions } from "./rosetta/canonical";
35
+ import { serializeCanonical } from "./rosetta/canonical";
36
+ import { computeBaseDigest } from "./rosetta/provenance-digest";
37
+ import type {
38
+ FormatIdentifier,
39
+ KnowledgeArtifact,
40
+ ProvenanceRecord,
41
+ } from "./schemas";
42
+
43
+ // ═══════════════════════════════════════════════════════════════════════════════
44
+ // Constants
45
+ // ═══════════════════════════════════════════════════════════════════════════════
46
+
47
+ /**
48
+ * The git-ignored root, relative to the repository/workspace root, under which
49
+ * normalized Base_Artifact content is cached. Matches the path decided in
50
+ * ADR-0049 and the Rosetta Stone design's "Base reconstruction" section.
51
+ */
52
+ export const BASE_CACHE_ROOT = join("upstream", ".kanon-base");
53
+
54
+ /**
55
+ * Serializer options used for both the digest and the cached content, so that
56
+ * the bytes hashed at import time match the bytes written to the cache and the
57
+ * bytes a later re-sync will re-hash. These mirror the options the import path
58
+ * uses when it serializes the artifact for writing.
59
+ */
60
+ const BASE_CACHE_SERIALIZER_OPTIONS: CanonicalSerializerOptions = {
61
+ emitEmptyAuxiliaryFiles: true,
62
+ emitBodyOverrides: true,
63
+ emitWorkflows: true,
64
+ };
65
+
66
+ // ═══════════════════════════════════════════════════════════════════════════════
67
+ // Provenance builder (pure)
68
+ // ═══════════════════════════════════════════════════════════════════════════════
69
+
70
+ /**
71
+ * The acquired-revision context an acquisition-driven import supplies so a
72
+ * `ProvenanceRecord` can be populated. Every field is caller-provided because
73
+ * translation is pure and must not read Git, the clock, or the filesystem
74
+ * implicitly (Requirement 12.6/12.7).
75
+ */
76
+ export interface AcquisitionContext {
77
+ /** The upstream identifier — matches a key in config `upstreams`. */
78
+ readonly upstream: string;
79
+ /** The source subpath within the upstream repository. */
80
+ readonly sourcePath: string;
81
+ /** The Source_Format the artifact was distilled from. */
82
+ readonly sourceFormat: FormatIdentifier;
83
+ /** The upstream revision (subtree commit) the import was taken from. */
84
+ readonly sourceRevision: string;
85
+ /**
86
+ * The Rosetta Stone Format_Contract identifier and version, e.g.
87
+ * `kiro-power@1`.
88
+ */
89
+ readonly contract: string;
90
+ /**
91
+ * The import timestamp as an ISO-8601 string, supplied by the orchestrator
92
+ * so this builder stays pure.
93
+ */
94
+ readonly importedAt: string;
95
+ }
96
+
97
+ /**
98
+ * The result of building a `ProvenanceRecord`: the record when the artifact
99
+ * could be fingerprinted, or `undefined` with the serializer diagnostics that
100
+ * prevented digest computation.
101
+ */
102
+ export interface ProvenanceBuildResult {
103
+ /** The populated provenance record, or undefined when the digest failed. */
104
+ readonly provenance: ProvenanceRecord | undefined;
105
+ /** Serializer diagnostics surfaced during digest computation (empty on success). */
106
+ readonly diagnostics: ReturnType<typeof computeBaseDigest>["diagnostics"];
107
+ }
108
+
109
+ /**
110
+ * Build a `ProvenanceRecord` from the acquired revision and the freshly
111
+ * translated Theirs_Artifact.
112
+ *
113
+ * The `baseDigest` is computed by the pure `computeBaseDigest` helper over the
114
+ * normalized artifact, so identical upstream revisions and translation options
115
+ * yield an identical digest (Requirement 18.2). When the artifact cannot be
116
+ * serialized (an invalid candidate), no digest — and therefore no provenance —
117
+ * is produced, and the serializer diagnostics are returned instead of writing a
118
+ * malformed record.
119
+ *
120
+ * Pure: depends only on its arguments. The clock value arrives via
121
+ * `context.importedAt`.
122
+ *
123
+ * @param artifact The freshly translated Theirs_Artifact being distilled.
124
+ * @param context The acquired-revision context.
125
+ * @returns The provenance record (or undefined) plus any digest diagnostics.
126
+ */
127
+ export function buildProvenanceRecord(
128
+ artifact: KnowledgeArtifact,
129
+ context: AcquisitionContext,
130
+ ): ProvenanceBuildResult {
131
+ const { digest, diagnostics } = computeBaseDigest(
132
+ artifact,
133
+ BASE_CACHE_SERIALIZER_OPTIONS,
134
+ );
135
+
136
+ if (digest === undefined) {
137
+ return { provenance: undefined, diagnostics };
138
+ }
139
+
140
+ const provenance: ProvenanceRecord = {
141
+ upstream: context.upstream,
142
+ sourcePath: context.sourcePath,
143
+ sourceFormat: context.sourceFormat,
144
+ sourceRevision: context.sourceRevision,
145
+ contract: context.contract,
146
+ baseDigest: digest,
147
+ importedAt: context.importedAt,
148
+ };
149
+
150
+ return { provenance, diagnostics: [] };
151
+ }
152
+
153
+ // ═══════════════════════════════════════════════════════════════════════════════
154
+ // Base-artifact cache path (pure)
155
+ // ═══════════════════════════════════════════════════════════════════════════════
156
+
157
+ /**
158
+ * The digest embeds a `sha256:` prefix and a hex body. `:` is unsafe as a path
159
+ * segment on some filesystems, so it is replaced with `-` when forming the
160
+ * `<name>@<digest>` cache key. The stored key remains a stable, reversible
161
+ * function of the digest.
162
+ */
163
+ function digestToPathSegment(digest: string): string {
164
+ return digest.replace(/:/g, "-");
165
+ }
166
+
167
+ /**
168
+ * Compute the git-ignored cache path for a Base_Artifact, relative to the
169
+ * provided workspace root:
170
+ * `upstream/.kanon-base/<upstream>/<name>@<digest>` (ADR-0049).
171
+ *
172
+ * Pure: derives a path string only; performs no IO.
173
+ *
174
+ * @param workspaceRoot The root the cache is anchored under.
175
+ * @param upstream The upstream identifier.
176
+ * @param name The canonical artifact name.
177
+ * @param digest The `sha256:<hex>` Base_Digest.
178
+ * @returns The absolute cache directory path for this base artifact.
179
+ */
180
+ export function baseArtifactCachePath(
181
+ workspaceRoot: string,
182
+ upstream: string,
183
+ name: string,
184
+ digest: string,
185
+ ): string {
186
+ return join(
187
+ workspaceRoot,
188
+ BASE_CACHE_ROOT,
189
+ upstream,
190
+ `${name}@${digestToPathSegment(digest)}`,
191
+ );
192
+ }
193
+
194
+ // ═══════════════════════════════════════════════════════════════════════════════
195
+ // Base-artifact cache writer (impure)
196
+ // ═══════════════════════════════════════════════════════════════════════════════
197
+
198
+ /**
199
+ * The outcome of writing a Base_Artifact to the cache.
200
+ */
201
+ export interface BaseCacheWriteResult {
202
+ /** True when the normalized base content was written. */
203
+ readonly written: boolean;
204
+ /** The cache directory the content was written to, when written. */
205
+ readonly cachePath: string | undefined;
206
+ /** Serializer diagnostics that prevented the write (empty on success). */
207
+ readonly diagnostics: ReturnType<typeof serializeCanonical>["diagnostics"];
208
+ }
209
+
210
+ /**
211
+ * Serialize and write the normalized Base_Artifact content to the git-ignored
212
+ * base cache (Requirement 18.2).
213
+ *
214
+ * The artifact is serialized with the same options used to compute its
215
+ * `baseDigest`, so the cached bytes reconstruct exactly the artifact the digest
216
+ * fingerprints. The content is written to
217
+ * `upstream/.kanon-base/<upstream>/<name>@<digest>/<file>` for every file in
218
+ * the canonical plan, preserving the canonical directory layout so a re-sync can
219
+ * re-parse the cached tree into a Base_Artifact.
220
+ *
221
+ * Impure: creates directories and writes files. On a serialization failure it
222
+ * writes nothing and returns the diagnostics so the caller can decide to
223
+ * proceed without a cached base (the reconciler then degrades to a two-way
224
+ * merge).
225
+ *
226
+ * @param artifact The normalized Base_Artifact to cache.
227
+ * @param digest The `sha256:<hex>` Base_Digest keying the cache entry.
228
+ * @param context The acquisition context (supplies the upstream identifier).
229
+ * @param workspaceRoot The root the cache is anchored under.
230
+ * @returns Whether the content was written, the cache path, and diagnostics.
231
+ */
232
+ export async function writeBaseArtifact(
233
+ artifact: KnowledgeArtifact,
234
+ digest: string,
235
+ context: Pick<AcquisitionContext, "upstream">,
236
+ workspaceRoot: string,
237
+ ): Promise<BaseCacheWriteResult> {
238
+ const { plan, diagnostics } = serializeCanonical(
239
+ artifact,
240
+ BASE_CACHE_SERIALIZER_OPTIONS,
241
+ );
242
+
243
+ if (!plan) {
244
+ return { written: false, cachePath: undefined, diagnostics };
245
+ }
246
+
247
+ const cachePath = baseArtifactCachePath(
248
+ workspaceRoot,
249
+ context.upstream,
250
+ artifact.name,
251
+ digest,
252
+ );
253
+
254
+ await mkdir(cachePath, { recursive: true });
255
+
256
+ for (const file of plan.outputFiles) {
257
+ const destPath = join(cachePath, file.relativePath);
258
+ const parent = dirname(destPath);
259
+ if (parent !== cachePath) {
260
+ await mkdir(parent, { recursive: true });
261
+ }
262
+ const content =
263
+ typeof file.content === "string"
264
+ ? file.content
265
+ : new TextDecoder().decode(file.content);
266
+ await writeFile(destPath, content, "utf-8");
267
+ }
268
+
269
+ return { written: true, cachePath, diagnostics: [] };
270
+ }