@tanstack/intent 0.0.36 → 0.0.37

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 (52) hide show
  1. package/dist/artifact-coverage-DA26utB1.mjs +3 -0
  2. package/dist/cli-error-BrMXlbtx.mjs +15 -0
  3. package/dist/cli-support-CHEYZ9xj.mjs +6 -0
  4. package/dist/cli-support-Dk2rgYli.mjs +114 -0
  5. package/dist/cli.mjs +17 -763
  6. package/dist/core-BlJqkv0a.mjs +497 -0
  7. package/dist/core.d.mts +85 -0
  8. package/dist/core.mjs +9 -0
  9. package/dist/display-COlw5FaB.mjs +5 -0
  10. package/dist/{display-CAof6doy.mjs → display-CVeoAwBd.mjs} +1 -1
  11. package/dist/edit-package-json-CzWlMXOf.mjs +8 -0
  12. package/dist/index.d.mts +5 -2
  13. package/dist/index.mjs +11 -11
  14. package/dist/install-BAUG1FD8.mjs +7 -0
  15. package/dist/{install-2_wkomiT.mjs → install-DA19Vg17.mjs} +7 -111
  16. package/dist/intent-library.mjs +8 -7
  17. package/dist/{library-scanner-fexXlPXb.mjs → library-scanner-CHepLJQJ.mjs} +2 -2
  18. package/dist/library-scanner.d.mts +1 -1
  19. package/dist/library-scanner.mjs +3 -3
  20. package/dist/list-D6osUZl7.mjs +107 -0
  21. package/dist/load-CzvLUFur.mjs +70 -0
  22. package/dist/meta-CYV9EzM8.mjs +38 -0
  23. package/dist/{project-context-alYMNoNa.mjs → project-context-CfSZGJFC.mjs} +1 -1
  24. package/dist/resolver-BTeG2oyZ.mjs +196 -0
  25. package/dist/scaffold-D2vwv9ls.mjs +75 -0
  26. package/dist/scanner-DgRSm4y0.mjs +6 -0
  27. package/dist/{scanner-B1j-wDhj.mjs → scanner-W6797hWs.mjs} +101 -19
  28. package/dist/{setup-Dp-W8y0Y.mjs → setup-B-1hsdmA.mjs} +2 -2
  29. package/dist/setup-github-actions-emXSyGy3.mjs +8 -0
  30. package/dist/setup.d.mts +1 -1
  31. package/dist/setup.mjs +4 -4
  32. package/dist/{skill-paths-8k9K9y26.mjs → skill-paths-DNOHrvL5.mjs} +1 -1
  33. package/dist/stale-flPZnWfI.mjs +53 -0
  34. package/dist/{staleness-PdgakrCQ.mjs → staleness-CFr3W-RI.mjs} +2 -2
  35. package/dist/staleness-DpyuNdd5.mjs +5 -0
  36. package/dist/{types-DT7Y6TFz.d.mts → types-S2zpibHp.d.mts} +1 -1
  37. package/dist/{utils-dkVvY7D7.mjs → utils-BHzSyNeJ.mjs} +1 -1
  38. package/dist/validate-ugk2DZBd.mjs +271 -0
  39. package/dist/{workflow-review-Dz_ofcYQ.mjs → workflow-review-CIdJXmKP.mjs} +1 -1
  40. package/dist/{workspace-patterns-x-dLZxx4.mjs → workspace-patterns-BGQcoSy7.mjs} +2 -2
  41. package/dist/{workspace-patterns-BN2A_60g.mjs → workspace-patterns-CNhdqCO4.mjs} +1 -1
  42. package/package.json +7 -3
  43. package/dist/artifact-coverage-BAN2W6aH.mjs +0 -3
  44. package/dist/display-B3vkG99D.mjs +0 -5
  45. package/dist/resolver-Whd12ksO.mjs +0 -70
  46. package/dist/scanner-C2YjF4w_.mjs +0 -6
  47. package/dist/staleness-DpbmYod4.mjs +0 -5
  48. /package/dist/{artifact-coverage-wLNVX8yC.mjs → artifact-coverage-DgWuVqUp.mjs} +0 -0
  49. /package/dist/{setup-t1i2o2-h.d.mts → setup-ldoQOQot.d.mts} +0 -0
  50. /package/dist/{skill-use-BzuuvLM7.mjs → skill-use-umYvZl94.mjs} +0 -0
  51. /package/dist/{utils-COlDcU72.mjs → utils-mdb4i6VA.mjs} +0 -0
  52. /package/dist/{workflow-review-CwkPVIQf.mjs → workflow-review-CwcR2ge4.mjs} +0 -0
package/dist/cli.mjs CHANGED
@@ -1,797 +1,51 @@
1
1
  #!/usr/bin/env node
