@soleri/core 9.13.0 → 9.14.4

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 (119) hide show
  1. package/dist/engine/bin/soleri-engine.js +7 -2
  2. package/dist/engine/bin/soleri-engine.js.map +1 -1
  3. package/dist/flows/types.d.ts +34 -30
  4. package/dist/flows/types.d.ts.map +1 -1
  5. package/dist/index.d.ts +3 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/knowledge-packs/community/.gitkeep +0 -0
  10. package/dist/knowledge-packs/salvador/salvador-craft/soleri-pack.json +10 -0
  11. package/dist/knowledge-packs/salvador/salvador-craft/vault/accessibility.json +53 -0
  12. package/dist/knowledge-packs/salvador/salvador-craft/vault/design-tokens.json +26 -0
  13. package/dist/knowledge-packs/salvador/salvador-craft/vault/design.json +33 -0
  14. package/dist/knowledge-packs/salvador/salvador-craft/vault/styling.json +44 -0
  15. package/dist/knowledge-packs/salvador/salvador-craft/vault/ux-laws.json +36 -0
  16. package/dist/knowledge-packs/salvador/salvador-craft/vault/ux.json +36 -0
  17. package/dist/knowledge-packs/salvador/salvador-engineering/soleri-pack.json +10 -0
  18. package/dist/knowledge-packs/salvador/salvador-engineering/vault/architecture.json +143 -0
  19. package/dist/knowledge-packs/salvador/salvador-engineering/vault/commercial.json +16 -0
  20. package/dist/knowledge-packs/salvador/salvador-engineering/vault/communication.json +33 -0
  21. package/dist/knowledge-packs/salvador/salvador-engineering/vault/component.json +16 -0
  22. package/dist/knowledge-packs/salvador/salvador-engineering/vault/express.json +34 -0
  23. package/dist/knowledge-packs/salvador/salvador-engineering/vault/leadership.json +33 -0
  24. package/dist/knowledge-packs/salvador/salvador-engineering/vault/methodology.json +33 -0
  25. package/dist/knowledge-packs/salvador/salvador-engineering/vault/monorepo.json +33 -0
  26. package/dist/knowledge-packs/salvador/salvador-engineering/vault/other.json +73 -0
  27. package/dist/knowledge-packs/salvador/salvador-engineering/vault/performance.json +35 -0
  28. package/dist/knowledge-packs/salvador/salvador-engineering/vault/prisma.json +33 -0
  29. package/dist/knowledge-packs/salvador/salvador-engineering/vault/product-strategy.json +42 -0
  30. package/dist/knowledge-packs/salvador/salvador-engineering/vault/react.json +47 -0
  31. package/dist/knowledge-packs/salvador/salvador-engineering/vault/security.json +34 -0
  32. package/dist/knowledge-packs/salvador/salvador-engineering/vault/testing.json +33 -0
  33. package/dist/knowledge-packs/salvador/salvador-engineering/vault/tooling.json +85 -0
  34. package/dist/knowledge-packs/salvador/salvador-engineering/vault/typescript.json +34 -0
  35. package/dist/knowledge-packs/salvador/salvador-engineering/vault/workflow.json +46 -0
  36. package/dist/knowledge-packs/salvador/salvador-uipro/soleri-pack.json +10 -0
  37. package/dist/knowledge-packs/salvador/salvador-uipro/vault/design.json +2589 -0
  38. package/dist/knowledge-packs/starter/api-design/soleri-pack.json +9 -0
  39. package/dist/knowledge-packs/starter/api-design/vault/patterns.json +137 -0
  40. package/dist/knowledge-packs/starter/architecture/soleri-pack.json +10 -0
  41. package/dist/knowledge-packs/starter/architecture/vault/patterns.json +137 -0
  42. package/dist/knowledge-packs/starter/design/soleri-pack.json +10 -0
  43. package/dist/knowledge-packs/starter/design/vault/patterns.json +137 -0
  44. package/dist/knowledge-packs/starter/nodejs/soleri-pack.json +9 -0
  45. package/dist/knowledge-packs/starter/nodejs/vault/patterns.json +137 -0
  46. package/dist/knowledge-packs/starter/react/soleri-pack.json +9 -0
  47. package/dist/knowledge-packs/starter/react/vault/patterns.json +164 -0
  48. package/dist/knowledge-packs/starter/security/soleri-pack.json +10 -0
  49. package/dist/knowledge-packs/starter/security/vault/patterns.json +137 -0
  50. package/dist/knowledge-packs/starter/testing/soleri-pack.json +9 -0
  51. package/dist/knowledge-packs/starter/testing/vault/patterns.json +128 -0
  52. package/dist/knowledge-packs/starter/typescript/soleri-pack.json +9 -0
  53. package/dist/knowledge-packs/starter/typescript/vault/patterns.json +164 -0
  54. package/dist/packs/index.d.ts +1 -1
  55. package/dist/packs/index.d.ts.map +1 -1
  56. package/dist/packs/index.js +1 -1
  57. package/dist/packs/index.js.map +1 -1
  58. package/dist/packs/resolver.d.ts +6 -0
  59. package/dist/packs/resolver.d.ts.map +1 -1
  60. package/dist/packs/resolver.js +20 -1
  61. package/dist/packs/resolver.js.map +1 -1
  62. package/dist/runtime/admin-setup-ops.js +1 -1
  63. package/dist/runtime/admin-setup-ops.js.map +1 -1
  64. package/dist/runtime/capture-ops.d.ts.map +1 -1
  65. package/dist/runtime/capture-ops.js +2 -1
  66. package/dist/runtime/capture-ops.js.map +1 -1
  67. package/dist/runtime/intake-ops.d.ts.map +1 -1
  68. package/dist/runtime/intake-ops.js +5 -5
  69. package/dist/runtime/intake-ops.js.map +1 -1
  70. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  71. package/dist/runtime/orchestrate-ops.js +26 -2
  72. package/dist/runtime/orchestrate-ops.js.map +1 -1
  73. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  74. package/dist/runtime/planning-extra-ops.js +5 -7
  75. package/dist/runtime/planning-extra-ops.js.map +1 -1
  76. package/dist/runtime/playbook-ops.d.ts.map +1 -1
  77. package/dist/runtime/playbook-ops.js +2 -1
  78. package/dist/runtime/playbook-ops.js.map +1 -1
  79. package/dist/runtime/schema-helpers.d.ts +7 -0
  80. package/dist/runtime/schema-helpers.d.ts.map +1 -0
  81. package/dist/runtime/schema-helpers.js +21 -0
  82. package/dist/runtime/schema-helpers.js.map +1 -0
  83. package/dist/runtime/sync-ops.d.ts.map +1 -1
  84. package/dist/runtime/sync-ops.js +3 -4
  85. package/dist/runtime/sync-ops.js.map +1 -1
  86. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  87. package/dist/runtime/vault-extra-ops.js +5 -4
  88. package/dist/runtime/vault-extra-ops.js.map +1 -1
  89. package/dist/skills/sync-skills.d.ts +26 -7
  90. package/dist/skills/sync-skills.d.ts.map +1 -1
  91. package/dist/skills/sync-skills.js +132 -32
  92. package/dist/skills/sync-skills.js.map +1 -1
  93. package/dist/skills/validate-skill-docs.d.ts +24 -0
  94. package/dist/skills/validate-skill-docs.d.ts.map +1 -0
  95. package/dist/skills/validate-skill-docs.js +476 -0
  96. package/dist/skills/validate-skill-docs.js.map +1 -0
  97. package/package.json +2 -2
  98. package/src/__tests__/deviation-detection.test.ts +49 -0
  99. package/src/enforcement/adapters/claude-code.test.ts +9 -9
  100. package/src/engine/bin/soleri-engine.ts +7 -2
  101. package/src/flows/types.ts +4 -0
  102. package/src/index.ts +15 -2
  103. package/src/packs/index.ts +6 -1
  104. package/src/packs/resolver.ts +24 -1
  105. package/src/runtime/admin-setup-ops.test.ts +2 -0
  106. package/src/runtime/admin-setup-ops.ts +1 -1
  107. package/src/runtime/capture-ops.ts +2 -1
  108. package/src/runtime/intake-ops.ts +7 -7
  109. package/src/runtime/orchestrate-ops.ts +29 -2
  110. package/src/runtime/planning-extra-ops.ts +35 -37
  111. package/src/runtime/playbook-ops.ts +2 -1
  112. package/src/runtime/schema-helpers.test.ts +45 -0
  113. package/src/runtime/schema-helpers.ts +19 -0
  114. package/src/runtime/sync-ops.ts +8 -9
  115. package/src/runtime/vault-extra-ops.ts +5 -4
  116. package/src/skills/__tests__/sync-skills.test.ts +102 -29
  117. package/src/skills/__tests__/validate-skill-docs.test.ts +58 -0
  118. package/src/skills/sync-skills.ts +152 -32
  119. package/src/skills/validate-skill-docs.ts +562 -0
