@tanstack/intent 0.0.12 → 0.0.14
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/README.md +26 -26
- package/dist/cli.mjs +30 -9
- package/dist/index.d.mts +13 -1
- package/dist/index.mjs +6 -6
- package/dist/intent-library.mjs +2 -2
- package/dist/{library-scanner-V9sTOhrb.mjs → library-scanner-B1tmOzwf.mjs} +3 -11
- package/dist/library-scanner.mjs +2 -2
- package/dist/scanner-CECGXgox.mjs +4 -0
- package/dist/{scanner-dIYdkHQ1.mjs → scanner-CY40iozO.mjs} +53 -15
- package/dist/{setup-BYOg-Ii-.mjs → setup-Nif1-nhS.mjs} +15 -1
- package/dist/setup.mjs +1 -1
- package/dist/staleness-C1h7RuZ9.mjs +4 -0
- package/dist/{staleness-lP6B0O4z.mjs → staleness-DJfMKH62.mjs} +1 -1
- package/dist/utils-CDJzAdjD.mjs +79 -0
- package/meta/feedback-collection/SKILL.md +32 -11
- package/package.json +1 -1
- package/dist/scanner-DQeiZRzp.mjs +0 -4
- package/dist/staleness-B5gUj7FR.mjs +0 -4
- package/dist/utils-DH3jY3CI.mjs +0 -39
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# @tanstack/intent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A CLI for library maintainers to generate, validate, and ship [Agent Skills](https://agentskills.io) alongside their npm packages.
|
|
4
4
|
|
|
5
5
|
## The problem
|
|
6
6
|
|
|
7
7
|
Your docs are good. Your types are solid. Your agent still gets it wrong.
|
|
8
8
|
|
|
9
|
-
Docs target humans who browse. Types check individual API calls but can't encode intent. Training data snapshots the ecosystem as it _was_, mixing versions
|
|
9
|
+
Docs target humans who browse. Types check individual API calls but can't encode intent. Training data snapshots the ecosystem as it _was_, mixing versions with no way to tell which applies. Once a breaking change ships, models develop a permanent split-brain — training data contains _both_ versions forever with no way to disambiguate.
|
|
10
10
|
|
|
11
11
|
The ecosystem already moves toward agent-readable knowledge — Cursor rules, CLAUDE.md files, skills directories. But delivery is stuck in copy-paste: hunt for a community-maintained rules file, paste it into your config, repeat for every tool. No versioning, no update path, no staleness signal.
|
|
12
12
|
|
|
13
|
-
## Skills:
|
|
13
|
+
## Skills: versioned knowledge in npm
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Skills are npm packages of knowledge — encoding how tools compose, which patterns fit which goals, and what to avoid. When a library ships skills using `@tanstack/intent`, that knowledge travels with the tool via `npm update` — not the model's training cutoff. Versioned knowledge the maintainer owns, updated when the package updates.
|
|
15
|
+
A skill is a short, versioned document that tells agents how to use a specific capability of your library — correct patterns, common mistakes, and when to apply them. Skills ship inside your npm package and travel with the tool via `npm update` — not the model's training cutoff, not community-maintained rules files, not prompt snippets in READMEs. Versioned knowledge the maintainer owns, updated when the package updates.
|
|
18
16
|
|
|
19
17
|
Each skill declares its source docs. When those docs change, the CLI flags the skill for review. One source of truth, one derived artifact that stays in sync.
|
|
20
18
|
|
|
19
|
+
The [Agent Skills spec](https://agentskills.io) is an open standard already adopted by VS Code, GitHub Copilot, OpenAI Codex, Cursor, Claude Code, Goose, Amp, and others.
|
|
20
|
+
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
23
|
### For library consumers
|
|
@@ -25,15 +25,15 @@ Each skill declares its source docs. When those docs change, the CLI flags the s
|
|
|
25
25
|
Set up skill-to-task mappings in your project's agent config files (CLAUDE.md, .cursorrules, etc.):
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npx @tanstack/intent install
|
|
28
|
+
npx @tanstack/intent@latest install
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
No per-library setup. No hunting for rules files. Install the package, run `intent install`, and the agent understands the tool. Update the package, and skills update too.
|
|
31
|
+
No per-library setup. No hunting for rules files. Install the package, run `npx @tanstack/intent@latest install`, and the agent understands the tool. Update the package, and skills update too.
|
|
32
32
|
|
|
33
33
|
List available skills from installed packages:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npx @tanstack/intent list
|
|
36
|
+
npx @tanstack/intent@latest list
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
### For library maintainers
|
|
@@ -41,47 +41,47 @@ npx @tanstack/intent list
|
|
|
41
41
|
Generate skills for your library by telling your AI coding agent to run:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
npx @tanstack/intent scaffold
|
|
44
|
+
npx @tanstack/intent@latest scaffold
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
This
|
|
47
|
+
This walks the agent through domain discovery, skill tree generation, and skill creation — one step at a time with your review at each stage.
|
|
48
48
|
|
|
49
49
|
Validate your skill files:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
npx @tanstack/intent validate
|
|
52
|
+
npx @tanstack/intent@latest validate
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Check for skills that have fallen behind their sources:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
-
npx @tanstack/intent stale
|
|
58
|
+
npx @tanstack/intent@latest stale
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Copy CI workflow templates into your repo so validation and staleness checks run on every push:
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
npx @tanstack/intent setup
|
|
64
|
+
npx @tanstack/intent@latest setup-github-actions
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
## Keeping skills current
|
|
68
68
|
|
|
69
|
-
The real risk with any derived artifact is staleness. `npx @tanstack/intent stale` flags skills whose source docs have changed, and CI templates catch drift before it ships.
|
|
69
|
+
The real risk with any derived artifact is staleness. `npx @tanstack/intent@latest stale` flags skills whose source docs have changed, and CI templates catch drift before it ships.
|
|
70
70
|
|
|
71
|
-
The feedback loop runs both directions. `npx @tanstack/intent feedback` lets users submit structured reports when a skill produces wrong output — which skill, which version, what broke. That context flows back to the maintainer, and the fix ships to everyone on the next `npm update`.
|
|
71
|
+
The feedback loop runs both directions. `npx @tanstack/intent@latest feedback` lets users submit structured reports when a skill produces wrong output — which skill, which version, what broke. That context flows back to the maintainer, and the fix ships to everyone on the next `npm update`. Every support interaction produces an artifact that prevents the same class of problem for all future users — not just the one who reported it.
|
|
72
72
|
|
|
73
73
|
## CLI Commands
|
|
74
74
|
|
|
75
|
-
| Command
|
|
76
|
-
|
|
|
77
|
-
| `npx @tanstack/intent install`
|
|
78
|
-
| `npx @tanstack/intent list [--json]`
|
|
79
|
-
| `npx @tanstack/intent meta`
|
|
80
|
-
| `npx @tanstack/intent scaffold`
|
|
81
|
-
| `npx @tanstack/intent validate [dir]`
|
|
82
|
-
| `npx @tanstack/intent setup`
|
|
83
|
-
| `npx @tanstack/intent stale [--json]`
|
|
84
|
-
| `npx @tanstack/intent feedback`
|
|
75
|
+
| Command | Description |
|
|
76
|
+
| -------------------------------------------------- | --------------------------------------------------- |
|
|
77
|
+
| `npx @tanstack/intent@latest install` | Set up skill-to-task mappings in agent config files |
|
|
78
|
+
| `npx @tanstack/intent@latest list [--json]` | Discover intent-enabled packages |
|
|
79
|
+
| `npx @tanstack/intent@latest meta` | List meta-skills for library maintainers |
|
|
80
|
+
| `npx @tanstack/intent@latest scaffold` | Print the guided skill generation prompt |
|
|
81
|
+
| `npx @tanstack/intent@latest validate [dir]` | Validate SKILL.md files |
|
|
82
|
+
| `npx @tanstack/intent@latest setup-github-actions` | Copy CI templates into your repo |
|
|
83
|
+
| `npx @tanstack/intent@latest stale [--json]` | Check skills for version drift |
|
|
84
|
+
| `npx @tanstack/intent@latest feedback` | Submit skill feedback |
|
|
85
85
|
|
|
86
86
|
## License
|
|
87
87
|
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { t as scanForIntents } from "./scanner-
|
|
2
|
+
import { r as parseFrontmatter, t as findSkillFiles } from "./utils-CDJzAdjD.mjs";
|
|
3
|
+
import { t as scanForIntents } from "./scanner-CY40iozO.mjs";
|
|
4
4
|
import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-D_XzuGnu.mjs";
|
|
5
5
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
6
6
|
import { dirname, join, relative, sep } from "node:path";
|
|
@@ -65,12 +65,33 @@ async function cmdList(args) {
|
|
|
65
65
|
for (const w of result.warnings) console.log(` ⚠ ${w}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
function cmdMeta() {
|
|
68
|
+
function cmdMeta(args) {
|
|
69
69
|
const metaDir = getMetaDir();
|
|
70
70
|
if (!existsSync(metaDir)) {
|
|
71
71
|
console.error("Meta-skills directory not found.");
|
|
72
72
|
process.exit(1);
|
|
73
73
|
}
|
|
74
|
+
if (args.length > 0) {
|
|
75
|
+
const name = args[0];
|
|
76
|
+
if (name.includes("..") || name.includes("/") || name.includes("\\")) {
|
|
77
|
+
console.error(`Invalid meta-skill name: "${name}"`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const skillFile = join(metaDir, name, "SKILL.md");
|
|
81
|
+
if (!existsSync(skillFile)) {
|
|
82
|
+
console.error(`Meta-skill "${name}" not found.`);
|
|
83
|
+
console.error(`Run \`npx @tanstack/intent meta\` to list available meta-skills.`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
console.log(readFileSync(skillFile, "utf8"));
|
|
88
|
+
} catch (err) {
|
|
89
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
+
console.error(`Failed to read meta-skill "${name}": ${msg}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
74
95
|
const entries = readdirSync(metaDir, { withFileTypes: true }).filter((e) => e.isDirectory()).filter((e) => existsSync(join(metaDir, e.name, "SKILL.md")));
|
|
75
96
|
if (entries.length === 0) {
|
|
76
97
|
console.log("No meta-skills found.");
|
|
@@ -290,8 +311,8 @@ This produces: individual SKILL.md files.
|
|
|
290
311
|
3. For each publishable package, run: \`npx @tanstack/intent add-library-bin\`
|
|
291
312
|
4. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
|
|
292
313
|
5. Ensure each package has \`@tanstack/intent\` as a devDependency
|
|
293
|
-
6. Create a \`
|
|
294
|
-
7. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent install\`"
|
|
314
|
+
6. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
|
|
315
|
+
7. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
|
|
295
316
|
`;
|
|
296
317
|
console.log(prompt);
|
|
297
318
|
}
|
|
@@ -299,7 +320,7 @@ const USAGE = `TanStack Intent CLI
|
|
|
299
320
|
|
|
300
321
|
Usage:
|
|
301
322
|
intent list [--json] Discover intent-enabled packages
|
|
302
|
-
intent meta
|
|
323
|
+
intent meta [name] List meta-skills, or print one by name
|
|
303
324
|
intent validate [<dir>] Validate skill files (default: skills/)
|
|
304
325
|
intent install Print a skill that guides your coding agent to set up skill-to-task mappings
|
|
305
326
|
intent scaffold Print maintainer scaffold prompt
|
|
@@ -314,7 +335,7 @@ switch (command) {
|
|
|
314
335
|
await cmdList(commandArgs);
|
|
315
336
|
break;
|
|
316
337
|
case "meta":
|
|
317
|
-
cmdMeta();
|
|
338
|
+
cmdMeta(commandArgs);
|
|
318
339
|
break;
|
|
319
340
|
case "validate":
|
|
320
341
|
cmdValidate(commandArgs);
|
|
@@ -371,8 +392,8 @@ skills:
|
|
|
371
392
|
cmdScaffold();
|
|
372
393
|
break;
|
|
373
394
|
case "stale": {
|
|
374
|
-
const { checkStaleness } = await import("./staleness-
|
|
375
|
-
const { scanForIntents: scanStale } = await import("./scanner-
|
|
395
|
+
const { checkStaleness } = await import("./staleness-C1h7RuZ9.mjs");
|
|
396
|
+
const { scanForIntents: scanStale } = await import("./scanner-CECGXgox.mjs");
|
|
376
397
|
let staleResult;
|
|
377
398
|
try {
|
|
378
399
|
staleResult = await scanStale();
|
package/dist/index.d.mts
CHANGED
|
@@ -39,9 +39,21 @@ declare function submitMetaFeedback(payload: MetaFeedbackPayload, opts: {
|
|
|
39
39
|
* Recursively find all SKILL.md files under a directory.
|
|
40
40
|
*/
|
|
41
41
|
declare function findSkillFiles(dir: string): string[];
|
|
42
|
+
/**
|
|
43
|
+
* Read dependencies and peerDependencies (and optionally devDependencies) from
|
|
44
|
+
* a parsed package.json object.
|
|
45
|
+
*/
|
|
46
|
+
declare function getDeps(pkgJson: Record<string, unknown>, includeDevDeps?: boolean): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the directory of a dependency by name. First checks the top-level
|
|
49
|
+
* node_modules (hoisted layout — npm, yarn, bun), then resolves through the
|
|
50
|
+
* parent package's real path to handle pnpm's virtual store layout where
|
|
51
|
+
* transitive deps are siblings in the .pnpm virtual store node_modules.
|
|
52
|
+
*/
|
|
53
|
+
declare function resolveDepDir(depName: string, parentDir: string, parentName: string, nodeModulesDir: string): string | null;
|
|
42
54
|
/**
|
|
43
55
|
* Parse YAML frontmatter from a file. Returns null if no frontmatter or on error.
|
|
44
56
|
*/
|
|
45
57
|
declare function parseFrontmatter(filePath: string): Record<string, unknown> | null;
|
|
46
58
|
//#endregion
|
|
47
|
-
export { type AddLibraryBinResult, type AgentName, type EditPackageJsonResult, type FeedbackPayload, type IntentConfig, type IntentPackage, type IntentProjectConfig, type MetaFeedbackPayload, type MetaSkillName, type ScanResult, type SetupGithubActionsResult, type SkillEntry, type SkillStaleness, type StalenessReport, checkStaleness, containsSecrets, findSkillFiles, hasGhCli, metaToMarkdown, parseFrontmatter, resolveFrequency, runAddLibraryBin, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
|
|
59
|
+
export { type AddLibraryBinResult, type AgentName, type EditPackageJsonResult, type FeedbackPayload, type IntentConfig, type IntentPackage, type IntentProjectConfig, type MetaFeedbackPayload, type MetaSkillName, type ScanResult, type SetupGithubActionsResult, type SkillEntry, type SkillStaleness, type StalenessReport, checkStaleness, containsSecrets, findSkillFiles, getDeps, hasGhCli, metaToMarkdown, parseFrontmatter, resolveDepDir, resolveFrequency, runAddLibraryBin, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as parseFrontmatter, t as findSkillFiles } from "./utils-
|
|
2
|
-
import { t as scanForIntents } from "./scanner-
|
|
3
|
-
import { t as checkStaleness } from "./staleness-
|
|
4
|
-
import { n as runEditPackageJson, r as runSetupGithubActions, t as runAddLibraryBin } from "./setup-
|
|
1
|
+
import { i as resolveDepDir, n as getDeps, r as parseFrontmatter, t as findSkillFiles } from "./utils-CDJzAdjD.mjs";
|
|
2
|
+
import { t as scanForIntents } from "./scanner-CY40iozO.mjs";
|
|
3
|
+
import { t as checkStaleness } from "./staleness-DJfMKH62.mjs";
|
|
4
|
+
import { n as runEditPackageJson, r as runSetupGithubActions, t as runAddLibraryBin } from "./setup-Nif1-nhS.mjs";
|
|
5
5
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { execFileSync, execSync } from "node:child_process";
|
|
@@ -212,7 +212,7 @@ function submitMetaFeedback(payload, opts) {
|
|
|
212
212
|
"--title",
|
|
213
213
|
`Meta-Skill Feedback: ${payload.metaSkill} (${payload.userRating})`,
|
|
214
214
|
"--label",
|
|
215
|
-
`
|
|
215
|
+
`skill:${payload.metaSkill}`,
|
|
216
216
|
"--body",
|
|
217
217
|
"-"
|
|
218
218
|
], {
|
|
@@ -246,4 +246,4 @@ function submitMetaFeedback(payload, opts) {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
//#endregion
|
|
249
|
-
export { checkStaleness, containsSecrets, findSkillFiles, hasGhCli, metaToMarkdown, parseFrontmatter, resolveFrequency, runAddLibraryBin, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
|
|
249
|
+
export { checkStaleness, containsSecrets, findSkillFiles, getDeps, hasGhCli, metaToMarkdown, parseFrontmatter, resolveDepDir, resolveFrequency, runAddLibraryBin, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
|
package/dist/intent-library.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./utils-
|
|
2
|
+
import "./utils-CDJzAdjD.mjs";
|
|
3
3
|
import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-D_XzuGnu.mjs";
|
|
4
|
-
import { t as scanLibrary } from "./library-scanner-
|
|
4
|
+
import { t as scanLibrary } from "./library-scanner-B1tmOzwf.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/intent-library.ts
|
|
7
7
|
async function cmdList() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as parseFrontmatter } from "./utils-
|
|
1
|
+
import { i as resolveDepDir, n as getDeps, r as parseFrontmatter } from "./utils-CDJzAdjD.mjs";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, sep } from "node:path";
|
|
4
4
|
|
|
@@ -24,14 +24,6 @@ function hasIntentBin(pkg) {
|
|
|
24
24
|
if (!bin || typeof bin !== "object") return false;
|
|
25
25
|
return "intent" in bin;
|
|
26
26
|
}
|
|
27
|
-
function getDeps(pkg) {
|
|
28
|
-
const seen = /* @__PURE__ */ new Set();
|
|
29
|
-
for (const field of ["dependencies", "peerDependencies"]) {
|
|
30
|
-
const d = pkg[field];
|
|
31
|
-
if (d && typeof d === "object") for (const name of Object.keys(d)) seen.add(name);
|
|
32
|
-
}
|
|
33
|
-
return [...seen];
|
|
34
|
-
}
|
|
35
27
|
function discoverSkills(skillsDir) {
|
|
36
28
|
const skills = [];
|
|
37
29
|
function walk(dir) {
|
|
@@ -97,8 +89,8 @@ async function scanLibrary(scriptPath, projectRoot) {
|
|
|
97
89
|
skills: existsSync(skillsDir) ? discoverSkills(skillsDir) : []
|
|
98
90
|
});
|
|
99
91
|
for (const depName of getDeps(pkg)) {
|
|
100
|
-
const depDir =
|
|
101
|
-
if (!
|
|
92
|
+
const depDir = resolveDepDir(depName, dir, name, nodeModulesDir);
|
|
93
|
+
if (!depDir) continue;
|
|
102
94
|
const depPkg = readPkgJson(depDir);
|
|
103
95
|
if (depPkg && hasIntentBin(depPkg)) processPackage(depName, depDir);
|
|
104
96
|
}
|
package/dist/library-scanner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as parseFrontmatter } from "./utils-
|
|
1
|
+
import { i as resolveDepDir, n as getDeps, r as parseFrontmatter } from "./utils-CDJzAdjD.mjs";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { join, relative, sep } from "node:path";
|
|
4
4
|
|
|
@@ -143,31 +143,69 @@ async function scanForIntents(root) {
|
|
|
143
143
|
}
|
|
144
144
|
} else if (!entry.name.startsWith(".")) packageDirs.push({ dirPath });
|
|
145
145
|
}
|
|
146
|
-
|
|
146
|
+
const foundNames = /* @__PURE__ */ new Set();
|
|
147
|
+
/**
|
|
148
|
+
* Try to register a package with a skills/ directory. Reads its
|
|
149
|
+
* package.json, validates intent config, discovers skills, and pushes
|
|
150
|
+
* to `packages`. Returns true if the package was registered.
|
|
151
|
+
*/
|
|
152
|
+
function tryRegister(dirPath, fallbackName) {
|
|
147
153
|
const skillsDir = join(dirPath, "skills");
|
|
148
|
-
if (!existsSync(skillsDir))
|
|
149
|
-
const pkgJsonPath = join(dirPath, "package.json");
|
|
154
|
+
if (!existsSync(skillsDir)) return false;
|
|
150
155
|
let pkgJson;
|
|
151
156
|
try {
|
|
152
|
-
pkgJson = JSON.parse(readFileSync(
|
|
157
|
+
pkgJson = JSON.parse(readFileSync(join(dirPath, "package.json"), "utf8"));
|
|
153
158
|
} catch {
|
|
154
159
|
warnings.push(`Could not read package.json for ${dirPath}`);
|
|
155
|
-
|
|
160
|
+
return false;
|
|
156
161
|
}
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
const intent = validateIntentField(
|
|
162
|
+
const name = typeof pkgJson.name === "string" ? pkgJson.name : fallbackName;
|
|
163
|
+
if (foundNames.has(name)) return false;
|
|
164
|
+
const intent = validateIntentField(name, pkgJson.intent) ?? deriveIntentConfig(pkgJson);
|
|
160
165
|
if (!intent) {
|
|
161
|
-
warnings.push(`${
|
|
162
|
-
|
|
166
|
+
warnings.push(`${name} has a skills/ directory but could not determine repo/docs from package.json (add a "repository" field or explicit "intent" config)`);
|
|
167
|
+
return false;
|
|
163
168
|
}
|
|
164
|
-
const skills = discoverSkills(skillsDir, pkgName);
|
|
165
169
|
packages.push({
|
|
166
|
-
name
|
|
167
|
-
version:
|
|
170
|
+
name,
|
|
171
|
+
version: typeof pkgJson.version === "string" ? pkgJson.version : "0.0.0",
|
|
168
172
|
intent,
|
|
169
|
-
skills
|
|
173
|
+
skills: discoverSkills(skillsDir, name)
|
|
170
174
|
});
|
|
175
|
+
foundNames.add(name);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
for (const { dirPath } of packageDirs) tryRegister(dirPath, "unknown");
|
|
179
|
+
const walkVisited = /* @__PURE__ */ new Set();
|
|
180
|
+
function walkDeps(pkgDir, pkgName) {
|
|
181
|
+
if (walkVisited.has(pkgName)) return;
|
|
182
|
+
walkVisited.add(pkgName);
|
|
183
|
+
let pkgJson;
|
|
184
|
+
try {
|
|
185
|
+
pkgJson = JSON.parse(readFileSync(join(pkgDir, "package.json"), "utf8"));
|
|
186
|
+
} catch {
|
|
187
|
+
warnings.push(`Could not read package.json for ${pkgName} (skipping dependency walk)`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
for (const depName of getDeps(pkgJson)) {
|
|
191
|
+
if (foundNames.has(depName) || walkVisited.has(depName)) continue;
|
|
192
|
+
const depDir = resolveDepDir(depName, pkgDir, pkgName, nodeModulesDir);
|
|
193
|
+
if (!depDir) continue;
|
|
194
|
+
tryRegister(depDir, depName);
|
|
195
|
+
walkDeps(depDir, depName);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
for (const pkg of [...packages]) walkDeps(join(nodeModulesDir, pkg.name), pkg.name);
|
|
199
|
+
let projectPkg = null;
|
|
200
|
+
try {
|
|
201
|
+
projectPkg = JSON.parse(readFileSync(join(projectRoot, "package.json"), "utf8"));
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (!(err && typeof err === "object" && "code" in err && err.code === "ENOENT")) warnings.push(`Could not read project package.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
204
|
+
}
|
|
205
|
+
if (projectPkg) for (const depName of getDeps(projectPkg, true)) {
|
|
206
|
+
if (walkVisited.has(depName)) continue;
|
|
207
|
+
const depDir = join(nodeModulesDir, depName);
|
|
208
|
+
if (existsSync(join(depDir, "package.json"))) walkDeps(depDir, depName);
|
|
171
209
|
}
|
|
172
210
|
return {
|
|
173
211
|
packageManager,
|
|
@@ -55,7 +55,21 @@ function getShimContent(ext) {
|
|
|
55
55
|
// Exposes the intent end-user CLI for consumers of this library.
|
|
56
56
|
// Commit this file, then add to your package.json:
|
|
57
57
|
// "bin": { "intent": "./bin/intent.${ext}" }
|
|
58
|
-
|
|
58
|
+
try {
|
|
59
|
+
await import('@tanstack/intent/intent-library')
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND') {
|
|
62
|
+
console.error('@tanstack/intent is not installed.')
|
|
63
|
+
console.error('')
|
|
64
|
+
console.error('Install it as a dev dependency:')
|
|
65
|
+
console.error(' npm add -D @tanstack/intent')
|
|
66
|
+
console.error('')
|
|
67
|
+
console.error('Or run directly:')
|
|
68
|
+
console.error(' npx @tanstack/intent@latest list')
|
|
69
|
+
process.exit(1)
|
|
70
|
+
}
|
|
71
|
+
throw e
|
|
72
|
+
}
|
|
59
73
|
`;
|
|
60
74
|
}
|
|
61
75
|
function detectShimExtension(root) {
|
package/dist/setup.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as runEditPackageJson, r as runSetupGithubActions, t as runAddLibraryBin } from "./setup-
|
|
1
|
+
import { n as runEditPackageJson, r as runSetupGithubActions, t as runAddLibraryBin } from "./setup-Nif1-nhS.mjs";
|
|
2
2
|
|
|
3
3
|
export { runAddLibraryBin, runEditPackageJson, runSetupGithubActions };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
|
|
5
|
+
//#region src/utils.ts
|
|
6
|
+
/**
|
|
7
|
+
* Recursively find all SKILL.md files under a directory.
|
|
8
|
+
*/
|
|
9
|
+
function findSkillFiles(dir) {
|
|
10
|
+
const files = [];
|
|
11
|
+
if (!existsSync(dir)) return files;
|
|
12
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
13
|
+
const fullPath = join(dir, entry.name);
|
|
14
|
+
if (entry.isDirectory()) files.push(...findSkillFiles(fullPath));
|
|
15
|
+
else if (entry.name === "SKILL.md") files.push(fullPath);
|
|
16
|
+
}
|
|
17
|
+
return files;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read dependencies and peerDependencies (and optionally devDependencies) from
|
|
21
|
+
* a parsed package.json object.
|
|
22
|
+
*/
|
|
23
|
+
function getDeps(pkgJson, includeDevDeps = false) {
|
|
24
|
+
const deps = /* @__PURE__ */ new Set();
|
|
25
|
+
const fields = includeDevDeps ? [
|
|
26
|
+
"dependencies",
|
|
27
|
+
"devDependencies",
|
|
28
|
+
"peerDependencies"
|
|
29
|
+
] : ["dependencies", "peerDependencies"];
|
|
30
|
+
for (const field of fields) {
|
|
31
|
+
const d = pkgJson[field];
|
|
32
|
+
if (d && typeof d === "object") for (const name of Object.keys(d)) deps.add(name);
|
|
33
|
+
}
|
|
34
|
+
return [...deps];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the directory of a dependency by name. First checks the top-level
|
|
38
|
+
* node_modules (hoisted layout — npm, yarn, bun), then resolves through the
|
|
39
|
+
* parent package's real path to handle pnpm's virtual store layout where
|
|
40
|
+
* transitive deps are siblings in the .pnpm virtual store node_modules.
|
|
41
|
+
*/
|
|
42
|
+
function resolveDepDir(depName, parentDir, parentName, nodeModulesDir) {
|
|
43
|
+
if (!parentName) return null;
|
|
44
|
+
const topLevel = join(nodeModulesDir, depName);
|
|
45
|
+
if (existsSync(join(topLevel, "package.json"))) return topLevel;
|
|
46
|
+
try {
|
|
47
|
+
const realParent = realpathSync(parentDir);
|
|
48
|
+
const segments = parentName.split("/").length;
|
|
49
|
+
let nmDir = realParent;
|
|
50
|
+
for (let i = 0; i < segments; i++) nmDir = dirname(nmDir);
|
|
51
|
+
const nested = join(nmDir, depName);
|
|
52
|
+
if (existsSync(join(nested, "package.json"))) return nested;
|
|
53
|
+
} catch (err) {
|
|
54
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
|
|
55
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") console.warn(`Warning: could not resolve ${depName} from ${parentDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse YAML frontmatter from a file. Returns null if no frontmatter or on error.
|
|
61
|
+
*/
|
|
62
|
+
function parseFrontmatter(filePath) {
|
|
63
|
+
let content;
|
|
64
|
+
try {
|
|
65
|
+
content = readFileSync(filePath, "utf8");
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
70
|
+
if (!match?.[1]) return null;
|
|
71
|
+
try {
|
|
72
|
+
return parse(match[1]);
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { resolveDepDir as i, getDeps as n, parseFrontmatter as r, findSkillFiles as t };
|
|
@@ -29,7 +29,17 @@ can be improved.
|
|
|
29
29
|
|
|
30
30
|
Review your own session transcript. No human interaction needed yet.
|
|
31
31
|
|
|
32
|
-
### 1a:
|
|
32
|
+
### 1a: Skills inventory
|
|
33
|
+
|
|
34
|
+
Before analyzing gaps and errors, inventory all skills that were available
|
|
35
|
+
during the session:
|
|
36
|
+
|
|
37
|
+
- **Loaded and used:** Skills you read and actively followed.
|
|
38
|
+
- **Available but not loaded:** Skills that were installed (discoverable via
|
|
39
|
+
`intent list`) but you never read. This is important — many issues stem from
|
|
40
|
+
the agent not loading the right skill, not from the skill itself being wrong.
|
|
41
|
+
|
|
42
|
+
### 1b: Gap detection
|
|
33
43
|
|
|
34
44
|
Identify moments where the skill was silent and you had to bridge the gap
|
|
35
45
|
yourself — via code reading, search, trial-and-error, or general knowledge.
|
|
@@ -40,7 +50,7 @@ For each gap, note:
|
|
|
40
50
|
- What the skill should have told you
|
|
41
51
|
- How you solved it (code reading, web search, guessing)
|
|
42
52
|
|
|
43
|
-
###
|
|
53
|
+
### 1c: Error/correction tracking
|
|
44
54
|
|
|
45
55
|
Identify moments where the skill prescribed an approach that produced an error.
|
|
46
56
|
|
|
@@ -50,7 +60,7 @@ For each error, note:
|
|
|
50
60
|
- The error or incorrect behavior that resulted
|
|
51
61
|
- The fix you applied
|
|
52
62
|
|
|
53
|
-
###
|
|
63
|
+
### 1d: Human intervention events
|
|
54
64
|
|
|
55
65
|
Identify moments where the human clarified, corrected, or overrode your approach.
|
|
56
66
|
|
|
@@ -60,7 +70,7 @@ For each intervention, note:
|
|
|
60
70
|
- What the human said or changed
|
|
61
71
|
- Whether the skill could have prevented this
|
|
62
72
|
|
|
63
|
-
###
|
|
73
|
+
### 1e: Step duration anomalies
|
|
64
74
|
|
|
65
75
|
Identify steps that consumed disproportionate effort compared to their apparent
|
|
66
76
|
complexity. These signal that the skill should provide a template, snippet, or
|
|
@@ -107,21 +117,31 @@ referenced.
|
|
|
107
117
|
|
|
108
118
|
[one-sentence summary of what the human asked you to do]
|
|
109
119
|
|
|
120
|
+
## Skills Inventory
|
|
121
|
+
|
|
122
|
+
**Loaded and used:**
|
|
123
|
+
|
|
124
|
+
- [list each skill the agent read and actively followed during the session]
|
|
125
|
+
|
|
126
|
+
**Available but not loaded:**
|
|
127
|
+
|
|
128
|
+
- [list skills that were installed/available but the agent never read]
|
|
129
|
+
|
|
110
130
|
## What Worked
|
|
111
131
|
|
|
112
132
|
[patterns/instructions from the skill that were accurate and helpful]
|
|
113
133
|
|
|
114
134
|
## What Failed
|
|
115
135
|
|
|
116
|
-
[from
|
|
136
|
+
[from 1c — skill instructions that produced errors]
|
|
117
137
|
|
|
118
138
|
## Missing
|
|
119
139
|
|
|
120
|
-
[from
|
|
140
|
+
[from 1b — gaps where the skill should have covered]
|
|
121
141
|
|
|
122
142
|
## Self-Corrections
|
|
123
143
|
|
|
124
|
-
[from
|
|
144
|
+
[from 1c fixes + 1d human interventions, combined]
|
|
125
145
|
|
|
126
146
|
## User Comments
|
|
127
147
|
|
|
@@ -136,10 +156,11 @@ referenced.
|
|
|
136
156
|
| Package | The npm package the skill lives in (e.g. `@tanstack/query-intent`) |
|
|
137
157
|
| Skill version | Frontmatter `metadata.version` or `library_version` |
|
|
138
158
|
| Task | Summarize the human's original request in one sentence |
|
|
159
|
+
| Skills Inventory | Which skills were loaded vs. available but not loaded (see below) |
|
|
139
160
|
| What Worked | List skill sections/patterns that were correct and useful |
|
|
140
|
-
| What Failed | From
|
|
141
|
-
| Missing | From
|
|
142
|
-
| Self-Corrections | From
|
|
161
|
+
| What Failed | From 1c — skill instructions that produced errors |
|
|
162
|
+
| Missing | From 1b — gaps where the skill was silent |
|
|
163
|
+
| Self-Corrections | From 1c fixes + 1d human interventions, combined |
|
|
143
164
|
| Rating | From Phase 2 sentiment analysis or explicit rating |
|
|
144
165
|
| User Comments | From Phase 2 answers, keep brief |
|
|
145
166
|
|
|
@@ -177,7 +198,7 @@ not contain project-specific details. Before submission:
|
|
|
177
198
|
Submit directly as a GitHub issue:
|
|
178
199
|
|
|
179
200
|
```bash
|
|
180
|
-
gh issue create --repo [owner/repo] --title "Skill Feedback: [skill-name] ([rating])" --label "
|
|
201
|
+
gh issue create --repo [owner/repo] --title "Skill Feedback: [skill-name] ([rating])" --label "skill:[skill-name]" --body-file intent-feedback.md
|
|
181
202
|
```
|
|
182
203
|
|
|
183
204
|
If the label doesn't exist, omit the `--label` flag — don't let a missing
|
package/package.json
CHANGED
package/dist/utils-DH3jY3CI.mjs
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { parse } from "yaml";
|
|
4
|
-
|
|
5
|
-
//#region src/utils.ts
|
|
6
|
-
/**
|
|
7
|
-
* Recursively find all SKILL.md files under a directory.
|
|
8
|
-
*/
|
|
9
|
-
function findSkillFiles(dir) {
|
|
10
|
-
const files = [];
|
|
11
|
-
if (!existsSync(dir)) return files;
|
|
12
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
13
|
-
const fullPath = join(dir, entry.name);
|
|
14
|
-
if (entry.isDirectory()) files.push(...findSkillFiles(fullPath));
|
|
15
|
-
else if (entry.name === "SKILL.md") files.push(fullPath);
|
|
16
|
-
}
|
|
17
|
-
return files;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Parse YAML frontmatter from a file. Returns null if no frontmatter or on error.
|
|
21
|
-
*/
|
|
22
|
-
function parseFrontmatter(filePath) {
|
|
23
|
-
let content;
|
|
24
|
-
try {
|
|
25
|
-
content = readFileSync(filePath, "utf8");
|
|
26
|
-
} catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
30
|
-
if (!match?.[1]) return null;
|
|
31
|
-
try {
|
|
32
|
-
return parse(match[1]);
|
|
33
|
-
} catch {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
//#endregion
|
|
39
|
-
export { parseFrontmatter as n, findSkillFiles as t };
|