2
- import { s as toPosixPath } from "./utils-COlDcU72.mjs";
3
- import { n as findWorkspacePackages } from "./workspace-patterns-BN2A_60g.mjs";
4
- import { i as parseSkillUse } from "./skill-use-BzuuvLM7.mjs";
5
- import { r as resolveSkillUse } from "./resolver-Whd12ksO.mjs";
6
- import { t as resolveProjectContext } from "./project-context-alYMNoNa.mjs";
7
- import { a as scanIntentsOrFail, c as fail, i as resolveStaleTargets, l as isCliFailure, n as runInstallCommand, o as scanOptionsFromGlobalFlags, r as getMetaDir, s as printWarnings } from "./install-2_wkomiT.mjs";
8
- import { appendFileSync, existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
9
- import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
2
+ import { n as isCliFailure, t as fail } from "./cli-error-BrMXlbtx.mjs";
3
+ import { realpathSync } from "node:fs";
10
4
  import { fileURLToPath } from "node:url";
11
5
  import { cac } from "cac";
12
6
 
13
- //#region src/commands/edit-package-json.ts
14
- async function runEditPackageJsonCommand(root) {
15
- const { runEditPackageJsonAll } = await import("./setup.mjs");
16
- runEditPackageJsonAll(root);
17
- }
18
-
19
- //#endregion
20
- //#region src/commands/list.ts
21
- function formatScanCoverage(result) {
22
- const coverage = [];
23
- if (result.nodeModules.local.scanned) coverage.push("project node_modules");
24
- if (result.nodeModules.global.scanned) coverage.push("global node_modules");
25
- return coverage.join(", ");
26
- }
27
- function printVersionConflicts(result) {
28
- if (result.conflicts.length === 0) return;
29
- console.log("\nVersion conflicts:\n");
30
- for (const conflict of result.conflicts) {
31
- console.log(` ${conflict.packageName} -> using ${conflict.chosen.version}`);
32
- console.log(` chosen: ${conflict.chosen.packageRoot}`);
33
- for (const variant of conflict.variants) {
34
- if (variant.packageRoot === conflict.chosen.packageRoot) continue;
35
- console.log(` also found: ${variant.version} at ${variant.packageRoot}`);
36
- }
37
- console.log();
38
- }
39
- }
40
- async function runListCommand(options, scanIntentsOrFail$1) {
41
- const result = await scanIntentsOrFail$1(scanOptionsFromGlobalFlags(options));
42
- if (options.json) {
43
- console.log(JSON.stringify(result, null, 2));
44
- return;
45
- }
46
- const { computeSkillNameWidth, printSkillTree, printTable } = await import("./display-B3vkG99D.mjs");
47
- const scanCoverage = formatScanCoverage(result);
48
- if (result.packages.length === 0) {
49
- console.log("No intent-enabled packages found.");
50
- if (scanCoverage) console.log(`Scanned: ${scanCoverage}`);
51
- if (result.warnings.length > 0) {
52
- console.log();
53
- printWarnings(result.warnings);
54
- }
55
- return;
56
- }
57
- const totalSkills = result.packages.reduce((sum, pkg) => sum + pkg.skills.length, 0);
58
- console.log(`\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`);
59
- if (scanCoverage) console.log(`Scanned: ${scanCoverage}${result.nodeModules.global.scanned ? " (local packages take precedence)" : ""}\n`);
60
- printTable([
61
- "PACKAGE",
62
- "SOURCE",
63
- "VERSION",
64
- "SKILLS",
65
- "REQUIRES"
66
- ], result.packages.map((pkg) => [
67
- pkg.name,
68
- pkg.source,
69
- pkg.version,
70
- String(pkg.skills.length),
71
- pkg.intent.requires?.join(", ") || "–"
72
- ]));
73
- printVersionConflicts(result);
74
- const nameWidth = computeSkillNameWidth(result.packages.map((pkg) => pkg.skills));
75
- const showTypes = result.packages.some((pkg) => pkg.skills.some((skill) => skill.type));
76
- console.log(`\nSkills:\n`);
77
- for (const pkg of result.packages) {
78
- console.log(` ${pkg.name}`);
79
- printSkillTree(pkg.skills, {
80
- nameWidth,
81
- packageName: pkg.name,
82
- showTypes
83
- });
84
- console.log();
85
- }
86
- console.log("Feedback:");
87
- console.log(" Submit feedback on skill usage to help maintainers improve the skills.");
88
- console.log(" Load: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md");
89
- console.log();
90
- printWarnings(result.warnings);
91
- }
92
-
93
- //#endregion
94
- //#region src/commands/load.ts
95
- function resolveFromCwd(path) {
96
- return resolve(process.cwd(), path);
97
- }
98
- function isPathInsidePackageRoot(path, packageRoot) {
99
- const relativePath = relative(resolveFromCwd(packageRoot), resolveFromCwd(path));
100
- return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
101
- }
102
- function splitDestinationSuffix(destination) {
103
- const hashIndex = destination.indexOf("#");
104
- const queryIndex = destination.indexOf("?");
105
- const suffixIndex = hashIndex === -1 ? queryIndex : queryIndex === -1 ? hashIndex : Math.min(hashIndex, queryIndex);
106
- if (suffixIndex === -1) return {
107
- pathPart: destination,
108
- suffix: ""
109
- };
110
- return {
111
- pathPart: destination.slice(0, suffixIndex),
112
- suffix: destination.slice(suffixIndex)
113
- };
114
- }
115
- function isExternalOrAbsoluteDestination(destination) {
116
- return destination === "" || destination.startsWith("#") || destination.startsWith("?") || destination.startsWith("//") || /^[A-Za-z][A-Za-z0-9+.-]*:/.test(destination) || isAbsolute(destination);
117
- }
118
- function findClosingBracket(line, start) {
119
- let depth = 0;
120
- for (let index = start; index < line.length; index++) {
121
- const char = line[index];
122
- if (char === "\\") {
123
- index++;
124
- continue;
125
- }
126
- if (char === "[") {
127
- depth++;
128
- continue;
129
- }
130
- if (char === "]") {
131
- depth--;
132
- if (depth === 0) return index;
133
- }
134
- }
135
- return -1;
136
- }
137
- function findClosingParen(line, start) {
138
- for (let index = start; index < line.length; index++) {
139
- const char = line[index];
140
- if (char === "\\") {
141
- index++;
142
- continue;
143
- }
144
- if (char === ")") return index;
145
- }
146
- return -1;
147
- }
148
- function readBareDestination(line, start) {
149
- let depth = 0;
150
- for (let index = start; index < line.length; index++) {
151
- const char = line[index];
152
- if (char === "\\") {
153
- index++;
154
- continue;
155
- }
156
- if (char === "(") {
157
- depth++;
158
- continue;
159
- }
160
- if (char === ")") {
161
- if (depth === 0) return {
162
- destinationEnd: index,
163
- endParen: index
164
- };
165
- depth--;
166
- continue;
167
- }
168
- if (/\s/.test(char) && depth === 0) {
169
- const endParen = findClosingParen(line, index);
170
- if (endParen === -1) return null;
171
- return {
172
- destinationEnd: index,
173
- endParen
174
- };
175
- }
176
- }
177
- return null;
178
- }
179
- function readMarkdownDestination(line, start) {
180
- let cursor = start;
181
- while (cursor < line.length && /\s/.test(line[cursor])) cursor++;
182
- if (line[cursor] === "<") {
183
- const destinationStart = cursor + 1;
184
- const destinationEnd = line.indexOf(">", destinationStart);
185
- if (destinationEnd === -1) return null;
186
- const endParen = findClosingParen(line, destinationEnd + 1);
187
- if (endParen === -1) return null;
188
- return {
189
- destination: line.slice(destinationStart, destinationEnd),
190
- destinationStart,
191
- destinationEnd,
192
- endParen
193
- };
194
- }
195
- const read = readBareDestination(line, cursor);
196
- if (!read) return null;
197
- return {
198
- destination: line.slice(cursor, read.destinationEnd),
199
- destinationStart: cursor,
200
- destinationEnd: read.destinationEnd,
201
- endParen: read.endParen
202
- };
203
- }
204
- function getCodeFenceMarker(line) {
205
- const marker = line.match(/^\s*(`{3,}|~{3,})/)?.[1]?.[0];
206
- return marker === "`" || marker === "~" ? marker : null;
207
- }
208
- function rewriteMarkdownDestination({ context, destination }) {
209
- if (isExternalOrAbsoluteDestination(destination)) return destination;
210
- const { pathPart, suffix } = splitDestinationSuffix(destination);
211
- if (isExternalOrAbsoluteDestination(pathPart)) return destination;
212
- const resolvedDestinationPath = resolve(context.skillDir, pathPart);
213
- const relativeToPackageRoot = relative(context.resolvedPackageRoot, resolvedDestinationPath);
214
- if (relativeToPackageRoot.startsWith("..") || isAbsolute(relativeToPackageRoot)) return destination;
215
- const relativeToCwd = relative(context.cwd, resolvedDestinationPath);
216
- return `${toPosixPath(relativeToCwd && !relativeToCwd.startsWith("..") && !isAbsolute(relativeToCwd) ? relativeToCwd : resolvedDestinationPath)}${suffix}`;
217
- }
218
- function rewriteMarkdownLineDestinations({ context, line }) {
219
- if (!line.includes("[")) return line;
220
- let output = "";
221
- let cursor = 0;
222
- while (cursor < line.length) {
223
- const nextCodeStart = line.indexOf("`", cursor);
224
- const nextLinkStart = line.indexOf("[", cursor);
225
- if (nextLinkStart === -1) {
226
- output += line.slice(cursor);
227
- break;
228
- }
229
- if (nextCodeStart !== -1 && nextCodeStart < nextLinkStart) {
230
- output += line.slice(cursor, nextCodeStart);
231
- cursor = nextCodeStart;
232
- const codeStart = cursor;
233
- while (cursor < line.length && line[cursor] === "`") cursor++;
234
- const marker = line.slice(codeStart, cursor);
235
- const codeEnd = line.indexOf(marker, cursor);
236
- if (codeEnd === -1) {
237
- output += line.slice(codeStart);
238
- break;
239
- }
240
- output += line.slice(codeStart, codeEnd + marker.length);
241
- cursor = codeEnd + marker.length;
242
- continue;
243
- }
244
- const linkStart = nextLinkStart > 0 && line[nextLinkStart - 1] === "!" ? nextLinkStart - 1 : nextLinkStart;
245
- output += line.slice(cursor, linkStart);
246
- const labelEnd = findClosingBracket(line, nextLinkStart);
247
- if (labelEnd === -1) {
248
- output += line.slice(linkStart);
249
- break;
250
- }
251
- if (line[labelEnd + 1] !== "(") {
252
- output += line.slice(linkStart, nextLinkStart + 1);
253
- cursor = nextLinkStart + 1;
254
- continue;
255
- }
256
- const destination = readMarkdownDestination(line, labelEnd + 2);
257
- if (!destination) {
258
- output += line.slice(linkStart, nextLinkStart + 1);
259
- cursor = nextLinkStart + 1;
260
- continue;
261
- }
262
- const rewritten = rewriteMarkdownDestination({
263
- context,
264
- destination: destination.destination
265
- });
266
- output += line.slice(linkStart, destination.destinationStart) + rewritten + line.slice(destination.destinationEnd, destination.endParen + 1);
267
- cursor = destination.endParen + 1;
268
- }
269
- return output;
270
- }
271
- function rewriteLoadedSkillMarkdownDestinations({ content, packageRoot, skillFilePath }) {
272
- const context = {
273
- cwd: process.cwd(),
274
- resolvedPackageRoot: resolveFromCwd(packageRoot),
275
- skillDir: dirname(skillFilePath)
276
- };
277
- let inFence = null;
278
- const parts = content.split(/(\r?\n)/);
279
- let output = "";
280
- for (let index = 0; index < parts.length; index += 2) {
281
- const line = parts[index] ?? "";
282
- const newline = parts[index + 1] ?? "";
283
- const marker = getCodeFenceMarker(line);
284
- if (inFence) {
285
- output += line + newline;
286
- if (marker === inFence) inFence = null;
287
- continue;
288
- }
289
- if (marker) {
290
- inFence = marker;
291
- output += line + newline;
292
- continue;
293
- }
294
- output += rewriteMarkdownLineDestinations({
295
- context,
296
- line
297
- }) + newline;
298
- }
299
- return output;
300
- }
301
- async function runLoadCommand(use, options, scanIntentsOrFail$1) {
302
- if (!use) fail("Missing skill use. Expected: intent load <package>#<skill>");
303
- if (options.json && options.path) fail("Use either --json or --path, not both.");
304
- parseSkillUse(use);
305
- const resolved = resolveSkillUse(use, await scanIntentsOrFail$1(scanOptionsFromGlobalFlags(options)));
306
- const resolvedPath = resolveFromCwd(resolved.path);
307
- if (!isPathInsidePackageRoot(resolved.path, resolved.packageRoot)) fail(`Resolved skill path for "${use}" is outside package root: ${resolved.path}`);
308
- if (!existsSync(resolvedPath)) fail(`Resolved skill file was not found: ${resolved.path}`);
309
- if (options.path) {
310
- console.log(resolved.path);
311
- for (const warning of resolved.warnings) console.error(`Warning: ${warning}`);
312
- return;
313
- }
314
- const content = rewriteLoadedSkillMarkdownDestinations({
315
- content: readFileSync(resolvedPath, "utf8"),
316
- packageRoot: resolved.packageRoot,
317
- skillFilePath: resolvedPath
318
- });
319
- if (options.json) {
320
- console.log(JSON.stringify({
321
- package: resolved.packageName,
322
- skill: resolved.skillName,
323
- path: resolved.path,
324
- packageRoot: resolved.packageRoot,
325
- source: resolved.source,
326
- version: resolved.version,
327
- content,
328
- warnings: resolved.warnings
329
- }, null, 2));
330
- return;
331
- }
332
- process.stdout.write(content);
333
- for (const warning of resolved.warnings) console.error(`Warning: ${warning}`);
334
- }
335
-
336
- //#endregion
337
- //#region src/commands/meta.ts
338
- async function runMetaCommand(name, metaDir) {
339
- if (!existsSync(metaDir)) fail("Meta-skills directory not found.");
340
- if (name) {
341
- if (name.includes("..") || name.includes("/") || name.includes("\\")) fail(`Invalid meta-skill name: "${name}"`);
342
- const skillFile = join(metaDir, name, "SKILL.md");
343
- if (!existsSync(skillFile)) fail(`Meta-skill "${name}" not found. Run \`intent meta\` to list available meta-skills.`);
344
- try {
345
- console.log(readFileSync(skillFile, "utf8"));
346
- } catch (err) {
347
- fail(`Failed to read meta-skill "${name}": ${err instanceof Error ? err.message : String(err)}`);
348
- }
349
- return;
350
- }
351
- const { parseFrontmatter } = await import("./utils-dkVvY7D7.mjs");
352
- const entries = readdirSync(metaDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => existsSync(join(metaDir, entry.name, "SKILL.md")));
353
- if (entries.length === 0) {
354
- console.log("No meta-skills found.");
355
- return;
356
- }
357
- console.log("Meta-skills (for library maintainers):\n");
358
- for (const entry of entries) {
359
- const fm = parseFrontmatter(join(metaDir, entry.name, "SKILL.md"));
360
- let description = "";
361
- if (typeof fm?.description === "string") description = fm.description.replace(/\s+/g, " ").trim();
362
- const shortDesc = description.length > 60 ? `${description.slice(0, 57)}...` : description;
363
- console.log(` ${entry.name.padEnd(28)} ${shortDesc}`);
364
- }
365
- console.log("\nUsage: load the SKILL.md into your AI agent conversation.");
366
- console.log("Path: node_modules/@tanstack/intent/meta/<name>/SKILL.md");
367
- }
368
-
369
- //#endregion
370
- //#region src/commands/scaffold.ts
371
- function runScaffoldCommand(metaDir) {
372
- function metaSkillPath(name) {
373
- return join(metaDir, name, "SKILL.md");
374
- }
375
- const prompt = `You are helping a library maintainer scaffold Intent skills.
376
-
377
- Run the three meta skills below **one at a time, in order**. For each step:
378
- 1. Load the SKILL.md file specified
379
- 2. Follow its instructions completely
380
- 3. Present outputs to the maintainer for review
381
- 4. Do NOT proceed to the next step until the maintainer confirms
382
-
383
- ## Before you start
384
-
385
- Gather this context yourself (do not ask the maintainer — agents should never
386
- ask for information they can discover):
387
- 1. Read package.json for library name, repository URL, and homepage/docs URL
388
- 2. Detect if this is a monorepo (look for workspaces field, packages/ directory, lerna.json)
389
- 3. Use skills/ as the default skills root
390
- 4. For monorepos:
391
- - Domain map artifacts go at the REPO ROOT: _artifacts/
392
- - Skills go INSIDE EACH PACKAGE: packages/<pkg>/skills/
393
- - Identify which packages are client-facing (usually client SDKs and primary framework adapters)
394
-
395
- ---
396
-
397
- ## Step 1 — Domain Discovery
398
-
399
- Load and follow: ${metaSkillPath("domain-discovery")}
400
-
401
- This produces: domain_map.yaml and skill_spec.md in the artifacts directory.
402
- Domain discovery covers the WHOLE library (one domain map even for monorepos).
403
-
404
- **STOP. Review outputs with the maintainer before continuing.**
405
-
406
- ---
407
-
408
- ## Step 2 — Tree Generator
409
-
410
- Load and follow: ${metaSkillPath("tree-generator")}
411
-
412
- This produces: skill_tree.yaml in the artifacts directory.
413
- For monorepos, each skill entry should include a \`package\` field.
414
-
415
- **STOP. Review outputs with the maintainer before continuing.**
416
-
417
- ---
418
-
419
- ## Step 3 — Generate Skills
420
-
421
- Load and follow: ${metaSkillPath("generate-skill")}
422
-
423
- This produces: individual SKILL.md files.
424
- - Single-repo: skills/<domain>/<skill>/SKILL.md
425
- - Monorepo: packages/<pkg>/skills/<domain>/<skill>/SKILL.md
426
-
427
- ---
428
-
429
- ## After all skills are generated
430
-
431
- 1. Run \`intent validate\` in each package directory
432
- 2. Commit skills/ and artifacts
433
- 3. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
434
- 4. Ensure each package has \`@tanstack/intent\` as a devDependency
435
- 5. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
436
- 6. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
437
- `;
438
- console.log(prompt);
439
- }
440
-
441
- //#endregion
442
- //#region src/commands/setup-github-actions.ts
443
- async function runSetupGithubActionsCommand(root, metaDir) {
444
- const { runSetupGithubActions } = await import("./setup.mjs");
445
- runSetupGithubActions(root, metaDir);
446
- }
447
-
448
- //#endregion
449
- //#region src/commands/stale.ts
450
- async function runStaleCommand(targetDir, options, resolveStaleTargets$1) {
451
- if (options.githubReview) {
452
- await runGithubReview(targetDir, options, resolveStaleTargets$1);
453
- return;
454
- }
455
- const { reports, workflowAdvisories = [] } = await resolveStaleTargets$1(targetDir);
456
- if (options.json) {
457
- console.log(JSON.stringify(reports, null, 2));
458
- return;
459
- }
460
- for (const advisory of workflowAdvisories) console.log(advisory);
461
- if (workflowAdvisories.length > 0) console.log();
462
- if (reports.length === 0) {
463
- console.log("No intent-enabled packages found.");
464
- return;
465
- }
466
- for (const report of reports) {
467
- const driftLabel = report.versionDrift ? ` [${report.versionDrift} drift]` : "";
468
- const vLabel = report.skillVersion && report.currentVersion ? ` (${report.skillVersion} → ${report.currentVersion})` : "";
469
- console.log(`${report.library}${vLabel}${driftLabel}`);
470
- const stale = report.skills.filter((skill) => skill.needsReview);
471
- const signals = report.signals.filter((signal) => signal.needsReview);
472
- if (stale.length === 0 && signals.length === 0) console.log(" All skills up-to-date");
473
- else {
474
- for (const skill of stale) console.log(` ⚠ ${skill.name}: ${skill.reasons.join(", ")}`);
475
- for (const signal of signals) {
476
- const subject = signal.packageName ?? signal.packageRoot ?? signal.skill ?? signal.artifactPath ?? signal.subject ?? report.library;
477
- console.log(` ⚠ ${subject}: ${signal.reasons.join(", ")}`);
478
- }
479
- }
480
- console.log();
481
- }
482
- }
483
- async function runGithubReview(targetDir, options, resolveStaleTargets$1) {
484
- const { collectStaleReviewItems, createFailedStaleReviewItem, createWorkflowAdvisoryReviewItems, writeStaleReviewWorkflowFiles } = await import("./workflow-review-Dz_ofcYQ.mjs");
485
- const packageLabel = options.packageLabel ?? "workspace";
486
- try {
487
- const { reports, workflowAdvisories = [] } = await resolveStaleTargets$1(targetDir);
488
- const items = [...collectStaleReviewItems(reports), ...createWorkflowAdvisoryReviewItems(packageLabel, workflowAdvisories)];
489
- writeStaleReviewWorkflowFiles(items);
490
- if (items.length === 0) console.log("No stale skills or coverage gaps found.");
491
- else console.log(`Wrote ${items.length} intent skill review item(s).`);
492
- } catch (err) {
493
- writeStaleReviewWorkflowFiles([createFailedStaleReviewItem(packageLabel)]);
494
- const message = err instanceof Error ? err.message : String(err);
495
- console.log(`Intent stale check failed: ${message}`);
496
- console.log("Wrote a review PR body so maintainers can inspect the logs.");
497
- }
498
- }
499
-
500
- //#endregion
501
- //#region src/commands/validate.ts
502
- const agentSkillNamePattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
503
- function buildValidationFailure(errors, warnings) {
504
- const lines = [
505
- "",
506
- `❌ Validation failed with ${errors.length} error(s):`,
507
- ""
508
- ];
509
- for (const { file, message } of errors) lines.push(` ${file}: ${message}`);
510
- if (warnings.length > 0) {
511
- lines.push("", "⚠ Packaging warnings:");
512
- for (const warning of warnings) lines.push(` ${warning}`);
513
- }
514
- return lines.join("\n");
515
- }
516
- function collectPackagingWarnings(context) {
517
- if (!context.packageRoot || !context.targetPackageJsonPath) return [];
518
- const pkgJsonPath = context.targetPackageJsonPath;
519
- if (!existsSync(pkgJsonPath)) return [];
520
- let pkgJson;
521
- try {
522
- pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
523
- } catch (err) {
524
- return [`Could not parse package.json: ${err instanceof Error ? err.message : String(err)}`];
525
- }
526
- const warnings = [];
527
- if (!pkgJson.devDependencies?.["@tanstack/intent"]) warnings.push("@tanstack/intent is not in devDependencies");
528
- const keywords = pkgJson.keywords;
529
- if (!Array.isArray(keywords) || !keywords.includes("tanstack-intent")) warnings.push("Missing \"tanstack-intent\" in keywords array");
530
- const files = pkgJson.files;
531
- if (Array.isArray(files)) {
532
- if (!files.includes("skills")) warnings.push("\"skills\" is not in the \"files\" array — skills won't be published");
533
- if (!context.isMonorepo && !files.includes("!skills/_artifacts")) warnings.push("\"!skills/_artifacts\" is not in the \"files\" array — artifacts will be published unnecessarily");
534
- }
535
- return warnings;
536
- }
537
- function formatWarning({ file, message }) {
538
- return `${file}: ${message}`;
539
- }
540
- function isRecord(value) {
541
- return !!value && typeof value === "object" && !Array.isArray(value);
542
- }
543
- function collectAgentSkillSpecWarnings({ filePath, fm, rel }) {
544
- const warnings = [];
545
- if (typeof fm.name === "string") {
546
- if (fm.name.length > 64) warnings.push({
547
- file: rel,
548
- message: `Agent Skills spec warning: name exceeds 64 characters (${fm.name.length} chars)`
549
- });
550
- for (const segment of fm.name.split("/")) if (!agentSkillNamePattern.test(segment)) {
551
- warnings.push({
552
- file: rel,
553
- message: "Agent Skills spec warning: each name segment should use lowercase letters, numbers, and single hyphens only"
554
- });
555
- break;
556
- }
557
- const parentDir = basename(dirname(filePath));
558
- if (!fm.name.includes("/") && fm.name !== parentDir) warnings.push({
559
- file: rel,
560
- message: "Agent Skills spec warning: name should match the parent directory name"
561
- });
562
- }
563
- if (fm.license !== void 0 && (typeof fm.license !== "string" || fm.license.trim().length === 0)) warnings.push({
564
- file: rel,
565
- message: "Agent Skills spec warning: license should be a non-empty string"
566
- });
567
- if (fm.compatibility !== void 0) {
568
- if (typeof fm.compatibility !== "string" || fm.compatibility.trim().length === 0) warnings.push({
569
- file: rel,
570
- message: "Agent Skills spec warning: compatibility should be a non-empty string"
571
- });
572
- else if (fm.compatibility.length > 500) warnings.push({
573
- file: rel,
574
- message: `Agent Skills spec warning: compatibility exceeds 500 characters (${fm.compatibility.length} chars)`
575
- });
576
- }
577
- if (fm.metadata !== void 0) {
578
- if (!isRecord(fm.metadata)) warnings.push({
579
- file: rel,
580
- message: "Agent Skills spec warning: metadata should be a mapping"
581
- });
582
- else if (Object.values(fm.metadata).some((value) => typeof value !== "string")) warnings.push({
583
- file: rel,
584
- message: "Agent Skills spec warning: metadata values should be strings"
585
- });
586
- }
587
- if (fm["allowed-tools"] !== void 0 && typeof fm["allowed-tools"] !== "string") warnings.push({
588
- file: rel,
589
- message: "Agent Skills spec warning: allowed-tools should be a space-separated string"
590
- });
591
- return warnings;
592
- }
593
- async function runValidateCommand(dir, options = {}) {
594
- if (!options.githubSummary) {
595
- await runValidateCommandInternal(dir);
596
- return;
597
- }
598
- try {
599
- await runValidateCommandInternal(dir);
600
- writeGithubValidationSummary({ ok: true });
601
- } catch (err) {
602
- writeGithubValidationSummary({
603
- ok: false,
604
- message: validationErrorMessage(err)
605
- });
606
- throw err;
607
- }
608
- }
609
- async function runValidateCommandInternal(dir) {
610
- const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-dkVvY7D7.mjs")]);
611
- const context = resolveProjectContext({
612
- cwd: process.cwd(),
613
- targetPath: dir
614
- });
615
- const explicitDir = dir !== void 0;
616
- const skillsDirs = explicitDir ? [context.targetSkillsDir ?? resolve(process.cwd(), dir)] : collectDefaultSkillsDirs(context, findSkillFiles);
617
- if (explicitDir && !existsSync(skillsDirs[0])) fail(`Skills directory not found: ${skillsDirs[0]}`);
618
- const errors = [];
619
- const warnings = [];
620
- let validatedCount = 0;
621
- if (explicitDir && findSkillFiles(skillsDirs[0]).length === 0) fail("No SKILL.md files found");
622
- if (skillsDirs.length === 0) {
623
- console.log("No skills/ directory found — skipping validation.");
624
- return;
625
- }
626
- for (const skillsDir of skillsDirs) {
627
- const skillFiles = findSkillFiles(skillsDir);
628
- const validateContext = resolveProjectContext({
629
- cwd: process.cwd(),
630
- targetPath: skillsDir
631
- });
632
- for (const filePath of skillFiles) {
633
- const rel = relative(process.cwd(), filePath);
634
- const content = readFileSync(filePath, "utf8");
635
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)/);
636
- if (!match) {
637
- errors.push({
638
- file: rel,
639
- message: "Missing or invalid frontmatter"
640
- });
641
- continue;
642
- }
643
- if (!match[1]) {
644
- errors.push({
645
- file: rel,
646
- message: "Missing YAML frontmatter"
647
- });
648
- continue;
649
- }
650
- let fm;
651
- try {
652
- fm = parseYaml(match[1]);
653
- } catch (err) {
654
- const detail = err instanceof Error ? err.message : String(err);
655
- errors.push({
656
- file: rel,
657
- message: `Invalid YAML frontmatter: ${detail}`
658
- });
659
- continue;
660
- }
661
- if (!fm.name) errors.push({
662
- file: rel,
663
- message: "Missing required field: name"
664
- });
665
- if (!fm.description) errors.push({
666
- file: rel,
667
- message: "Missing required field: description"
668
- });
669
- if (typeof fm.name === "string") {
670
- const expectedPath = relative(skillsDir, filePath).replace(/[/\\]SKILL\.md$/, "").split(sep).join("/");
671
- if (fm.name !== expectedPath) errors.push({
672
- file: rel,
673
- message: `name "${fm.name}" does not match directory path "${expectedPath}"`
674
- });
675
- }
676
- if (typeof fm.description === "string" && fm.description.length > 1024) errors.push({
677
- file: rel,
678
- message: `Description exceeds 1024 character limit (${fm.description.length} chars)`
679
- });
680
- if (fm.type === "framework" && !Array.isArray(fm.requires)) errors.push({
681
- file: rel,
682
- message: "Framework skills must have a \"requires\" field"
683
- });
684
- warnings.push(...collectAgentSkillSpecWarnings({
685
- filePath,
686
- fm,
687
- rel
688
- }).map(formatWarning));
689
- const lineCount = content.split(/\r?\n/).length;
690
- if (lineCount > 500) errors.push({
691
- file: rel,
692
- message: `Exceeds 500 line limit (${lineCount} lines). Rewrite for conciseness: move API tables to references/, trim verbose examples, and remove content an agent already knows. Do not simply raise the limit.`
693
- });
694
- }
695
- const artifactsDir = join(skillsDir, "_artifacts");
696
- if (!validateContext.isMonorepo && existsSync(artifactsDir)) for (const fileName of [
697
- "domain_map.yaml",
698
- "skill_spec.md",
699
- "skill_tree.yaml"
700
- ]) {
701
- const artifactPath = join(artifactsDir, fileName);
702
- if (!existsSync(artifactPath)) {
703
- errors.push({
704
- file: relative(process.cwd(), artifactPath),
705
- message: "Missing required artifact"
706
- });
707
- continue;
708
- }
709
- const content = readFileSync(artifactPath, "utf8");
710
- if (content.trim().length === 0) {
711
- errors.push({
712
- file: relative(process.cwd(), artifactPath),
713
- message: "Artifact file is empty"
714
- });
715
- continue;
716
- }
717
- if (fileName.endsWith(".yaml")) try {
718
- parseYaml(content);
719
- } catch (err) {
720
- const detail = err instanceof Error ? err.message : String(err);
721
- errors.push({
722
- file: relative(process.cwd(), artifactPath),
723
- message: `Invalid YAML in artifact file: ${detail}`
724
- });
725
- }
726
- }
727
- validatedCount += skillFiles.length;
728
- warnings.push(...collectPackagingWarnings(validateContext));
729
- }
730
- if (errors.length > 0) fail(buildValidationFailure(errors, warnings));
731
- console.log(`✅ Validated ${validatedCount} skill files — all passed`);
732
- if (warnings.length > 0) console.log();
733
- printWarnings(warnings);
734
- }
735
- function validationErrorMessage(err) {
736
- if (isCliFailure(err)) return err.message;
737
- if (err instanceof Error) return err.message;
738
- return String(err);
739
- }
740
- function writeGithubValidationSummary({ message, ok }) {
741
- const summaryPath = process.env.GITHUB_STEP_SUMMARY;
742
- if (!summaryPath) return;
743
- const lines = ["### Intent skill validation", ""];
744
- if (ok) lines.push("Skill validation passed.", "");
745
- else lines.push("Skill validation failed.", "", "Why this failed:", "", "Intent validates SKILL.md frontmatter, skill names, required fields, size limits, framework requirements, and artifact files.", "The command output below contains the exact file-level reasons to fix.", "", "Run locally:", "", "```bash", "npx @tanstack/intent@latest validate", "```", "", "Command output:", "", "```text", message ?? "Unknown validation error.", "```", "");
746
- appendFileSync(summaryPath, lines.join("\n"));
747
- }
748
- function collectDefaultSkillsDirs(context, findSkillFiles) {
749
- const skillsDirs = [];
750
- const addSkillsDir = (skillsDir) => {
751
- if (existsSync(skillsDir) && findSkillFiles(skillsDir).length > 0) skillsDirs.push(skillsDir);
752
- };
753
- if (context.workspaceRoot && context.cwd === context.workspaceRoot) {
754
- addSkillsDir(join(context.workspaceRoot, "skills"));
755
- for (const packageDir of findWorkspacePackages(context.workspaceRoot)) addSkillsDir(join(packageDir, "skills"));
756
- return [...new Set(skillsDirs)].sort((a, b) => a.localeCompare(b));
757
- }
758
- addSkillsDir(context.targetSkillsDir ?? (context.packageRoot ? join(context.packageRoot, "skills") : resolve(context.cwd, "skills")));
759
- return skillsDirs;
760
- }
761
-
762
- //#endregion
763
7
  //#region src/cli.ts
764
8
  function createCli() {
765
9
  const cli = cac("intent");
766
10
  cli.usage("<command> [options]");
767
- cli.command("list", "Discover intent-enabled packages from the project or workspace").usage("list [--json] [--global] [--global-only]").option("--json", "Output JSON").option("--global", "Include global packages after project packages").option("--global-only", "List global packages only").example("list").example("list --json").example("list --global").action(async (options) => {
768
- await runListCommand(options, scanIntentsOrFail);
11
+ cli.command("list", "Discover intent-enabled packages from the project or workspace").usage("list [--json] [--debug] [--exclude <pattern>] [--global] [--global-only]").option("--json", "Output JSON").option("--debug", "Print discovery debug details to stderr").option("--exclude <pattern>", "Exclude package name glob").option("--global", "Include global packages after project packages").option("--global-only", "List global packages only").example("list").example("list --json").example("list --global").action(async (options) => {
12
+ const { runListCommand } = await import("./list-D6osUZl7.mjs");
13
+ await runListCommand(options);
769
14
  });
770
- cli.command("load [use]", "Load a compact skill use and print its SKILL.md").usage("load <use> [--path] [--json] [--global] [--global-only]").option("--path", "Print the resolved skill path instead of file content").option("--json", "Output JSON").option("--global", "Load from project packages, then global packages").option("--global-only", "Load from global packages only").example("load @tanstack/query#core").example("load @tanstack/query#core --path").action(async (use, options) => {
771
- await runLoadCommand(use, options, scanIntentsOrFail);
15
+ cli.command("load [use]", "Load a compact skill use and print its SKILL.md").usage("load <use> [--path] [--json] [--debug] [--exclude <pattern>] [--global] [--global-only]").option("--path", "Print the resolved skill path instead of file content").option("--json", "Output JSON").option("--debug", "Print resolution debug details to stderr").option("--exclude <pattern>", "Exclude package name glob").option("--global", "Load from project packages, then global packages").option("--global-only", "Load from global packages only").example("load @tanstack/query#core").example("load @tanstack/query#core --path").action(async (use, options) => {
16
+ const { runLoadCommand } = await import("./load-CzvLUFur.mjs");
17
+ await runLoadCommand(use, options);
772
18
  });
773
19
  cli.command("meta [name]", "List meta-skills, or print one by name").usage("meta [name]").example("meta").example("meta domain-discovery").action(async (name) => {
20
+ const [{ getMetaDir }, { runMetaCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./meta-CYV9EzM8.mjs")]);
774
21
  await runMetaCommand(name, getMetaDir());
775
22
  });
776
23
  cli.command("validate [dir]", "Validate skill files").usage("validate [dir] [--github-summary]").option("--github-summary", "Write a GitHub Actions step summary").example("validate").example("validate packages/query/skills").action(async (dir, options) => {
24
+ const { runValidateCommand } = await import("./validate-ugk2DZBd.mjs");
777
25
  await runValidateCommand(dir, options);
778
26
  });
779
27
  cli.command("install", "Create or update skill loading guidance in an agent config file").usage("install [--map] [--dry-run] [--print-prompt] [--global] [--global-only]").option("--map", "Write explicit skill-to-task mappings").option("--dry-run", "Print the generated block without writing").option("--print-prompt", "Print the legacy agent setup prompt instead of writing").option("--global", "Include global packages after project packages").option("--global-only", "Install mappings from global packages only").example("install").example("install --map").example("install --dry-run").example("install --print-prompt").example("install --global").action(async (options) => {
28
+ const [{ scanIntentsOrFail }, { runInstallCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./install-BAUG1FD8.mjs")]);
780
29
  await runInstallCommand(options, scanIntentsOrFail);
781
30
  });
782
- cli.command("scaffold", "Print maintainer scaffold prompt").usage("scaffold").action(() => {
31
+ cli.command("scaffold", "Print maintainer scaffold prompt").usage("scaffold").action(async () => {
32
+ const [{ getMetaDir }, { runScaffoldCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./scaffold-D2vwv9ls.mjs")]);
783
33
  runScaffoldCommand(getMetaDir());
784
34
  });
785
35
  cli.command("stale [dir]", "Check skills for staleness in the current package or workspace").usage("stale [dir] [--json] [--github-review]").option("--json", "Output JSON").option("--github-review", "Write GitHub Actions review PR files").option("--package-label <label>", "Fallback package label for review PRs").example("stale").example("stale packages/query").example("stale --json").action(async (targetDir, options) => {
36
+ const [{ resolveStaleTargets }, { runStaleCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./stale-flPZnWfI.mjs")]);
786
37
  await runStaleCommand(targetDir, options, resolveStaleTargets);
787
38
  });
788
39
  cli.command("edit-package-json", "Update package.json files so skills are published").usage("edit-package-json").action(async () => {
40
+ const { runEditPackageJsonCommand } = await import("./edit-package-json-CzWlMXOf.mjs");
789
41
  await runEditPackageJsonCommand(process.cwd());
790
42
  });
791
43
  cli.command("setup", "Copy Intent CI workflow templates into .github/workflows/").usage("setup").action(async () => {
44
+ const [{ getMetaDir }, { runSetupGithubActionsCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./setup-github-actions-emXSyGy3.mjs")]);
792
45
  await runSetupGithubActionsCommand(process.cwd(), getMetaDir());
793
46
  });
794
47
  cli.command("setup-github-actions", "Copy Intent CI workflow templates into .github/workflows/").usage("setup-github-actions").action(async () => {
48
+ const [{ getMetaDir }, { runSetupGithubActionsCommand }] = await Promise.all([import("./cli-support-CHEYZ9xj.mjs"), import("./setup-github-actions-emXSyGy3.mjs")]);
795
49
  await runSetupGithubActionsCommand(process.cwd(), getMetaDir());
796
50
  });
797
51
  cli.command("help [command]", "Display help for a command").action((commandName) => {