@@ -0,0 +1,476 @@
1
+ /**
2
+ * Build-time validator for SKILL.md inline op-call examples.
3
+ *
4
+ * Parses `YOUR_AGENT_core op:<name> params: { ... }` blocks in SKILL.md files
5
+ * and validates the params against the actual Zod schemas defined in the
6
+ * facade source files.
7
+ *
8
+ * Usage: tsx packages/core/src/skills/validate-skill-docs.ts
9
+ * Exit 0 = all valid, Exit 1 = mismatches found.
10
+ */
11
+ import { readFileSync, readdirSync, existsSync } from 'node:fs';
12
+ import { join, resolve, relative } from 'node:path';
13
+ // ── Facade factory imports ──────────────────────────────────────────────
14
+ import { createVaultFacadeOps } from '../runtime/facades/vault-facade.js';
15
+ import { createPlanFacadeOps } from '../runtime/facades/plan-facade.js';
16
+ import { createBrainFacadeOps } from '../runtime/facades/brain-facade.js';
17
+ import { createMemoryFacadeOps } from '../runtime/facades/memory-facade.js';
18
+ import { createAdminFacadeOps } from '../runtime/facades/admin-facade.js';
19
+ import { createCuratorFacadeOps } from '../runtime/facades/curator-facade.js';
20
+ import { createLoopFacadeOps } from '../runtime/facades/loop-facade.js';
21
+ import { createOrchestrateFacadeOps } from '../runtime/facades/orchestrate-facade.js';
22
+ import { createControlFacadeOps } from '../runtime/facades/control-facade.js';
23
+ import { createContextFacadeOps } from '../runtime/facades/context-facade.js';
24
+ import { createAgencyFacadeOps } from '../runtime/facades/agency-facade.js';
25
+ import { createChatFacadeOps } from '../runtime/facades/chat-facade.js';
26
+ import { createOperatorFacadeOps } from '../runtime/facades/operator-facade.js';
27
+ import { createArchiveFacadeOps } from '../runtime/facades/archive-facade.js';
28
+ import { createSyncFacadeOps } from '../runtime/facades/sync-facade.js';
29
+ import { createReviewFacadeOps } from '../runtime/facades/review-facade.js';
30
+ import { createIntakeFacadeOps } from '../runtime/facades/intake-facade.js';
31
+ import { createLinksFacadeOps } from '../runtime/facades/links-facade.js';
32
+ import { createBranchingFacadeOps } from '../runtime/facades/branching-facade.js';
33
+ import { createTierFacadeOps } from '../runtime/facades/tier-facade.js';
34
+ import { createEmbeddingFacadeOps } from '../runtime/facades/embedding-facade.js';
35
+ // ── Mock runtime ────────────────────────────────────────────────────────
36
+ // Schemas are constructed during factory calls but handlers are never invoked,
37
+ // so a recursive proxy that returns itself for any property access is enough.
38
+ function createNoopProxy() {
39
+ const handler = {
40
+ get(_target, prop) {
41
+ // Return primitives for common property checks
42
+ if (prop === Symbol.toPrimitive)
43
+ return () => '';
44
+ if (prop === Symbol.iterator)
45
+ return undefined;
46
+ if (prop === 'then')
47
+ return undefined; // prevent Promise detection
48
+ if (prop === 'toString')
49
+ return () => '[mock]';
50
+ if (prop === 'valueOf')
51
+ return () => 0;
52
+ if (prop === 'length')
53
+ return 0;
54
+ // Return a callable proxy for methods
55
+ return new Proxy(function () { }, handler);
56
+ },
57
+ apply() {
58
+ // When called as a function, return a new proxy
59
+ return new Proxy({}, handler);
60
+ },
61
+ };
62
+ return new Proxy({}, handler);
63
+ }
64
+ // ── Schema registry ─────────────────────────────────────────────────────
65
+ // Build a flat map of opName → ZodSchema from all facades.
66
+ function buildSchemaRegistry() {
67
+ const runtime = createNoopProxy();
68
+ const registry = new Map();
69
+ const facadeFactories = [
70
+ createVaultFacadeOps,
71
+ createPlanFacadeOps,
72
+ createBrainFacadeOps,
73
+ createMemoryFacadeOps,
74
+ createAdminFacadeOps,
75
+ createCuratorFacadeOps,
76
+ createLoopFacadeOps,
77
+ createOrchestrateFacadeOps,
78
+ createControlFacadeOps,
79
+ createContextFacadeOps,
80
+ createAgencyFacadeOps,
81
+ createChatFacadeOps,
82
+ createOperatorFacadeOps,
83
+ createArchiveFacadeOps,
84
+ createSyncFacadeOps,
85
+ createReviewFacadeOps,
86
+ createIntakeFacadeOps,
87
+ createLinksFacadeOps,
88
+ createBranchingFacadeOps,
89
+ createTierFacadeOps,
90
+ createEmbeddingFacadeOps,
91
+ ];
92
+ for (const factory of facadeFactories) {
93
+ try {
94
+ const ops = factory(runtime);
95
+ for (const op of ops) {
96
+ if (op.schema) {
97
+ registry.set(op.name, op.schema);
98
+ }
99
+ }
100
+ }
101
+ catch {
102
+ // Some facades may fail with the mock runtime — skip them.
103
+ // Schemas from other facades still get registered.
104
+ }
105
+ }
106
+ return registry;
107
+ }
108
+ // ── SKILL.md parser ─────────────────────────────────────────────────────
109
+ // Extracts op-call examples from fenced code blocks.
110
+ //
111
+ // Formats matched:
112
+ // YOUR_AGENT_core op:<name>
113
+ // YOUR_AGENT_core op:<name> params: { ... }
114
+ // YOUR_AGENT_core op:<name>
115
+ // params: { ... }
116
+ function extractOpExamples(filePath) {
117
+ const content = readFileSync(filePath, 'utf-8');
118
+ const lines = content.split('\n');
119
+ const examples = [];
120
+ // Track code blocks
121
+ let inCodeBlock = false;
122
+ let codeBlockStart = -1;
123
+ let codeBlockLines = [];
124
+ for (let i = 0; i < lines.length; i++) {
125
+ const line = lines[i];
126
+ if (line.trimStart().startsWith('```')) {
127
+ if (!inCodeBlock) {
128
+ inCodeBlock = true;
129
+ codeBlockStart = i + 1;
130
+ codeBlockLines = [];
131
+ }
132
+ else {
133
+ // Process the code block
134
+ extractFromCodeBlock(filePath, codeBlockStart, codeBlockLines, examples);
135
+ inCodeBlock = false;
136
+ codeBlockLines = [];
137
+ }
138
+ continue;
139
+ }
140
+ if (inCodeBlock) {
141
+ codeBlockLines.push(line);
142
+ }
143
+ }
144
+ return examples;
145
+ }
146
+ function extractFromCodeBlock(filePath, startLine, blockLines, results) {
147
+ // Pattern: YOUR_AGENT_core op:<name> [params: { ... }]
148
+ // Also matches: op:<name> params: { ... } (without facade prefix)
149
+ const opPattern = /(?:YOUR_AGENT_\w+\s+)?op:(\w+)(?:\s+params:\s*(.*))?/;
150
+ for (let i = 0; i < blockLines.length; i++) {
151
+ const line = blockLines[i];
152
+ const match = line.match(opPattern);
153
+ if (!match)
154
+ continue;
155
+ const opName = match[1];
156
+ const lineNum = startLine + i + 1; // 1-indexed
157
+ // Collect params — may be inline or on following lines
158
+ let rawParams = '';
159
+ if (match[2]) {
160
+ // Params start on same line
161
+ rawParams = match[2].trim();
162
+ }
163
+ else if (i + 1 < blockLines.length && blockLines[i + 1].trim().startsWith('params:')) {
164
+ // Params on next line(s)
165
+ const paramsLine = blockLines[i + 1].trim();
166
+ const paramsMatch = paramsLine.match(/^params:\s*(.*)/);
167
+ if (paramsMatch) {
168
+ rawParams = paramsMatch[1].trim();
169
+ }
170
+ }
171
+ // If we found params start, collect the full multi-line object
172
+ if (rawParams) {
173
+ // Collect continuation lines for multi-line objects
174
+ const fullParams = collectMultiLineParams(blockLines, i, rawParams);
175
+ const { parsed, error } = parseLooseJson(fullParams);
176
+ results.push({
177
+ file: filePath,
178
+ line: lineNum,
179
+ opName,
180
+ rawParams: fullParams,
181
+ parsedParams: parsed,
182
+ parseError: error,
183
+ });
184
+ }
185
+ else {
186
+ // Op without params — nothing to validate
187
+ }
188
+ }
189
+ }
190
+ /**
191
+ * Collect multi-line params from code block lines.
192
+ * Handles the common pattern where params span multiple indented lines:
193
+ * params: {
194
+ * key: "value",
195
+ * nested: { ... }
196
+ * }
197
+ */
198
+ function collectMultiLineParams(blockLines, opLineIdx, initial) {
199
+ // If the initial string already has balanced braces, return it
200
+ if (isBalanced(initial))
201
+ return initial;
202
+ // Start from the line after the op line (or after params: line)
203
+ let startIdx = opLineIdx + 1;
204
+ if (!blockLines[opLineIdx].includes('params:') && startIdx < blockLines.length) {
205
+ if (blockLines[startIdx].trim().startsWith('params:')) {
206
+ startIdx++;
207
+ }
208
+ }
209
+ let result = initial;
210
+ for (let j = startIdx; j < blockLines.length; j++) {
211
+ const nextLine = blockLines[j].trim();
212
+ if (!nextLine)
213
+ continue;
214
+ // Stop if we hit another op: line
215
+ if (nextLine.match(/(?:YOUR_AGENT_\w+\s+)?op:\w+/))
216
+ break;
217
+ result += '\n' + nextLine;
218
+ if (isBalanced(result))
219
+ break;
220
+ }
221
+ return result;
222
+ }
223
+ /** Check if braces/brackets are balanced in a string. */
224
+ function isBalanced(s) {
225
+ let depth = 0;
226
+ for (const ch of s) {
227
+ if (ch === '{' || ch === '[')
228
+ depth++;
229
+ if (ch === '}' || ch === ']')
230
+ depth--;
231
+ if (depth < 0)
232
+ return false;
233
+ }
234
+ return depth === 0;
235
+ }
236
+ /**
237
+ * Parse loose JS-like object notation into a JS object.
238
+ * Handles: unquoted keys, single quotes, trailing commas, [...] arrays,
239
+ * template strings like "<placeholder>".
240
+ */
241
+ function parseLooseJson(raw) {
242
+ if (!raw.trim())
243
+ return { parsed: null };
244
+ try {
245
+ // Normalize to valid JSON-ish:
246
+ const normalized = raw
247
+ // Replace <placeholder> values with "placeholder"
248
+ .replace(/"<([^">]+)>"/g, '"$1"')
249
+ // Unquoted keys → quoted keys
250
+ .replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":')
251
+ // Single quotes → double quotes (simple cases)
252
+ .replace(/'/g, '"')
253
+ // Trailing commas before } or ]
254
+ .replace(/,\s*([}\]])/g, '$1')
255
+ // Spread syntax [...] → placeholder
256
+ .replace(/\.\.\./g, '')
257
+ // Handle array shorthand [item1, item2, ...]
258
+ .replace(/\["?<[^>]+>"?\]/g, '["placeholder"]');
259
+ // Try to parse
260
+ const result = JSON.parse(normalized);
261
+ return { parsed: result };
262
+ }
263
+ catch (e) {
264
+ // Second attempt: extract key-value pairs manually for simple flat objects
265
+ try {
266
+ const result = extractFlatParams(raw);
267
+ if (result && Object.keys(result).length > 0) {
268
+ return { parsed: result };
269
+ }
270
+ }
271
+ catch {
272
+ // fall through
273
+ }
274
+ return {
275
+ parsed: null,
276
+ error: `Cannot parse params: ${e.message}`,
277
+ };
278
+ }
279
+ }
280
+ /**
281
+ * Extract flat key-value pairs from loose notation.
282
+ * Handles: `key: "value"`, `key: true`, `key: 123`
283
+ */
284
+ function extractFlatParams(raw) {
285
+ const result = {};
286
+ // Match patterns like: key: "value" or key: value or key: [...] or key: {...}
287
+ const kvPattern = /(\w+)\s*:\s*(?:"([^"]*)"|\[([^\]]*)\]|(\{[^}]*\})|(\w+))/g;
288
+ let match;
289
+ let found = false;
290
+ while ((match = kvPattern.exec(raw)) !== null) {
291
+ found = true;
292
+ const key = match[1];
293
+ if (match[2] !== undefined) {
294
+ // Quoted string
295
+ result[key] = match[2].replace(/<[^>]+>/g, 'placeholder');
296
+ }
297
+ else if (match[3] !== undefined) {
298
+ // Array
299
+ result[key] = ['placeholder'];
300
+ }
301
+ else if (match[4] !== undefined) {
302
+ // Object — keep as generic object
303
+ result[key] = {};
304
+ }
305
+ else if (match[5] !== undefined) {
306
+ // Unquoted value
307
+ const val = match[5];
308
+ if (val === 'true')
309
+ result[key] = true;
310
+ else if (val === 'false')
311
+ result[key] = false;
312
+ else if (/^\d+$/.test(val))
313
+ result[key] = parseInt(val, 10);
314
+ else
315
+ result[key] = val;
316
+ }
317
+ }
318
+ return found ? result : null;
319
+ }
320
+ // ── Validation ──────────────────────────────────────────────────────────
321
+ /**
322
+ * Check if a value looks like a placeholder (e.g., "correct-tier", "type",
323
+ * "critical|warning|suggestion") rather than a concrete example value.
324
+ */
325
+ function isPlaceholder(value) {
326
+ if (typeof value !== 'string')
327
+ return false;
328
+ // Pipe-separated enum hints like "critical|warning|suggestion"
329
+ if (value.includes('|'))
330
+ return true;
331
+ // Common placeholder patterns
332
+ if (/^<.*>$/.test(value))
333
+ return true;
334
+ // Generic placeholder words (including hyphenated like "correct-tier", "entry-id")
335
+ if (/^(placeholder|example|value|name|id|title|description|type|domain)$/i.test(value))
336
+ return true;
337
+ if (/^[\w]+-[\w]+$/.test(value) &&
338
+ /\b(correct|your|my|the|this|some|new|old|entry|item|current)\b/i.test(value))
339
+ return true;
340
+ return false;
341
+ }
342
+ /**
343
+ * Filter Zod issues to exclude those caused by placeholder values.
344
+ * Keeps structural issues (missing required fields, wrong types) but
345
+ * skips enum mismatches on placeholder strings.
346
+ */
347
+ function isPlaceholderIssue(issue, params) {
348
+ // "Invalid enum value" on a placeholder string
349
+ if (issue.code === 'invalid_enum_value') {
350
+ const received = issue.received ?? getNestedValue(params, issue.path);
351
+ if (isPlaceholder(received))
352
+ return true;
353
+ }
354
+ return false;
355
+ }
356
+ /** Traverse nested object by path segments. */
357
+ function getNestedValue(obj, path) {
358
+ let current = obj;
359
+ for (const key of path) {
360
+ if (current === null || current === undefined || typeof current !== 'object')
361
+ return undefined;
362
+ current = current[key];
363
+ }
364
+ return current;
365
+ }
366
+ function validateExamples(examples, registry) {
367
+ const errors = [];
368
+ for (const ex of examples) {
369
+ // Skip examples where params couldn't be parsed
370
+ if (ex.parseError) {
371
+ // Don't report parse errors — many SKILL.md examples use placeholder syntax
372
+ // that's intentionally not valid JSON (e.g., "<title>", "...")
373
+ continue;
374
+ }
375
+ if (!ex.parsedParams)
376
+ continue;
377
+ const schema = registry.get(ex.opName);
378
+ if (!schema) {
379
+ // Op not found in registry — may be from a facade that failed to load,
380
+ // or a typo in the SKILL.md. Report it.
381
+ errors.push({
382
+ file: ex.file,
383
+ line: ex.line,
384
+ opName: ex.opName,
385
+ message: `unknown op — not found in any facade schema registry`,
386
+ });
387
+ continue;
388
+ }
389
+ // Validate params against schema
390
+ const result = schema.safeParse(ex.parsedParams);
391
+ if (!result.success && result.error) {
392
+ for (const issue of result.error.issues) {
393
+ // Skip issues caused by placeholder values
394
+ if (isPlaceholderIssue(issue, ex.parsedParams)) {
395
+ continue;
396
+ }
397
+ const path = issue.path.join('.');
398
+ errors.push({
399
+ file: ex.file,
400
+ line: ex.line,
401
+ opName: ex.opName,
402
+ message: `${path ? path + ': ' : ''}${issue.message}`,
403
+ });
404
+ }
405
+ }
406
+ }
407
+ return errors;
408
+ }
409
+ // ── SKILL.md discovery ──────────────────────────────────────────────────
410
+ function discoverSkillDocs(rootDir) {
411
+ const skillsDir = join(rootDir, 'packages', 'forge', 'src', 'skills');
412
+ const paths = [];
413
+ if (!existsSync(skillsDir))
414
+ return paths;
415
+ const entries = readdirSync(skillsDir, { withFileTypes: true });
416
+ for (const entry of entries) {
417
+ if (!entry.isDirectory())
418
+ continue;
419
+ const skillMd = join(skillsDir, entry.name, 'SKILL.md');
420
+ if (existsSync(skillMd)) {
421
+ paths.push(skillMd);
422
+ }
423
+ }
424
+ return paths;
425
+ }
426
+ // ── Main ────────────────────────────────────────────────────────────────
427
+ export function validateSkillDocs(rootDir) {
428
+ const registry = buildSchemaRegistry();
429
+ const skillFiles = discoverSkillDocs(rootDir);
430
+ let totalExamples = 0;
431
+ const allErrors = [];
432
+ for (const file of skillFiles) {
433
+ const examples = extractOpExamples(file);
434
+ totalExamples += examples.length;
435
+ const errors = validateExamples(examples, registry);
436
+ allErrors.push(...errors);
437
+ }
438
+ return {
439
+ errors: allErrors,
440
+ totalExamples,
441
+ totalFiles: skillFiles.length,
442
+ registrySize: registry.size,
443
+ };
444
+ }
445
+ // ── CLI entry point ─────────────────────────────────────────────────────
446
+ function main() {
447
+ // Find project root — walk up from this file's location
448
+ const thisDir = new URL('.', import.meta.url).pathname;
449
+ const rootDir = resolve(thisDir, '..', '..', '..', '..');
450
+ console.log('Validating SKILL.md op-call examples against Zod schemas...\n');
451
+ const { errors, totalExamples, totalFiles, registrySize } = validateSkillDocs(rootDir);
452
+ console.log(` Schema registry: ${registrySize} ops`);
453
+ console.log(` Skill files: ${totalFiles}`);
454
+ console.log(` Op examples: ${totalExamples}`);
455
+ console.log('');
456
+ if (errors.length === 0) {
457
+ console.log('All examples validate against their schemas.');
458
+ process.exit(0);
459
+ }
460
+ console.log(`Found ${errors.length} validation error(s):\n`);
461
+ for (const err of errors) {
462
+ const relPath = relative(rootDir, err.file);
463
+ console.log(` ${relPath}:${err.line} — ${err.opName}: ${err.message}`);
464
+ }
465
+ console.log('');
466
+ process.exit(1);
467
+ }
468
+ // Run if invoked directly
469
+ const isMainModule = typeof process !== 'undefined' &&
470
+ process.argv[1] &&
471
+ (process.argv[1].endsWith('validate-skill-docs.ts') ||
472
+ process.argv[1].endsWith('validate-skill-docs.js'));
473
+ if (isMainModule) {
474
+ main();
475
+ }
476
+ //# sourceMappingURL=validate-skill-docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-skill-docs.js","sourceRoot":"","sources":["../../src/skills/validate-skill-docs.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soleri/core",
3
- "version": "9.13.0",
3
+ "version": "9.14.4",
4
4
  "description": "Shared engine for Soleri agents — vault, brain, planner, LLM utilities, and facade infrastructure.",
