@planvokter/riotplan-catalyst 1.0.17-dev.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/.kodrdriv/config.yaml +2 -0
- package/LICENSE +17 -0
- package/README.md +330 -0
- package/dist/riotplan-catalyst.d.ts +534 -0
- package/dist/riotplan-catalyst.js +379 -0
- package/dist/riotplan-catalyst.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { stat, readFile, readdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { resolve, join } from "node:path";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
const FACET_DIRECTORIES = {
|
|
6
|
+
questions: "questions",
|
|
7
|
+
constraints: "constraints",
|
|
8
|
+
outputTemplates: "output-templates",
|
|
9
|
+
domainKnowledge: "domain-knowledge",
|
|
10
|
+
processGuidance: "process-guidance",
|
|
11
|
+
validationRules: "validation-rules"
|
|
12
|
+
};
|
|
13
|
+
const FACET_TYPES = [
|
|
14
|
+
"questions",
|
|
15
|
+
"constraints",
|
|
16
|
+
"outputTemplates",
|
|
17
|
+
"domainKnowledge",
|
|
18
|
+
"processGuidance",
|
|
19
|
+
"validationRules"
|
|
20
|
+
];
|
|
21
|
+
const FacetsDeclarationSchema = z.object({
|
|
22
|
+
questions: z.boolean().optional().describe("Whether this catalyst provides guiding questions"),
|
|
23
|
+
constraints: z.boolean().optional().describe("Whether this catalyst provides constraints/rules"),
|
|
24
|
+
outputTemplates: z.boolean().optional().describe("Whether this catalyst provides output templates"),
|
|
25
|
+
domainKnowledge: z.boolean().optional().describe("Whether this catalyst provides domain knowledge"),
|
|
26
|
+
processGuidance: z.boolean().optional().describe("Whether this catalyst provides process guidance"),
|
|
27
|
+
validationRules: z.boolean().optional().describe("Whether this catalyst provides validation rules")
|
|
28
|
+
});
|
|
29
|
+
const SEMVER_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
30
|
+
const NPM_PACKAGE_PATTERN = /^(@[\w-]+\/)?[\w-]+$/;
|
|
31
|
+
const CatalystManifestSchema = z.object({
|
|
32
|
+
/**
|
|
33
|
+
* Catalyst identifier - should match NPM package name
|
|
34
|
+
* @example "@kjerneverk/catalyst-nodejs"
|
|
35
|
+
*/
|
|
36
|
+
id: z.string().regex(NPM_PACKAGE_PATTERN, "ID must be a valid NPM package name (e.g., @scope/name or name)").describe("Catalyst identifier (NPM package name)"),
|
|
37
|
+
/** Human-readable name for display */
|
|
38
|
+
name: z.string().min(1, "Name cannot be empty").describe("Human-readable name"),
|
|
39
|
+
/** Description of what this catalyst provides */
|
|
40
|
+
description: z.string().min(1, "Description cannot be empty").describe("What this catalyst provides"),
|
|
41
|
+
/**
|
|
42
|
+
* Semver version string
|
|
43
|
+
* @example "1.0.0" or "1.0.0-dev.0"
|
|
44
|
+
*/
|
|
45
|
+
version: z.string().regex(SEMVER_PATTERN, "Version must be valid semver (e.g., 1.0.0 or 1.0.0-dev.0)").describe("Semver version"),
|
|
46
|
+
/**
|
|
47
|
+
* Declaration of which facets this catalyst provides
|
|
48
|
+
* If omitted, facets are auto-detected from directory structure
|
|
49
|
+
*/
|
|
50
|
+
facets: FacetsDeclarationSchema.optional().describe("Declaration of which facets this catalyst provides")
|
|
51
|
+
});
|
|
52
|
+
const PlanManifestSchema = z.object({
|
|
53
|
+
/** Plan identifier (typically kebab-case) */
|
|
54
|
+
id: z.string().min(1, "ID cannot be empty").describe("Plan identifier"),
|
|
55
|
+
/** Human-readable title */
|
|
56
|
+
title: z.string().min(1, "Title cannot be empty").describe("Human-readable title"),
|
|
57
|
+
/**
|
|
58
|
+
* Ordered list of catalyst IDs associated with this plan
|
|
59
|
+
* Catalysts are applied in order (first = base, last = top layer)
|
|
60
|
+
*/
|
|
61
|
+
catalysts: z.array(z.string()).optional().describe("Ordered list of catalyst IDs"),
|
|
62
|
+
/** ISO timestamp of when the plan was created */
|
|
63
|
+
created: z.string().optional().describe("ISO timestamp of creation"),
|
|
64
|
+
/** Extensible metadata for future use */
|
|
65
|
+
metadata: z.record(z.string()).optional().describe("Extensible metadata")
|
|
66
|
+
});
|
|
67
|
+
async function loadManifest(directoryPath) {
|
|
68
|
+
const manifestPath = join(directoryPath, "catalyst.yml");
|
|
69
|
+
try {
|
|
70
|
+
const content = await readFile(manifestPath, "utf-8");
|
|
71
|
+
const parsed = parse(content);
|
|
72
|
+
const result = CatalystManifestSchema.safeParse(parsed);
|
|
73
|
+
if (!result.success) {
|
|
74
|
+
const errors = result.error.issues.map(
|
|
75
|
+
(issue) => `${issue.path.join(".")}: ${issue.message}`
|
|
76
|
+
).join("; ");
|
|
77
|
+
throw new Error(`Invalid catalyst manifest: ${errors}`);
|
|
78
|
+
}
|
|
79
|
+
return result.data;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error.code === "ENOENT") {
|
|
82
|
+
throw new Error(`Catalyst manifest not found at ${manifestPath}`);
|
|
83
|
+
}
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function loadFacetFiles(facetPath) {
|
|
88
|
+
try {
|
|
89
|
+
const entries = await readdir(facetPath, { withFileTypes: true });
|
|
90
|
+
const markdownFiles = entries.filter(
|
|
91
|
+
(entry) => entry.isFile() && entry.name.endsWith(".md")
|
|
92
|
+
);
|
|
93
|
+
const contents = await Promise.all(
|
|
94
|
+
markdownFiles.map(async (file) => {
|
|
95
|
+
const filePath = join(facetPath, file.name);
|
|
96
|
+
const content = await readFile(filePath, "utf-8");
|
|
97
|
+
return {
|
|
98
|
+
filename: file.name,
|
|
99
|
+
content
|
|
100
|
+
};
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
return contents;
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (error.code === "ENOENT") {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function directoryExists(path) {
|
|
112
|
+
try {
|
|
113
|
+
const stats = await stat(path);
|
|
114
|
+
return stats.isDirectory();
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function loadFacets(directoryPath, manifest, options = {}) {
|
|
120
|
+
var _a;
|
|
121
|
+
const facets = {};
|
|
122
|
+
const warnings = [];
|
|
123
|
+
for (const [facetKey, dirName] of Object.entries(FACET_DIRECTORIES)) {
|
|
124
|
+
const facetType = facetKey;
|
|
125
|
+
const facetPath = join(directoryPath, dirName);
|
|
126
|
+
const exists = await directoryExists(facetPath);
|
|
127
|
+
const declared = (_a = manifest.facets) == null ? void 0 : _a[facetType];
|
|
128
|
+
if (exists) {
|
|
129
|
+
const content = await loadFacetFiles(facetPath);
|
|
130
|
+
if (content.length > 0) {
|
|
131
|
+
facets[facetType] = content;
|
|
132
|
+
}
|
|
133
|
+
if (declared === false && options.warnOnUndeclaredFacets) {
|
|
134
|
+
warnings.push(
|
|
135
|
+
`Facet '${facetType}' is present but declared as false in manifest`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
if (declared === true && options.warnOnMissingFacets) {
|
|
140
|
+
warnings.push(
|
|
141
|
+
`Facet '${facetType}' is declared in manifest but directory '${dirName}' not found`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { facets, warnings };
|
|
147
|
+
}
|
|
148
|
+
async function loadCatalyst(directoryPath, options = {}) {
|
|
149
|
+
const absolutePath = resolve(directoryPath);
|
|
150
|
+
if (!await directoryExists(absolutePath)) {
|
|
151
|
+
throw new Error(`Catalyst directory not found: ${absolutePath}`);
|
|
152
|
+
}
|
|
153
|
+
const manifest = await loadManifest(absolutePath);
|
|
154
|
+
const { facets, warnings } = await loadFacets(absolutePath, manifest, options);
|
|
155
|
+
if (warnings.length > 0 && !options.strict) {
|
|
156
|
+
for (const warning of warnings) {
|
|
157
|
+
console.warn(`[catalyst-loader] ${warning}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
manifest,
|
|
162
|
+
facets,
|
|
163
|
+
directoryPath: absolutePath
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async function loadCatalystSafe(directoryPath, options = {}) {
|
|
167
|
+
try {
|
|
168
|
+
const catalyst = await loadCatalyst(directoryPath, options);
|
|
169
|
+
return {
|
|
170
|
+
success: true,
|
|
171
|
+
catalyst
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: error instanceof Error ? error.message : String(error)
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function resolveCatalysts(identifiers, basePath = process.cwd(), options = {}) {
|
|
181
|
+
const catalysts = [];
|
|
182
|
+
for (const identifier of identifiers) {
|
|
183
|
+
const path = resolve(basePath, identifier);
|
|
184
|
+
try {
|
|
185
|
+
const catalyst = await loadCatalyst(path, options);
|
|
186
|
+
catalysts.push(catalyst);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`Failed to load catalyst '${identifier}': ${error instanceof Error ? error.message : String(error)}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return catalysts;
|
|
194
|
+
}
|
|
195
|
+
function mergeCatalysts(catalysts) {
|
|
196
|
+
const mergedFacets = {};
|
|
197
|
+
const catalystIds = catalysts.map((c) => c.manifest.id);
|
|
198
|
+
const contributions = /* @__PURE__ */ new Map();
|
|
199
|
+
for (const facetType of FACET_TYPES) {
|
|
200
|
+
const mergedContent = [];
|
|
201
|
+
for (const catalyst of catalysts) {
|
|
202
|
+
const facetContent = catalyst.facets[facetType];
|
|
203
|
+
if (facetContent && facetContent.length > 0) {
|
|
204
|
+
for (const file of facetContent) {
|
|
205
|
+
mergedContent.push({
|
|
206
|
+
content: file.content,
|
|
207
|
+
sourceId: catalyst.manifest.id,
|
|
208
|
+
filename: file.filename
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const contrib = contributions.get(catalyst.manifest.id) || {
|
|
212
|
+
facetTypes: [],
|
|
213
|
+
contentCount: 0
|
|
214
|
+
};
|
|
215
|
+
if (!contrib.facetTypes.includes(facetType)) {
|
|
216
|
+
contrib.facetTypes.push(facetType);
|
|
217
|
+
}
|
|
218
|
+
contrib.contentCount += facetContent.length;
|
|
219
|
+
contributions.set(catalyst.manifest.id, contrib);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (mergedContent.length > 0) {
|
|
223
|
+
mergedFacets[facetType] = mergedContent;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
catalystIds,
|
|
228
|
+
facets: mergedFacets,
|
|
229
|
+
contributions
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function formatFacetName(facetType) {
|
|
233
|
+
const names = {
|
|
234
|
+
questions: "Questions",
|
|
235
|
+
constraints: "Constraints",
|
|
236
|
+
outputTemplates: "Output Templates",
|
|
237
|
+
domainKnowledge: "Domain Knowledge",
|
|
238
|
+
processGuidance: "Process Guidance",
|
|
239
|
+
validationRules: "Validation Rules"
|
|
240
|
+
};
|
|
241
|
+
return names[facetType];
|
|
242
|
+
}
|
|
243
|
+
function renderFacet(merged, facetType) {
|
|
244
|
+
const content = merged.facets[facetType];
|
|
245
|
+
if (!content || content.length === 0) {
|
|
246
|
+
return "";
|
|
247
|
+
}
|
|
248
|
+
const lines = [];
|
|
249
|
+
let currentSource = "";
|
|
250
|
+
for (const item of content) {
|
|
251
|
+
if (item.sourceId !== currentSource) {
|
|
252
|
+
if (lines.length > 0) {
|
|
253
|
+
lines.push("");
|
|
254
|
+
}
|
|
255
|
+
lines.push(`From ${item.sourceId}:`);
|
|
256
|
+
currentSource = item.sourceId;
|
|
257
|
+
}
|
|
258
|
+
lines.push(item.content);
|
|
259
|
+
}
|
|
260
|
+
return lines.join("\n");
|
|
261
|
+
}
|
|
262
|
+
function renderAllFacets(merged) {
|
|
263
|
+
const rendered = {};
|
|
264
|
+
for (const facetType of FACET_TYPES) {
|
|
265
|
+
rendered[facetType] = renderFacet(merged, facetType);
|
|
266
|
+
}
|
|
267
|
+
return rendered;
|
|
268
|
+
}
|
|
269
|
+
function summarizeMerge(merged) {
|
|
270
|
+
if (merged.catalystIds.length === 0) {
|
|
271
|
+
return "No catalysts merged";
|
|
272
|
+
}
|
|
273
|
+
const lines = [];
|
|
274
|
+
lines.push(`Merged ${merged.catalystIds.length} catalyst(s):`);
|
|
275
|
+
lines.push("");
|
|
276
|
+
for (const [catalystId, contrib] of merged.contributions) {
|
|
277
|
+
lines.push(`- ${catalystId}:`);
|
|
278
|
+
lines.push(` - Facets: ${contrib.facetTypes.map((t) => formatFacetName(t)).join(", ")}`);
|
|
279
|
+
lines.push(` - Content items: ${contrib.contentCount}`);
|
|
280
|
+
}
|
|
281
|
+
return lines.join("\n");
|
|
282
|
+
}
|
|
283
|
+
const MANIFEST_FILENAME = "plan.yaml";
|
|
284
|
+
async function readPlanManifest(planDirectory) {
|
|
285
|
+
const manifestPath = join(planDirectory, MANIFEST_FILENAME);
|
|
286
|
+
try {
|
|
287
|
+
const content = await readFile(manifestPath, "utf-8");
|
|
288
|
+
const parsed = parse(content);
|
|
289
|
+
const result = PlanManifestSchema.safeParse(parsed);
|
|
290
|
+
if (!result.success) {
|
|
291
|
+
const errors = result.error.issues.map(
|
|
292
|
+
(issue) => `${issue.path.join(".")}: ${issue.message}`
|
|
293
|
+
).join("; ");
|
|
294
|
+
throw new Error(`Invalid plan manifest: ${errors}`);
|
|
295
|
+
}
|
|
296
|
+
return result.data;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
if (error.code === "ENOENT") {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async function writePlanManifest(planDirectory, manifest) {
|
|
305
|
+
const result = PlanManifestSchema.safeParse(manifest);
|
|
306
|
+
if (!result.success) {
|
|
307
|
+
const errors = result.error.issues.map(
|
|
308
|
+
(issue) => `${issue.path.join(".")}: ${issue.message}`
|
|
309
|
+
).join("; ");
|
|
310
|
+
throw new Error(`Invalid plan manifest: ${errors}`);
|
|
311
|
+
}
|
|
312
|
+
const manifestToWrite = {
|
|
313
|
+
...result.data,
|
|
314
|
+
created: result.data.created || (/* @__PURE__ */ new Date()).toISOString()
|
|
315
|
+
};
|
|
316
|
+
const yaml = stringify(manifestToWrite, {
|
|
317
|
+
indent: 2,
|
|
318
|
+
lineWidth: 120
|
|
319
|
+
});
|
|
320
|
+
const manifestPath = join(planDirectory, MANIFEST_FILENAME);
|
|
321
|
+
await writeFile(manifestPath, yaml, "utf-8");
|
|
322
|
+
}
|
|
323
|
+
async function updatePlanManifest(planDirectory, updates) {
|
|
324
|
+
let existing = await readPlanManifest(planDirectory);
|
|
325
|
+
if (!existing) {
|
|
326
|
+
if (!updates.id || !updates.title) {
|
|
327
|
+
throw new Error("Cannot create manifest without id and title");
|
|
328
|
+
}
|
|
329
|
+
existing = {
|
|
330
|
+
id: "",
|
|
331
|
+
title: ""
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const merged = {
|
|
335
|
+
...existing,
|
|
336
|
+
...updates
|
|
337
|
+
};
|
|
338
|
+
await writePlanManifest(planDirectory, merged);
|
|
339
|
+
}
|
|
340
|
+
async function addCatalystToManifest(planDirectory, catalystId) {
|
|
341
|
+
const manifest = await readPlanManifest(planDirectory);
|
|
342
|
+
const currentCatalysts = (manifest == null ? void 0 : manifest.catalysts) ?? [];
|
|
343
|
+
if (!currentCatalysts.includes(catalystId)) {
|
|
344
|
+
currentCatalysts.push(catalystId);
|
|
345
|
+
}
|
|
346
|
+
await updatePlanManifest(planDirectory, {
|
|
347
|
+
catalysts: currentCatalysts
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async function removeCatalystFromManifest(planDirectory, catalystId) {
|
|
351
|
+
const manifest = await readPlanManifest(planDirectory);
|
|
352
|
+
const currentCatalysts = (manifest == null ? void 0 : manifest.catalysts) ?? [];
|
|
353
|
+
const filtered = currentCatalysts.filter((id) => id !== catalystId);
|
|
354
|
+
if (filtered.length !== currentCatalysts.length) {
|
|
355
|
+
await updatePlanManifest(planDirectory, {
|
|
356
|
+
catalysts: filtered.length > 0 ? filtered : void 0
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
export {
|
|
361
|
+
CatalystManifestSchema,
|
|
362
|
+
FACET_DIRECTORIES,
|
|
363
|
+
FACET_TYPES,
|
|
364
|
+
FacetsDeclarationSchema,
|
|
365
|
+
PlanManifestSchema,
|
|
366
|
+
addCatalystToManifest,
|
|
367
|
+
loadCatalyst,
|
|
368
|
+
loadCatalystSafe,
|
|
369
|
+
mergeCatalysts,
|
|
370
|
+
readPlanManifest,
|
|
371
|
+
removeCatalystFromManifest,
|
|
372
|
+
renderAllFacets,
|
|
373
|
+
renderFacet,
|
|
374
|
+
resolveCatalysts,
|
|
375
|
+
summarizeMerge,
|
|
376
|
+
updatePlanManifest,
|
|
377
|
+
writePlanManifest
|
|
378
|
+
};
|
|
379
|
+
//# sourceMappingURL=riotplan-catalyst.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"riotplan-catalyst.js","sources":["../src/schema/schemas.ts","../src/loader/catalyst-loader.ts","../src/merger/facet-merger.ts","../src/loader/plan-manifest.ts"],"sourcesContent":["/**\n * Zod schemas for catalyst.yml and plan.yaml manifests\n * @packageDocumentation\n */\n\nimport { z } from 'zod';\n\n/**\n * Facet directory names as they appear on disk\n */\nexport const FACET_DIRECTORIES = {\n questions: 'questions',\n constraints: 'constraints',\n outputTemplates: 'output-templates',\n domainKnowledge: 'domain-knowledge',\n processGuidance: 'process-guidance',\n validationRules: 'validation-rules',\n} as const;\n\n/**\n * All valid facet types\n */\nexport const FACET_TYPES = [\n 'questions',\n 'constraints',\n 'outputTemplates',\n 'domainKnowledge',\n 'processGuidance',\n 'validationRules',\n] as const;\n\nexport type FacetType = typeof FACET_TYPES[number];\n\n/**\n * Schema for the facets declaration in catalyst.yml\n * Each facet can be declared as present (true) or explicitly absent (false)\n */\nexport const FacetsDeclarationSchema = z.object({\n questions: z.boolean().optional().describe('Whether this catalyst provides guiding questions'),\n constraints: z.boolean().optional().describe('Whether this catalyst provides constraints/rules'),\n outputTemplates: z.boolean().optional().describe('Whether this catalyst provides output templates'),\n domainKnowledge: z.boolean().optional().describe('Whether this catalyst provides domain knowledge'),\n processGuidance: z.boolean().optional().describe('Whether this catalyst provides process guidance'),\n validationRules: z.boolean().optional().describe('Whether this catalyst provides validation rules'),\n});\n\n/**\n * Semver pattern for version validation\n * Matches: 1.0.0, 1.0.0-dev.0, 1.0.0-alpha.1, etc.\n */\nconst SEMVER_PATTERN = /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/;\n\n/**\n * NPM package name pattern\n * Matches: @scope/name, name, @scope/name-with-dashes\n */\nconst NPM_PACKAGE_PATTERN = /^(@[\\w-]+\\/)?[\\w-]+$/;\n\n/**\n * Schema for catalyst.yml manifest file\n * \n * The manifest defines the catalyst's identity and declares which facets it provides.\n * Facets are optional - a catalyst can provide any subset of the six facet types.\n */\nexport const CatalystManifestSchema = z.object({\n /** \n * Catalyst identifier - should match NPM package name\n * @example \"@kjerneverk/catalyst-nodejs\"\n */\n id: z.string()\n .regex(NPM_PACKAGE_PATTERN, 'ID must be a valid NPM package name (e.g., @scope/name or name)')\n .describe('Catalyst identifier (NPM package name)'),\n \n /** Human-readable name for display */\n name: z.string()\n .min(1, 'Name cannot be empty')\n .describe('Human-readable name'),\n \n /** Description of what this catalyst provides */\n description: z.string()\n .min(1, 'Description cannot be empty')\n .describe('What this catalyst provides'),\n \n /** \n * Semver version string\n * @example \"1.0.0\" or \"1.0.0-dev.0\"\n */\n version: z.string()\n .regex(SEMVER_PATTERN, 'Version must be valid semver (e.g., 1.0.0 or 1.0.0-dev.0)')\n .describe('Semver version'),\n \n /** \n * Declaration of which facets this catalyst provides\n * If omitted, facets are auto-detected from directory structure\n */\n facets: FacetsDeclarationSchema.optional()\n .describe('Declaration of which facets this catalyst provides'),\n});\n\n/**\n * Schema for plan.yaml manifest file\n * \n * The plan manifest gives each plan an identity and records which catalysts\n * are associated with it.\n */\nexport const PlanManifestSchema = z.object({\n /** Plan identifier (typically kebab-case) */\n id: z.string()\n .min(1, 'ID cannot be empty')\n .describe('Plan identifier'),\n \n /** Human-readable title */\n title: z.string()\n .min(1, 'Title cannot be empty')\n .describe('Human-readable title'),\n \n /** \n * Ordered list of catalyst IDs associated with this plan\n * Catalysts are applied in order (first = base, last = top layer)\n */\n catalysts: z.array(z.string())\n .optional()\n .describe('Ordered list of catalyst IDs'),\n \n /** ISO timestamp of when the plan was created */\n created: z.string()\n .optional()\n .describe('ISO timestamp of creation'),\n \n /** Extensible metadata for future use */\n metadata: z.record(z.string())\n .optional()\n .describe('Extensible metadata'),\n});\n\n/**\n * Inferred TypeScript types from Zod schemas\n */\nexport type CatalystManifestInput = z.input<typeof CatalystManifestSchema>;\nexport type CatalystManifestOutput = z.output<typeof CatalystManifestSchema>;\nexport type PlanManifestInput = z.input<typeof PlanManifestSchema>;\nexport type PlanManifestOutput = z.output<typeof PlanManifestSchema>;\nexport type FacetsDeclaration = z.infer<typeof FacetsDeclarationSchema>;\n","/**\n * Catalyst loading from local directories\n * @packageDocumentation\n */\n\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { \n CatalystManifestSchema, \n FACET_DIRECTORIES,\n type FacetType,\n} from '@/schema/schemas.js';\nimport type { \n Catalyst, \n CatalystManifest, \n CatalystFacets, \n FacetContent,\n CatalystLoadOptions,\n CatalystLoadResult,\n} from '@/types.js';\n\n/**\n * Load a catalyst manifest from catalyst.yml\n * @param directoryPath - Absolute path to catalyst directory\n * @returns Parsed and validated manifest\n * @throws Error if manifest is missing or invalid\n */\nasync function loadManifest(directoryPath: string): Promise<CatalystManifest> {\n const manifestPath = join(directoryPath, 'catalyst.yml');\n \n try {\n const content = await readFile(manifestPath, 'utf-8');\n const parsed = parseYaml(content);\n \n // Validate with Zod schema\n const result = CatalystManifestSchema.safeParse(parsed);\n \n if (!result.success) {\n const errors = result.error.issues.map(issue => \n `${issue.path.join('.')}: ${issue.message}`\n ).join('; ');\n throw new Error(`Invalid catalyst manifest: ${errors}`);\n }\n \n return result.data;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(`Catalyst manifest not found at ${manifestPath}`);\n }\n throw error;\n }\n}\n\n/**\n * Load all markdown files from a facet directory\n * @param facetPath - Path to facet directory\n * @returns Array of FacetContent objects\n */\nasync function loadFacetFiles(facetPath: string): Promise<FacetContent[]> {\n try {\n const entries = await readdir(facetPath, { withFileTypes: true });\n const markdownFiles = entries.filter(\n entry => entry.isFile() && entry.name.endsWith('.md')\n );\n \n const contents = await Promise.all(\n markdownFiles.map(async (file) => {\n const filePath = join(facetPath, file.name);\n const content = await readFile(filePath, 'utf-8');\n return {\n filename: file.name,\n content,\n };\n })\n );\n \n return contents;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n // Directory doesn't exist - return empty array\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Check if a directory exists\n */\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Load all facets from a catalyst directory\n * @param directoryPath - Absolute path to catalyst directory\n * @param manifest - Parsed manifest (for cross-referencing)\n * @param options - Load options\n * @returns Loaded facets and any warnings\n */\nasync function loadFacets(\n directoryPath: string,\n manifest: CatalystManifest,\n options: CatalystLoadOptions = {}\n): Promise<{ facets: CatalystFacets; warnings: string[] }> {\n const facets: CatalystFacets = {};\n const warnings: string[] = [];\n \n // Load each facet type\n for (const [facetKey, dirName] of Object.entries(FACET_DIRECTORIES)) {\n const facetType = facetKey as FacetType;\n const facetPath = join(directoryPath, dirName);\n const exists = await directoryExists(facetPath);\n \n // Check if facet is declared in manifest\n const declared = manifest.facets?.[facetType];\n \n if (exists) {\n // Load the facet content\n const content = await loadFacetFiles(facetPath);\n if (content.length > 0) {\n facets[facetType] = content;\n }\n \n // Warn if present but explicitly declared as false\n if (declared === false && options.warnOnUndeclaredFacets) {\n warnings.push(\n `Facet '${facetType}' is present but declared as false in manifest`\n );\n }\n } else {\n // Warn if declared but missing\n if (declared === true && options.warnOnMissingFacets) {\n warnings.push(\n `Facet '${facetType}' is declared in manifest but directory '${dirName}' not found`\n );\n }\n }\n }\n \n return { facets, warnings };\n}\n\n/**\n * Load a catalyst from a local directory\n * \n * Reads the catalyst.yml manifest, validates it, and loads all facet content\n * from the directory structure.\n * \n * @param directoryPath - Path to catalyst directory (absolute or relative)\n * @param options - Load options\n * @returns Loaded catalyst\n * @throws Error if manifest is missing or invalid\n * \n * @example\n * ```typescript\n * const catalyst = await loadCatalyst('./my-catalyst');\n * console.log(catalyst.manifest.name);\n * console.log(catalyst.facets.constraints?.length);\n * ```\n */\nexport async function loadCatalyst(\n directoryPath: string,\n options: CatalystLoadOptions = {}\n): Promise<Catalyst> {\n // Resolve to absolute path\n const absolutePath = resolve(directoryPath);\n \n // Check if directory exists\n if (!await directoryExists(absolutePath)) {\n throw new Error(`Catalyst directory not found: ${absolutePath}`);\n }\n \n // Load and validate manifest\n const manifest = await loadManifest(absolutePath);\n \n // Load all facets\n const { facets, warnings } = await loadFacets(absolutePath, manifest, options);\n \n // Log warnings if any\n if (warnings.length > 0 && !options.strict) {\n for (const warning of warnings) {\n // eslint-disable-next-line no-console\n console.warn(`[catalyst-loader] ${warning}`);\n }\n }\n \n return {\n manifest,\n facets,\n directoryPath: absolutePath,\n };\n}\n\n/**\n * Load a catalyst with full error handling\n * \n * Like loadCatalyst but returns a result object instead of throwing\n * \n * @param directoryPath - Path to catalyst directory\n * @param options - Load options\n * @returns Result object with success/error\n */\nexport async function loadCatalystSafe(\n directoryPath: string,\n options: CatalystLoadOptions = {}\n): Promise<CatalystLoadResult> {\n try {\n const catalyst = await loadCatalyst(directoryPath, options);\n return {\n success: true,\n catalyst,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Resolve catalyst identifiers to directories and load them\n * \n * Phase 1: Only supports local directory paths (absolute or relative)\n * Phase 2 (future): Will support NPM package resolution from node_modules\n * \n * @param identifiers - Array of catalyst paths\n * @param basePath - Base path for resolving relative paths\n * @param options - Load options\n * @returns Array of loaded catalysts\n */\nexport async function resolveCatalysts(\n identifiers: string[],\n basePath: string = process.cwd(),\n options: CatalystLoadOptions = {}\n): Promise<Catalyst[]> {\n const catalysts: Catalyst[] = [];\n \n for (const identifier of identifiers) {\n // Phase 1: treat identifier as a path\n // If it's relative, resolve from basePath\n const path = resolve(basePath, identifier);\n \n try {\n const catalyst = await loadCatalyst(path, options);\n catalysts.push(catalyst);\n } catch (error) {\n throw new Error(\n `Failed to load catalyst '${identifier}': ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n \n return catalysts;\n}\n","/**\n * Facet merging for multiple catalysts\n * @packageDocumentation\n */\n\nimport type { Catalyst } from '@/types.js';\nimport type { FacetType } from '@/schema/schemas.js';\nimport { FACET_TYPES } from '@/schema/schemas.js';\n\n/**\n * A single piece of content with source attribution\n */\nexport interface AttributedContent {\n content: string;\n sourceId: string;\n filename?: string;\n}\n\n/**\n * Facets merged from multiple catalysts with source attribution\n */\nexport interface MergedFacets {\n questions?: AttributedContent[];\n constraints?: AttributedContent[];\n outputTemplates?: AttributedContent[];\n domainKnowledge?: AttributedContent[];\n processGuidance?: AttributedContent[];\n validationRules?: AttributedContent[];\n}\n\n/**\n * Result of merging multiple catalysts\n */\nexport interface MergedCatalyst {\n /** Ordered list of catalyst IDs that were merged */\n catalystIds: string[];\n /** Merged facets with source attribution */\n facets: MergedFacets;\n /** Metadata about each catalyst's contribution */\n contributions: Map<string, {\n facetTypes: FacetType[];\n contentCount: number;\n }>;\n}\n\n/**\n * Merge multiple catalysts in order\n * \n * Catalysts are merged in the order provided, with later catalysts\n * layering on top of earlier ones. Content is concatenated (no conflict\n * resolution in v1), and each piece of content retains its source catalyst ID.\n * \n * @param catalysts - Ordered array of catalysts to merge (can be empty)\n * @returns Merged catalyst with source attribution\n * \n * @example\n * ```typescript\n * const catalyst1 = await loadCatalyst('./base-catalyst');\n * const catalyst2 = await loadCatalyst('./nodejs-catalyst');\n * const merged = mergeCatalysts([catalyst1, catalyst2]);\n * ```\n */\nexport function mergeCatalysts(catalysts: Catalyst[]): MergedCatalyst {\n const mergedFacets: MergedFacets = {};\n const catalystIds = catalysts.map(c => c.manifest.id);\n const contributions = new Map<string, {\n facetTypes: FacetType[];\n contentCount: number;\n }>();\n\n // Process each facet type\n for (const facetType of FACET_TYPES) {\n const mergedContent: AttributedContent[] = [];\n\n // Iterate through catalysts in order\n for (const catalyst of catalysts) {\n const facetContent = catalyst.facets[facetType];\n \n if (facetContent && facetContent.length > 0) {\n // Add each file's content with source attribution\n for (const file of facetContent) {\n mergedContent.push({\n content: file.content,\n sourceId: catalyst.manifest.id,\n filename: file.filename,\n });\n }\n\n // Track contribution\n const contrib = contributions.get(catalyst.manifest.id) || {\n facetTypes: [],\n contentCount: 0,\n };\n if (!contrib.facetTypes.includes(facetType)) {\n contrib.facetTypes.push(facetType);\n }\n contrib.contentCount += facetContent.length;\n contributions.set(catalyst.manifest.id, contrib);\n }\n }\n\n // Only set facet type if there's content\n if (mergedContent.length > 0) {\n mergedFacets[facetType] = mergedContent;\n }\n }\n\n return {\n catalystIds,\n facets: mergedFacets,\n contributions,\n };\n}\n\n/**\n * Format a facet type name for display\n */\nfunction formatFacetName(facetType: FacetType): string {\n const names: Record<FacetType, string> = {\n questions: 'Questions',\n constraints: 'Constraints',\n outputTemplates: 'Output Templates',\n domainKnowledge: 'Domain Knowledge',\n processGuidance: 'Process Guidance',\n validationRules: 'Validation Rules',\n };\n return names[facetType];\n}\n\n/**\n * Render merged facet content into a prompt-ready string\n * \n * Groups content by catalyst source and formats it for use in AI prompts.\n * Each source is labeled and content is separated for readability.\n * \n * @param merged - Merged catalyst\n * @param facetType - Facet type to render\n * @returns Formatted string ready for prompt injection, or empty string if no content\n * \n * @example\n * ```typescript\n * const merged = mergeCatalysts([catalyst1, catalyst2]);\n * const constraints = renderFacet(merged, 'constraints');\n * // Returns:\n * // From @kjerneverk/base-catalyst:\n * // [content from first catalyst]\n * // From @kjerneverk/nodejs-catalyst:\n * // [content from second catalyst]\n * ```\n */\nexport function renderFacet(\n merged: MergedCatalyst, \n facetType: FacetType\n): string {\n const content = merged.facets[facetType];\n \n if (!content || content.length === 0) {\n return '';\n }\n\n const lines: string[] = [];\n let currentSource = '';\n\n for (const item of content) {\n // Add source header when it changes\n if (item.sourceId !== currentSource) {\n if (lines.length > 0) {\n lines.push(''); // Blank line between sources\n }\n lines.push(`From ${item.sourceId}:`);\n currentSource = item.sourceId;\n }\n\n // Add content\n lines.push(item.content);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render all facets from a merged catalyst\n * \n * Returns an object with each facet type mapped to its rendered string.\n * Empty strings for facets with no content.\n * \n * @param merged - Merged catalyst\n * @returns Object with all facets rendered\n */\nexport function renderAllFacets(merged: MergedCatalyst): Record<FacetType, string> {\n const rendered: Partial<Record<FacetType, string>> = {};\n\n for (const facetType of FACET_TYPES) {\n rendered[facetType] = renderFacet(merged, facetType);\n }\n\n return rendered as Record<FacetType, string>;\n}\n\n/**\n * Generate a summary of merged catalysts\n * \n * Returns human-readable text about what was merged and what each\n * catalyst contributed.\n * \n * @param merged - Merged catalyst\n * @returns Summary string\n */\nexport function summarizeMerge(merged: MergedCatalyst): string {\n if (merged.catalystIds.length === 0) {\n return 'No catalysts merged';\n }\n\n const lines: string[] = [];\n lines.push(`Merged ${merged.catalystIds.length} catalyst(s):`);\n lines.push('');\n\n for (const [catalystId, contrib] of merged.contributions) {\n lines.push(`- ${catalystId}:`);\n lines.push(` - Facets: ${contrib.facetTypes.map(t => formatFacetName(t)).join(', ')}`);\n lines.push(` - Content items: ${contrib.contentCount}`);\n }\n\n return lines.join('\\n');\n}\n","/**\n * Plan manifest read/write\n * @packageDocumentation\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport { PlanManifestSchema, type PlanManifestOutput } from '@/schema/schemas.js';\n\n/**\n * Plan manifest stored in plan.yaml\n * \n * This is the metadata file for a plan that records:\n * - The plan's identity (ID and title)\n * - Which catalysts are associated with the plan\n * - When the plan was created\n * - Arbitrary metadata for extensibility\n */\nexport type PlanManifest = PlanManifestOutput;\n\nconst MANIFEST_FILENAME = 'plan.yaml';\n\n/**\n * Read a plan manifest from plan.yaml\n * \n * Returns null if the manifest file doesn't exist (graceful handling\n * for backward compatibility with plans created before catalyst support).\n * Throws if the file exists but contains invalid data.\n * \n * @param planDirectory - Absolute path to plan directory\n * @returns Parsed and validated manifest, or null if not present\n * @throws Error if manifest exists but is invalid\n * \n * @example\n * ```typescript\n * const manifest = await readPlanManifest('./my-plan');\n * if (manifest) {\n * console.log(`Plan: ${manifest.title}`);\n * console.log(`Uses catalysts: ${manifest.catalysts?.join(', ')}`);\n * }\n * ```\n */\nexport async function readPlanManifest(planDirectory: string): Promise<PlanManifest | null> {\n const manifestPath = join(planDirectory, MANIFEST_FILENAME);\n \n try {\n const content = await readFile(manifestPath, 'utf-8');\n const parsed = parseYaml(content);\n \n // Validate with Zod schema\n const result = PlanManifestSchema.safeParse(parsed);\n \n if (!result.success) {\n const errors = result.error.issues.map(issue => \n `${issue.path.join('.')}: ${issue.message}`\n ).join('; ');\n throw new Error(`Invalid plan manifest: ${errors}`);\n }\n \n return result.data;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n // File doesn't exist - return null for backward compatibility\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Write a plan manifest to plan.yaml\n * \n * Creates or overwrites the plan.yaml file with the provided manifest.\n * Automatically timestamps the manifest if `created` is not provided.\n * \n * @param planDirectory - Absolute path to plan directory\n * @param manifest - Manifest to write\n * @throws Error if manifest is invalid or write fails\n * \n * @example\n * ```typescript\n * const manifest: PlanManifest = {\n * id: 'add-user-auth',\n * title: 'Add User Authentication',\n * catalysts: ['@kjerneverk/catalyst-nodejs'],\n * created: new Date().toISOString(),\n * };\n * await writePlanManifest('./my-plan', manifest);\n * ```\n */\nexport async function writePlanManifest(\n planDirectory: string,\n manifest: PlanManifest\n): Promise<void> {\n // Validate manifest\n const result = PlanManifestSchema.safeParse(manifest);\n \n if (!result.success) {\n const errors = result.error.issues.map(issue => \n `${issue.path.join('.')}: ${issue.message}`\n ).join('; ');\n throw new Error(`Invalid plan manifest: ${errors}`);\n }\n \n // Ensure created timestamp exists\n const manifestToWrite: PlanManifest = {\n ...result.data,\n created: result.data.created || new Date().toISOString(),\n };\n \n // Serialize to YAML\n const yaml = stringifyYaml(manifestToWrite, {\n indent: 2,\n lineWidth: 120,\n });\n \n // Write to file\n const manifestPath = join(planDirectory, MANIFEST_FILENAME);\n await writeFile(manifestPath, yaml, 'utf-8');\n}\n\n/**\n * Update specific fields in a plan manifest\n * \n * Reads the existing manifest (or creates a new one if it doesn't exist),\n * merges the provided updates, and writes it back.\n * \n * @param planDirectory - Absolute path to plan directory\n * @param updates - Partial manifest to merge (only specified fields are changed)\n * @throws Error if updates are invalid or operation fails\n * \n * @example\n * ```typescript\n * // Add a catalyst to an existing plan\n * await updatePlanManifest('./my-plan', {\n * catalysts: ['@kjerneverk/catalyst-nodejs', '@kjerneverk/catalyst-react'],\n * });\n * ```\n */\nexport async function updatePlanManifest(\n planDirectory: string,\n updates: Partial<PlanManifest>\n): Promise<void> {\n // Read existing manifest\n let existing = await readPlanManifest(planDirectory);\n \n // If no existing manifest, start with a minimal one\n if (!existing) {\n // Updates must contain at least id and title\n if (!updates.id || !updates.title) {\n throw new Error('Cannot create manifest without id and title');\n }\n existing = {\n id: '',\n title: '',\n };\n }\n \n // Merge updates\n const merged: PlanManifest = {\n ...existing,\n ...updates,\n };\n \n // Write back\n await writePlanManifest(planDirectory, merged);\n}\n\n/**\n * Add a catalyst to a plan's manifest\n * \n * Convenience function that adds a catalyst ID to the catalysts array\n * without affecting other fields.\n * \n * @param planDirectory - Absolute path to plan directory\n * @param catalystId - Catalyst ID to add\n * \n * @example\n * ```typescript\n * await addCatalystToManifest('./my-plan', '@kjerneverk/catalyst-nodejs');\n * ```\n */\nexport async function addCatalystToManifest(\n planDirectory: string,\n catalystId: string\n): Promise<void> {\n const manifest = await readPlanManifest(planDirectory);\n const currentCatalysts = manifest?.catalysts ?? [];\n \n // Only add if not already present\n if (!currentCatalysts.includes(catalystId)) {\n currentCatalysts.push(catalystId);\n }\n \n await updatePlanManifest(planDirectory, {\n catalysts: currentCatalysts,\n });\n}\n\n/**\n * Remove a catalyst from a plan's manifest\n * \n * Convenience function that removes a catalyst ID from the catalysts array.\n * \n * @param planDirectory - Absolute path to plan directory\n * @param catalystId - Catalyst ID to remove\n * \n * @example\n * ```typescript\n * await removeCatalystFromManifest('./my-plan', '@kjerneverk/catalyst-old');\n * ```\n */\nexport async function removeCatalystFromManifest(\n planDirectory: string,\n catalystId: string\n): Promise<void> {\n const manifest = await readPlanManifest(planDirectory);\n const currentCatalysts = manifest?.catalysts ?? [];\n \n const filtered = currentCatalysts.filter(id => id !== catalystId);\n \n if (filtered.length !== currentCatalysts.length) {\n await updatePlanManifest(planDirectory, {\n catalysts: filtered.length > 0 ? filtered : undefined,\n });\n }\n}\n"],"names":["parseYaml","stringifyYaml"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@planvokter/riotplan-catalyst",
|
|
3
|
+
"version": "1.0.17-dev.0",
|
|
4
|
+
"description": "Catalyst system for RiotPlan - composable, layerable guidance packages for plan creation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/riotplan-catalyst.js",
|
|
7
|
+
"types": "./dist/riotplan-catalyst.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/riotplan-catalyst.d.ts",
|
|
11
|
+
"import": "./dist/riotplan-catalyst.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=24.0.0"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "npm run lint && vite build",
|
|
19
|
+
"test": "npm run test:coverage",
|
|
20
|
+
"test:coverage": "vitest run --coverage",
|
|
21
|
+
"test:debug": "vitest --run --coverage --reporter verbose",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"lint:fix": "eslint . --fix",
|
|
24
|
+
"clean": "rm -rf dist",
|
|
25
|
+
"precommit": "npm run build && npm run lint && npm run test",
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"yaml": "^2.4.0",
|
|
30
|
+
"zod": "^3.23.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
34
|
+
"@eslint/js": "^9.28.0",
|
|
35
|
+
"@types/node": "^25.2.2",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
|
37
|
+
"@typescript-eslint/parser": "^8.34.0",
|
|
38
|
+
"@vitest/coverage-v8": "^1.1.0",
|
|
39
|
+
"eslint": "^9.28.0",
|
|
40
|
+
"eslint-plugin-import": "^2.31.0",
|
|
41
|
+
"globals": "^17.0.0",
|
|
42
|
+
"typescript": "^5.4.0",
|
|
43
|
+
"vite": "^5.1.0",
|
|
44
|
+
"vite-plugin-dts": "^4.5.4",
|
|
45
|
+
"vitest": "^1.1.0"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"riotplan",
|
|
49
|
+
"catalyst",
|
|
50
|
+
"planning",
|
|
51
|
+
"guidance",
|
|
52
|
+
"ai"
|
|
53
|
+
],
|
|
54
|
+
"author": "Kjerneverk",
|
|
55
|
+
"license": "Apache-2.0",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/planvokter/riotplan-catalyst"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public",
|
|
62
|
+
"tag": "dev"
|
|
63
|
+
}
|
|
64
|
+
}
|