5
5
  "keywords": [
6
6
  "agent",
@@ -45,7 +45,7 @@
45
45
  "access": "public"
46
46
  },
47
47
  "scripts": {
48
- "build": "tsc",
48
+ "build": "tsc && rm -rf dist/knowledge-packs && cp -r ../../knowledge-packs dist/knowledge-packs",
49
49
  "typecheck": "tsc --noEmit",
50
50
  "test": "vitest run",
51
51
  "test:watch": "vitest",
@@ -156,6 +156,55 @@ describe('deviation-detection', () => {
156
156
  expect(plan.steps[1].allowedTools).toEqual(['tool_b']);
157
157
  });
158
158
 
159
+ it('injects workflowPrompt and workflowName when override has prompt', () => {
160
+ const plan = makePlan([
161
+ {
162
+ id: 'step-1',
163
+ name: 'Step one',
164
+ tools: [],
165
+ parallel: false,
166
+ requires: [],
167
+ status: 'pending',
168
+ },
169
+ ]);
170
+
171
+ const override: WorkflowOverride = {
172
+ name: 'feature-dev',
173
+ prompt: '# Feature Development\nFollow TDD approach.',
174
+ gates: [],
175
+ tools: [],
176
+ };
177
+
178
+ applyWorkflowOverride(plan, override);
179
+
180
+ expect(plan.workflowPrompt).toBe('# Feature Development\nFollow TDD approach.');
181
+ expect(plan.workflowName).toBe('feature-dev');
182
+ });
183
+
184
+ it('does not set workflowPrompt when override has no prompt', () => {
185
+ const plan = makePlan([
186
+ {
187
+ id: 'step-1',
188
+ name: 'Step one',
189
+ tools: [],
190
+ parallel: false,
191
+ requires: [],
192
+ status: 'pending',
193
+ },
194
+ ]);
195
+
196
+ const override: WorkflowOverride = {
197
+ name: 'test-workflow',
198
+ gates: [],
199
+ tools: [],
200
+ };
201
+
202
+ applyWorkflowOverride(plan, override);
203
+
204
+ expect(plan.workflowPrompt).toBeUndefined();
205
+ expect(plan.workflowName).toBeUndefined();
206
+ });
207
+
159
208
  it('does not set allowedTools on steps that remain tool-less', () => {
160
209
  const plan = makePlan([
161
210
  {
@@ -130,22 +130,22 @@ describe('ClaudeCodeAdapter', () => {
130
130
 
131
131
  it('should generate hookify file for pre-commit trigger', () => {
132
132
  const rule = createRule({
133
- id: 'no-ai-attribution',
133
+ id: 'no-console-log',
134
134
  trigger: 'pre-commit',
135
- pattern: 'Co-Authored-By',
136
- message: 'No AI attribution in commits',
137
- description: 'Blocks AI co-author lines',
135
+ pattern: 'console\\.log',
136
+ message: 'No console.log in commits',
137
+ description: 'Blocks console.log statements',
138
138
  });
139
139
  const result = adapter.translate(createConfig([rule]));
140
140
 
141
141
  expect(result.files).toHaveLength(1);
142
- expect(result.files[0].path).toBe('.claude/hookify.no-ai-attribution.local.md');
142
+ expect(result.files[0].path).toBe('.claude/hookify.no-console-log.local.md');
143
143
 
144
144
  const content = result.files[0].content;
145
- expect(content).toContain('name: no-ai-attribution');
146
- expect(content).toContain('Blocks AI co-author lines');
147
- expect(content).toContain('Pattern: `Co-Authored-By`');
148
- expect(content).toContain('No AI attribution in commits');
145
+ expect(content).toContain('name: no-console-log');
146
+ expect(content).toContain('Blocks console.log statements');
147
+ expect(content).toContain('Pattern: `console\\.log`');
148
+ expect(content).toContain('No console.log in commits');
149
149
  });
150
150
 
151
151
  it('should generate hookify file without pattern when none provided', () => {
@@ -163,10 +163,12 @@ async function main(): Promise<void> {
163
163
  .join(', ')})`,
164
164
  );
165
165
 
166
- // 6b. Auto-sync skills to ~/.claude/skills/
166
+ // 6b. Auto-sync skills to project-local .claude/skills/
167
167
  const skillsDir = join(agentDir, 'skills');
168
168
  if (existsSync(skillsDir)) {
169
- const syncResult = syncSkillsToClaudeCode([skillsDir], config.name as string);
169
+ const syncResult = syncSkillsToClaudeCode([skillsDir], config.name as string, {
170
+ projectRoot: process.cwd(),
171
+ });
170
172
  const total = syncResult.installed.length + syncResult.updated.length;
171
173
  if (total > 0) {
172
174
  console.error(
@@ -176,6 +178,9 @@ async function main(): Promise<void> {
176
178
  if (syncResult.removed.length) {
177
179
  console.error(`${tag} Removed ${syncResult.removed.length} orphaned skill(s)`);
178
180
  }
181
+ if (syncResult.cleanedGlobal.length) {
182
+ console.error(`${tag} Cleaned ${syncResult.cleanedGlobal.length} stale global skill(s)`);
183
+ }
179
184
  }
180
185
 
181
186
  // 7. Load domain packs
@@ -194,6 +194,10 @@ export interface OrchestrationPlan {
194
194
  estimatedTools: number;
195
195
  context: OrchestrationContext;
196
196
  deviations?: ToolDeviation[];
197
+ /** Workflow prompt.md content injected by applyWorkflowOverride */
198
+ workflowPrompt?: string;
199
+ /** Name of the matched workflow */
200
+ workflowName?: string;
197
201
  }
198
202
 
199
203
  export interface OrchestrationContext {