@tanstack/intent 0.0.5 → 0.0.6
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/dist/cli.mjs +46 -46
- package/dist/{feedback-DKreHfB1.mjs → feedback-BTSaBAS_.mjs} +2 -3
- package/dist/{feedback-FIUBOL0g.mjs → feedback-PR8JNBfM.mjs} +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +6 -6
- package/dist/{init-DEzzXm9j.mjs → init-BU1ZnUbK.mjs} +1 -1
- package/dist/{init-DNxmjQfU.mjs → init-DUiDMMrN.mjs} +2 -0
- package/dist/intent-library.mjs +7 -2
- package/dist/{library-scanner-BrznE00j.mjs → library-scanner-D0aP7is_.mjs} +5 -2
- package/dist/library-scanner.d.mts +1 -1
- package/dist/library-scanner.mjs +2 -2
- package/dist/scanner-DkShtCWX.mjs +4 -0
- package/dist/{scanner-CpsJAHXT.mjs → scanner-OmHt14bs.mjs} +41 -8
- package/dist/{setup-CNGz26qL.mjs → setup-BvrZZLsA.mjs} +3 -12
- package/dist/{setup-N5dttGp_.d.mts → setup-D2Bwubpw.d.mts} +0 -1
- package/dist/setup.d.mts +1 -1
- package/dist/setup.mjs +1 -1
- package/dist/staleness-B5gUj7FR.mjs +4 -0
- package/dist/{staleness-CnomT9Hm.mjs → staleness-lP6B0O4z.mjs} +1 -1
- package/dist/{types-kbQfN_is.d.mts → types-B20LP96b.d.mts} +1 -1
- package/dist/{utils-DjkEPBxu.mjs → utils-DH3jY3CI.mjs} +1 -1
- package/meta/domain-discovery/SKILL.md +50 -2
- package/meta/generate-skill/SKILL.md +9 -0
- package/meta/tree-generator/SKILL.md +7 -1
- package/package.json +1 -1
- package/dist/scanner-BuWPDJ4P.mjs +0 -4
- package/dist/staleness-DyhsrqQ5.mjs +0 -4
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as parseFrontmatter, t as findSkillFiles } from "./utils-
|
|
3
|
-
import { t as scanForIntents } from "./scanner-
|
|
2
|
+
import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DH3jY3CI.mjs";
|
|
3
|
+
import { t as scanForIntents } from "./scanner-OmHt14bs.mjs";
|
|
4
4
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
5
|
import { dirname, join, relative, sep } from "node:path";
|
|
6
6
|
import { parse } from "yaml";
|
|
7
|
-
import { spawnSync } from "node:child_process";
|
|
8
|
-
import { release } from "node:os";
|
|
9
7
|
import { fileURLToPath } from "node:url";
|
|
10
8
|
|
|
11
9
|
//#region src/cli.ts
|
|
@@ -106,6 +104,11 @@ async function cmdList(args) {
|
|
|
106
104
|
});
|
|
107
105
|
console.log();
|
|
108
106
|
}
|
|
107
|
+
console.log(`Feedback:`);
|
|
108
|
+
console.log(` After completing your task, collect feedback on skill usage.`);
|
|
109
|
+
console.log(` Instructions: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md`);
|
|
110
|
+
console.log(` Submit: npx intent feedback --submit --file intent-feedback.json`);
|
|
111
|
+
console.log();
|
|
109
112
|
if (result.warnings.length > 0) {
|
|
110
113
|
console.log(`Warnings:`);
|
|
111
114
|
for (const w of result.warnings) console.log(` ⚠ ${w}`);
|
|
@@ -196,7 +199,7 @@ function cmdValidate(args) {
|
|
|
196
199
|
const lineCount = content.split(/\r?\n/).length;
|
|
197
200
|
if (lineCount > 500) errors.push({
|
|
198
201
|
file: rel,
|
|
199
|
-
message: `Exceeds 500 line limit (${lineCount} lines)
|
|
202
|
+
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.`
|
|
200
203
|
});
|
|
201
204
|
}
|
|
202
205
|
const artifactsDir = join(skillsDir, "_artifacts");
|
|
@@ -238,40 +241,42 @@ function cmdValidate(args) {
|
|
|
238
241
|
console.log(`✅ Validated ${skillFiles.length} skill files — all passed`);
|
|
239
242
|
}
|
|
240
243
|
function cmdScaffold() {
|
|
241
|
-
|
|
242
|
-
const platform = process.platform;
|
|
243
|
-
const isWsl = platform === "linux" && (Boolean(process.env.WSL_DISTRO_NAME) || Boolean(process.env.WSL_INTEROP) || release().toLowerCase().includes("microsoft"));
|
|
244
|
-
const tryCommand = (command$1, args = []) => {
|
|
245
|
-
return spawnSync(command$1, args, { input: text }).status === 0;
|
|
246
|
-
};
|
|
247
|
-
if (platform === "darwin") return tryCommand("pbcopy");
|
|
248
|
-
if (platform === "win32") return tryCommand("clip");
|
|
249
|
-
if (isWsl) return tryCommand("clip.exe");
|
|
250
|
-
return tryCommand("wl-copy") || tryCommand("xclip", ["-selection", "clipboard"]) || tryCommand("xsel", ["--clipboard", "--input"]);
|
|
251
|
-
}
|
|
252
|
-
const prompt = `You are an AI assistant helping a library maintainer scaffold Intent skills.
|
|
244
|
+
console.log(`You are an AI assistant helping a library maintainer scaffold Intent skills.
|
|
253
245
|
You MUST use the Intent meta skills in this exact order and follow their output requirements.
|
|
254
246
|
|
|
255
|
-
Before you start, ask the maintainer
|
|
256
|
-
|
|
257
|
-
|
|
247
|
+
Before you start, ask the maintainer:
|
|
248
|
+
1. Skills root path (default: skills/). If custom, replace "skills/" in all paths below.
|
|
249
|
+
2. Is this a monorepo? If yes, you need the following layout:
|
|
250
|
+
- Domain map artifacts live at the REPO ROOT: _artifacts/domain_map.yaml, _artifacts/skill_spec.md, _artifacts/skill_tree.yaml
|
|
251
|
+
- Skills live INSIDE EACH PACKAGE: packages/<pkg>/skills/<domain>/<skill>/SKILL.md
|
|
252
|
+
- Each publishable package needs:
|
|
253
|
+
a. @tanstack/intent as a devDependency
|
|
254
|
+
b. A bin entry: "bin": { "intent": "./bin/intent.js" }
|
|
255
|
+
c. The shim file at bin/intent.js (run npx @tanstack/intent setup --shim in each package)
|
|
256
|
+
d. "skills" and "bin" in the package.json "files" array, with "!skills/_artifacts" to exclude artifacts
|
|
257
|
+
- Ask the maintainer which packages should get skills (usually client SDKs and primary framework adapters)
|
|
258
258
|
|
|
259
259
|
1) Meta skill: domain-discovery
|
|
260
260
|
- Input: library name, repo URL, docs URL(s), scope constraints, target audience.
|
|
261
|
-
- Output files
|
|
262
|
-
- skills/_artifacts/domain_map.yaml
|
|
263
|
-
-
|
|
261
|
+
- Output files:
|
|
262
|
+
- Single-repo: skills/_artifacts/domain_map.yaml, skills/_artifacts/skill_spec.md
|
|
263
|
+
- Monorepo: _artifacts/domain_map.yaml, _artifacts/skill_spec.md (at repo root)
|
|
264
|
+
- Domain discovery covers the WHOLE library. One domain map for the entire monorepo.
|
|
264
265
|
- These artifacts are maintainer-owned and should be committed to the repo.
|
|
265
266
|
|
|
266
267
|
2) Meta skill: tree-generator
|
|
267
|
-
- Input:
|
|
268
|
-
- Output file (
|
|
269
|
-
|
|
268
|
+
- Input: domain map + skill spec artifacts
|
|
269
|
+
- Output file: _artifacts/skill_tree.yaml (same location as domain map)
|
|
270
|
+
- The skill tree must specify which PACKAGE each skill belongs to.
|
|
271
|
+
- For monorepos, the tree maps skills to packages: each skill entry should include
|
|
272
|
+
a "package" field (e.g. packages/client, packages/react-client).
|
|
270
273
|
|
|
271
274
|
3) Meta skill: generate-skill
|
|
272
|
-
- Input:
|
|
273
|
-
- Output files
|
|
274
|
-
- skills/<domain>/<skill>/SKILL.md
|
|
275
|
+
- Input: skill tree
|
|
276
|
+
- Output files:
|
|
277
|
+
- Single-repo: skills/<domain>/<skill>/SKILL.md
|
|
278
|
+
- Monorepo: packages/<pkg>/skills/<domain>/<skill>/SKILL.md
|
|
279
|
+
- Skills are written into the package they describe, not a shared root.
|
|
275
280
|
|
|
276
281
|
Guidance for the maintainer:
|
|
277
282
|
- If any input is missing, ask for it.
|
|
@@ -280,20 +285,15 @@ Guidance for the maintainer:
|
|
|
280
285
|
- Use the library's actual terminology from docs and source.
|
|
281
286
|
|
|
282
287
|
At the end, produce a single Markdown feedback doc with three sections (Domain Discovery, Tree Generator, Generate Skill).
|
|
283
|
-
Ask if the maintainer wants to edit it, then
|
|
284
|
-
Use the issue title: [meta-feedback] intent meta skill.
|
|
288
|
+
Ask if the maintainer wants to edit it, then submit it via: npx @tanstack/intent feedback --meta --submit --file <path>
|
|
285
289
|
|
|
286
290
|
Finish with a short checklist:
|
|
287
|
-
- Run npx intent validate
|
|
288
|
-
- Commit skills/ and
|
|
289
|
-
- Exclude skills/_artifacts
|
|
290
|
-
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
console.log("✨ Copy the prompt below into your AI agent:\n");
|
|
294
|
-
console.log(prompt);
|
|
295
|
-
if (tryCopyToClipboard(prompt)) console.log("\n✅ Copied prompt to clipboard");
|
|
296
|
-
else console.log("\n⚠ Tip: Manually copy the prompt above into your agent");
|
|
291
|
+
- Run npx @tanstack/intent validate in each package directory (or for single-repo: at the root)
|
|
292
|
+
- Commit skills/ and artifacts
|
|
293
|
+
- Exclude artifacts from package publishing (add "!skills/_artifacts" to the "files" array in each package.json)
|
|
294
|
+
- For monorepos: ensure each package has @tanstack/intent as devDependency, bin entry, and shim
|
|
295
|
+
- Add README snippet: If you use an AI agent, run npx @tanstack/intent init
|
|
296
|
+
`);
|
|
297
297
|
}
|
|
298
298
|
const USAGE = `TanStack Intent CLI
|
|
299
299
|
|
|
@@ -303,7 +303,7 @@ Usage:
|
|
|
303
303
|
intent validate [<dir>] Validate skill files (default: skills/)
|
|
304
304
|
intent init Set up intent discovery in agent configs
|
|
305
305
|
intent scaffold Print maintainer scaffold prompt
|
|
306
|
-
intent setup [--workflows] [--
|
|
306
|
+
intent setup [--workflows] [--all] Copy CI templates into your repo
|
|
307
307
|
intent stale Check skills for staleness
|
|
308
308
|
intent feedback --submit --file <path> Submit skill feedback
|
|
309
309
|
intent feedback --meta --submit --file <path> Submit meta-skill feedback`;
|
|
@@ -320,7 +320,7 @@ switch (command) {
|
|
|
320
320
|
cmdValidate(commandArgs);
|
|
321
321
|
break;
|
|
322
322
|
case "init": {
|
|
323
|
-
const { runInit, detectAgentConfigs } = await import("./init-
|
|
323
|
+
const { runInit, detectAgentConfigs } = await import("./init-BU1ZnUbK.mjs");
|
|
324
324
|
const initRoot = process.cwd();
|
|
325
325
|
const result = runInit(initRoot);
|
|
326
326
|
for (const f of result.injected) console.log(`✓ Added intent block to ${f}`);
|
|
@@ -339,8 +339,8 @@ switch (command) {
|
|
|
339
339
|
cmdScaffold();
|
|
340
340
|
break;
|
|
341
341
|
case "stale": {
|
|
342
|
-
const { checkStaleness } = await import("./staleness-
|
|
343
|
-
const { scanForIntents: scanStale } = await import("./scanner-
|
|
342
|
+
const { checkStaleness } = await import("./staleness-B5gUj7FR.mjs");
|
|
343
|
+
const { scanForIntents: scanStale } = await import("./scanner-DkShtCWX.mjs");
|
|
344
344
|
let staleResult;
|
|
345
345
|
try {
|
|
346
346
|
staleResult = await scanStale();
|
|
@@ -372,7 +372,7 @@ switch (command) {
|
|
|
372
372
|
break;
|
|
373
373
|
}
|
|
374
374
|
case "feedback": {
|
|
375
|
-
const { runFeedback } = await import("./feedback-
|
|
375
|
+
const { runFeedback } = await import("./feedback-PR8JNBfM.mjs");
|
|
376
376
|
runFeedback(commandArgs);
|
|
377
377
|
break;
|
|
378
378
|
}
|
|
@@ -87,7 +87,6 @@ const VALID_META_SKILLS = [
|
|
|
87
87
|
"skill-staleness-check"
|
|
88
88
|
];
|
|
89
89
|
const VALID_AGENTS = [
|
|
90
|
-
"oz",
|
|
91
90
|
"claude-code",
|
|
92
91
|
"cursor",
|
|
93
92
|
"copilot",
|
|
@@ -259,10 +258,10 @@ function runFeedback(args) {
|
|
|
259
258
|
break;
|
|
260
259
|
case "file":
|
|
261
260
|
console.log(`✓ ${result$1.detail}`);
|
|
262
|
-
console.log(`
|
|
261
|
+
console.log(`You can manually open an issue at https://github.com/${META_FEEDBACK_REPO}/issues with this content.`);
|
|
263
262
|
break;
|
|
264
263
|
case "stdout":
|
|
265
|
-
console.log("--- Meta-feedback markdown (copy/paste to
|
|
264
|
+
console.log("--- Meta-feedback markdown (copy/paste to issue) ---");
|
|
266
265
|
console.log(result$1.detail);
|
|
267
266
|
break;
|
|
268
267
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as runFeedback, c as toMarkdown, i as resolveFrequency, l as validateMetaPayload, n as hasGhCli, o as submitFeedback, r as metaToMarkdown, s as submitMetaFeedback, t as containsSecrets, u as validatePayload } from "./feedback-
|
|
1
|
+
import { a as runFeedback, c as toMarkdown, i as resolveFrequency, l as validateMetaPayload, n as hasGhCli, o as submitFeedback, r as metaToMarkdown, s as submitMetaFeedback, t as containsSecrets, u as validatePayload } from "./feedback-BTSaBAS_.mjs";
|
|
2
2
|
|
|
3
3
|
export { runFeedback };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as IntentProjectConfig, c as ScanResult, d as StalenessReport, i as IntentPackage, l as SkillEntry, n as FeedbackPayload, o as MetaFeedbackPayload, r as IntentConfig, s as MetaSkillName, t as AgentName, u as SkillStaleness } from "./types-
|
|
2
|
-
import { n as runSetup } from "./setup-
|
|
1
|
+
import { a as IntentProjectConfig, c as ScanResult, d as StalenessReport, i as IntentPackage, l as SkillEntry, n as FeedbackPayload, o as MetaFeedbackPayload, r as IntentConfig, s as MetaSkillName, t as AgentName, u as SkillStaleness } from "./types-B20LP96b.mjs";
|
|
2
|
+
import { n as runSetup } from "./setup-D2Bwubpw.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/scanner.d.ts
|
|
5
5
|
declare function scanForIntents(root?: string): Promise<ScanResult>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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 { c as toMarkdown, i as resolveFrequency, l as validateMetaPayload, n as hasGhCli, o as submitFeedback, r as metaToMarkdown, s as submitMetaFeedback, t as containsSecrets, u as validatePayload } from "./feedback-
|
|
5
|
-
import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-
|
|
6
|
-
import { t as runSetup } from "./setup-
|
|
1
|
+
import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DH3jY3CI.mjs";
|
|
2
|
+
import { t as scanForIntents } from "./scanner-OmHt14bs.mjs";
|
|
3
|
+
import { t as checkStaleness } from "./staleness-lP6B0O4z.mjs";
|
|
4
|
+
import { c as toMarkdown, i as resolveFrequency, l as validateMetaPayload, n as hasGhCli, o as submitFeedback, r as metaToMarkdown, s as submitMetaFeedback, t as containsSecrets, u as validatePayload } from "./feedback-BTSaBAS_.mjs";
|
|
5
|
+
import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-DUiDMMrN.mjs";
|
|
6
|
+
import { t as runSetup } from "./setup-BvrZZLsA.mjs";
|
|
7
7
|
|
|
8
8
|
export { checkStaleness, containsSecrets, detectAgentConfigs, findSkillFiles, hasGhCli, hasIntentBlock, injectIntentBlock, metaToMarkdown, parseFrontmatter, readProjectConfig, resolveFrequency, runInit, runSetup, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload, writeProjectConfig };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-
|
|
1
|
+
import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-DUiDMMrN.mjs";
|
|
2
2
|
|
|
3
3
|
export { detectAgentConfigs, runInit };
|
|
@@ -14,6 +14,8 @@ const INTENT_BLOCK = `## Intent Skills
|
|
|
14
14
|
This project uses TanStack Intent. Run \`npx intent list\` to discover
|
|
15
15
|
available AI coding skills. Before working with a library that has skills,
|
|
16
16
|
read the relevant SKILL.md file at the path shown in the list output.
|
|
17
|
+
After completing a task that used skills, collect and submit feedback
|
|
18
|
+
following the instructions in the list output.
|
|
17
19
|
`;
|
|
18
20
|
const DEFAULT_CONFIG = { feedback: { frequency: "every-5" } };
|
|
19
21
|
function detectAgentConfigs(root) {
|
package/dist/intent-library.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./utils-
|
|
3
|
-
import { t as scanLibrary } from "./library-scanner-
|
|
2
|
+
import "./utils-DH3jY3CI.mjs";
|
|
3
|
+
import { t as scanLibrary } from "./library-scanner-D0aP7is_.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/intent-library.ts
|
|
6
6
|
function padColumn(text, width) {
|
|
@@ -90,6 +90,11 @@ async function cmdList() {
|
|
|
90
90
|
});
|
|
91
91
|
console.log();
|
|
92
92
|
}
|
|
93
|
+
console.log(`Feedback:`);
|
|
94
|
+
console.log(` After completing your task, collect feedback on skill usage.`);
|
|
95
|
+
console.log(` Instructions: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md`);
|
|
96
|
+
console.log(` Submit: npx intent feedback --submit --file intent-feedback.json`);
|
|
97
|
+
console.log();
|
|
93
98
|
if (result.warnings.length > 0) {
|
|
94
99
|
console.log(`Warnings:`);
|
|
95
100
|
for (const w of result.warnings) console.log(` ⚠ ${w}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as parseFrontmatter } from "./utils-
|
|
1
|
+
import { n as parseFrontmatter } from "./utils-DH3jY3CI.mjs";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, sep } from "node:path";
|
|
4
4
|
|
|
@@ -37,7 +37,10 @@ function discoverSkills(skillsDir) {
|
|
|
37
37
|
function walk(dir) {
|
|
38
38
|
let entries;
|
|
39
39
|
try {
|
|
40
|
-
entries = readdirSync(dir, {
|
|
40
|
+
entries = readdirSync(dir, {
|
|
41
|
+
withFileTypes: true,
|
|
42
|
+
encoding: "utf8"
|
|
43
|
+
});
|
|
41
44
|
} catch {
|
|
42
45
|
return;
|
|
43
46
|
}
|
package/dist/library-scanner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as parseFrontmatter } from "./utils-
|
|
1
|
+
import { n as parseFrontmatter } from "./utils-DH3jY3CI.mjs";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { join, relative, sep } from "node:path";
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ function detectPackageManager(root) {
|
|
|
12
12
|
if (existsSync(join(root, "package-lock.json"))) return "npm";
|
|
13
13
|
return "unknown";
|
|
14
14
|
}
|
|
15
|
-
function validateIntentField(
|
|
15
|
+
function validateIntentField(_pkgName, intent) {
|
|
16
16
|
if (!intent || typeof intent !== "object") return null;
|
|
17
17
|
const pb = intent;
|
|
18
18
|
if (pb.version !== 1) return null;
|
|
@@ -26,12 +26,39 @@ function validateIntentField(pkgName, intent) {
|
|
|
26
26
|
requires
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Derive an IntentConfig from standard package.json fields when no explicit
|
|
31
|
+
* `intent` field is present. A package with a `skills/` directory signals
|
|
32
|
+
* intent support; `repo` and `docs` are derived from `repository` and
|
|
33
|
+
* `homepage`.
|
|
34
|
+
*/
|
|
35
|
+
function deriveIntentConfig(pkgJson) {
|
|
36
|
+
let repo = null;
|
|
37
|
+
if (typeof pkgJson.repository === "string") repo = pkgJson.repository;
|
|
38
|
+
else if (pkgJson.repository && typeof pkgJson.repository === "object" && typeof pkgJson.repository.url === "string") {
|
|
39
|
+
repo = pkgJson.repository.url;
|
|
40
|
+
repo = repo.replace(/^git\+/, "").replace(/\.git$/, "").replace(/^https?:\/\/github\.com\//, "");
|
|
41
|
+
}
|
|
42
|
+
const docs = typeof pkgJson.homepage === "string" ? pkgJson.homepage : void 0;
|
|
43
|
+
if (!repo) return null;
|
|
44
|
+
const intentPartial = pkgJson.intent;
|
|
45
|
+
const requires = intentPartial && Array.isArray(intentPartial.requires) ? intentPartial.requires.filter((r) => typeof r === "string") : void 0;
|
|
46
|
+
return {
|
|
47
|
+
version: 1,
|
|
48
|
+
repo,
|
|
49
|
+
docs: docs ?? "",
|
|
50
|
+
requires
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function discoverSkills(skillsDir, _baseName) {
|
|
30
54
|
const skills = [];
|
|
31
55
|
function walk(dir) {
|
|
32
56
|
let entries;
|
|
33
57
|
try {
|
|
34
|
-
entries = readdirSync(dir, {
|
|
58
|
+
entries = readdirSync(dir, {
|
|
59
|
+
withFileTypes: true,
|
|
60
|
+
encoding: "utf8"
|
|
61
|
+
});
|
|
35
62
|
} catch {
|
|
36
63
|
return;
|
|
37
64
|
}
|
|
@@ -86,7 +113,10 @@ async function scanForIntents(root) {
|
|
|
86
113
|
const packageDirs = [];
|
|
87
114
|
let topEntries;
|
|
88
115
|
try {
|
|
89
|
-
topEntries = readdirSync(nodeModulesDir, {
|
|
116
|
+
topEntries = readdirSync(nodeModulesDir, {
|
|
117
|
+
withFileTypes: true,
|
|
118
|
+
encoding: "utf8"
|
|
119
|
+
});
|
|
90
120
|
} catch {
|
|
91
121
|
return {
|
|
92
122
|
packageManager,
|
|
@@ -100,7 +130,10 @@ async function scanForIntents(root) {
|
|
|
100
130
|
if (entry.name.startsWith("@")) {
|
|
101
131
|
let scopedEntries;
|
|
102
132
|
try {
|
|
103
|
-
scopedEntries = readdirSync(dirPath, {
|
|
133
|
+
scopedEntries = readdirSync(dirPath, {
|
|
134
|
+
withFileTypes: true,
|
|
135
|
+
encoding: "utf8"
|
|
136
|
+
});
|
|
104
137
|
} catch {
|
|
105
138
|
continue;
|
|
106
139
|
}
|
|
@@ -123,9 +156,9 @@ async function scanForIntents(root) {
|
|
|
123
156
|
}
|
|
124
157
|
const pkgName = typeof pkgJson.name === "string" ? pkgJson.name : "unknown";
|
|
125
158
|
const pkgVersion = typeof pkgJson.version === "string" ? pkgJson.version : "0.0.0";
|
|
126
|
-
const intent = validateIntentField(pkgName, pkgJson.intent);
|
|
159
|
+
const intent = validateIntentField(pkgName, pkgJson.intent) ?? deriveIntentConfig(pkgJson);
|
|
127
160
|
if (!intent) {
|
|
128
|
-
warnings.push(`${pkgName} has a skills/ directory but
|
|
161
|
+
warnings.push(`${pkgName} has a skills/ directory but could not determine repo/docs from package.json (add a "repository" field or explicit "intent" config)`);
|
|
129
162
|
continue;
|
|
130
163
|
}
|
|
131
164
|
const skills = discoverSkills(skillsDir, pkgName);
|
|
@@ -67,16 +67,13 @@ function generateShim(root, result) {
|
|
|
67
67
|
function runSetup(root, metaDir, args) {
|
|
68
68
|
const doAll = args.includes("--all");
|
|
69
69
|
const doWorkflows = doAll || args.includes("--workflows");
|
|
70
|
-
const doOz = doAll || args.includes("--oz");
|
|
71
70
|
const doShim = doAll || args.includes("--shim");
|
|
72
|
-
const defaultAll = !doWorkflows && !
|
|
71
|
+
const defaultAll = !doWorkflows && !doShim;
|
|
73
72
|
const installWorkflows = doWorkflows || defaultAll;
|
|
74
|
-
const installOz = doOz || defaultAll;
|
|
75
73
|
const installShim = doShim || defaultAll;
|
|
76
74
|
const vars = detectVars(root);
|
|
77
75
|
const result = {
|
|
78
76
|
workflows: [],
|
|
79
|
-
oz: [],
|
|
80
77
|
skipped: [],
|
|
81
78
|
shim: null
|
|
82
79
|
};
|
|
@@ -86,14 +83,8 @@ function runSetup(root, metaDir, args) {
|
|
|
86
83
|
result.workflows = copied;
|
|
87
84
|
result.skipped.push(...skipped);
|
|
88
85
|
}
|
|
89
|
-
if (installOz) {
|
|
90
|
-
const { copied, skipped } = copyTemplates(join(templatesDir, "oz"), join(root, ".intent", "oz"), vars);
|
|
91
|
-
result.oz = copied;
|
|
92
|
-
result.skipped.push(...skipped);
|
|
93
|
-
}
|
|
94
86
|
if (installShim) generateShim(root, result);
|
|
95
87
|
for (const f of result.workflows) console.log(`✓ Copied workflow: ${f}`);
|
|
96
|
-
for (const f of result.oz) console.log(`✓ Copied Oz prompt: ${f}`);
|
|
97
88
|
for (const f of result.skipped) console.log(` Already exists: ${f}`);
|
|
98
89
|
if (result.shim) {
|
|
99
90
|
console.log(`✓ Generated intent shim: ${result.shim}`);
|
|
@@ -101,8 +92,8 @@ function runSetup(root, metaDir, args) {
|
|
|
101
92
|
console.log(` "bin": { "intent": "./bin/intent.js" }`);
|
|
102
93
|
console.log(`\n Add bin/intent.js to your package.json "files" array.`);
|
|
103
94
|
}
|
|
104
|
-
if (result.workflows.length === 0 && result.
|
|
105
|
-
else if (result.workflows.length > 0
|
|
95
|
+
if (result.workflows.length === 0 && result.shim === null && result.skipped.length === 0) console.log("No templates directory found. Is @tanstack/intent installed?");
|
|
96
|
+
else if (result.workflows.length > 0) {
|
|
106
97
|
console.log(`\nTemplate variables applied:`);
|
|
107
98
|
console.log(` Package: ${vars.PACKAGE_NAME}`);
|
|
108
99
|
console.log(` Repo: ${vars.REPO}`);
|
package/dist/setup.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as runSetup, t as SetupResult } from "./setup-
|
|
1
|
+
import { n as runSetup, t as SetupResult } from "./setup-D2Bwubpw.mjs";
|
|
2
2
|
export { SetupResult, runSetup };
|
package/dist/setup.mjs
CHANGED
|
@@ -48,7 +48,7 @@ interface FeedbackPayload {
|
|
|
48
48
|
userComments?: string;
|
|
49
49
|
}
|
|
50
50
|
type MetaSkillName = 'domain-discovery' | 'tree-generator' | 'generate-skill' | 'skill-staleness-check';
|
|
51
|
-
type AgentName = '
|
|
51
|
+
type AgentName = 'claude-code' | 'cursor' | 'copilot' | 'codex' | 'other';
|
|
52
52
|
interface MetaFeedbackPayload {
|
|
53
53
|
metaSkill: MetaSkillName;
|
|
54
54
|
library: string;
|
|
@@ -57,7 +57,26 @@ reading exhaustively yet.
|
|
|
57
57
|
guidance, read it. This is high-signal for what the maintainer
|
|
58
58
|
considers important
|
|
59
59
|
|
|
60
|
-
### 1b —
|
|
60
|
+
### 1b — Read peer dependency constraints
|
|
61
|
+
|
|
62
|
+
Check `package.json` for `peerDependencies` and `peerDependenciesMeta`.
|
|
63
|
+
For each major peer dependency (React, Vue, Svelte, Next.js, etc.):
|
|
64
|
+
|
|
65
|
+
1. Note the version range required
|
|
66
|
+
2. Read the peer's docs for integration constraints that affect this
|
|
67
|
+
library: SSR/hydration rules, component lifecycle boundaries,
|
|
68
|
+
browser-only APIs, singleton patterns, connection limits
|
|
69
|
+
3. Log framework-specific failure modes — these are the highest-impact
|
|
70
|
+
failure modes and cannot be discovered from the library's own source
|
|
71
|
+
|
|
72
|
+
Examples of peer-dependency-driven failure modes:
|
|
73
|
+
|
|
74
|
+
- SSR: calling browser-only APIs during server render
|
|
75
|
+
- React: breaking hook rules in library wrapper components
|
|
76
|
+
- Connection limits: opening multiple WebSocket connections per tab
|
|
77
|
+
- Singleton patterns: creating multiple client instances in dev mode
|
|
78
|
+
|
|
79
|
+
### 1c — Note initial impressions
|
|
61
80
|
|
|
62
81
|
Log (but do not group yet):
|
|
63
82
|
|
|
@@ -191,7 +210,11 @@ Move concept inventory items into groups. Two items belong together when:
|
|
|
191
210
|
- They share a lifecycle, configuration scope, or architectural tradeoff
|
|
192
211
|
- Getting one wrong tends to produce bugs in the other
|
|
193
212
|
|
|
194
|
-
|
|
213
|
+
Let library complexity drive the domain count — a focused library may need
|
|
214
|
+
only 2–3 domains, while a large framework may need 7+. Validate by asking:
|
|
215
|
+
"Would a developer working on a single feature need to load skills from
|
|
216
|
+
multiple domains? If so, merge those domains." These are conceptual
|
|
217
|
+
groupings, not the final skills.
|
|
195
218
|
|
|
196
219
|
Do not create a group for:
|
|
197
220
|
|
|
@@ -202,6 +225,14 @@ Do not create a group for:
|
|
|
202
225
|
|
|
203
226
|
Name each domain as work being performed, not what the library provides.
|
|
204
227
|
|
|
228
|
+
**Validation step:** After grouping, check each domain by asking:
|
|
229
|
+
"Would a developer working on a single feature need to load skills from
|
|
230
|
+
multiple domains?" If yes, merge those domains. Group by developer tasks
|
|
231
|
+
(what they're trying to accomplish), not by architecture (how the library
|
|
232
|
+
is organized internally). For example, prefer "writing data" over
|
|
233
|
+
"producer lifecycle" — the former matches a developer's intent, the latter
|
|
234
|
+
matches the codebase structure.
|
|
235
|
+
|
|
205
236
|
### 3b — Map domains × tasks → skills
|
|
206
237
|
|
|
207
238
|
Merge your conceptual domains with the maintainer's task list from
|
|
@@ -268,6 +299,14 @@ For each skill, extract failure modes that pass all three tests:
|
|
|
268
299
|
|
|
269
300
|
Target 3 failure modes per skill minimum. Complex skills target 5–6.
|
|
270
301
|
|
|
302
|
+
**Code patterns.** Every failure mode should include `wrong_pattern` and
|
|
303
|
+
`correct_pattern` fields with short code snippets (3–10 lines each).
|
|
304
|
+
The wrong pattern is what an agent would generate; the correct pattern
|
|
305
|
+
is the fix. These feed directly into SKILL.md Common Mistakes sections
|
|
306
|
+
as wrong/correct code pairs. If the failure mode is purely conceptual
|
|
307
|
+
(e.g. an architectural choice) rather than a code pattern, omit both
|
|
308
|
+
fields and explain in `mechanism` instead.
|
|
309
|
+
|
|
271
310
|
**Cross-skill failure modes.** Some failure modes belong to multiple
|
|
272
311
|
skills. A developer doing SSR work and a developer doing state management
|
|
273
312
|
both need to know about "stale state during hydration" — they load
|
|
@@ -465,6 +504,11 @@ Update `status: draft` to `status: reviewed`.
|
|
|
465
504
|
If the maintainer uses a custom skills root, replace `skills/` in the paths
|
|
466
505
|
below with their chosen directory.
|
|
467
506
|
|
|
507
|
+
**Monorepo layout:** For monorepos, domain map artifacts go at the REPO ROOT
|
|
508
|
+
(e.g. `_artifacts/domain_map.yaml`) since they describe the whole library.
|
|
509
|
+
Skills are generated per-package later by the tree-generator and generate-skill
|
|
510
|
+
steps.
|
|
511
|
+
|
|
468
512
|
### 1. skills/\_artifacts/domain_map.yaml
|
|
469
513
|
|
|
470
514
|
```yaml
|
|
@@ -510,6 +554,10 @@ skills:
|
|
|
510
554
|
failure_modes:
|
|
511
555
|
- mistake: '[5-10 word phrase]'
|
|
512
556
|
mechanism: '[one sentence]'
|
|
557
|
+
wrong_pattern: | # the code an agent would incorrectly generate
|
|
558
|
+
[short code snippet showing the mistake]
|
|
559
|
+
correct_pattern: | # the code that should be generated instead
|
|
560
|
+
[short code snippet showing the fix]
|
|
513
561
|
source: '[doc page, source file, issue link, or maintainer interview]'
|
|
514
562
|
priority: '[CRITICAL | HIGH | MEDIUM]'
|
|
515
563
|
status: '[active | fixed-but-legacy-risk | removed]'
|
|
@@ -47,6 +47,10 @@ You will receive:
|
|
|
47
47
|
If the maintainer uses a custom skills root, replace `skills/` in any paths
|
|
48
48
|
below with their chosen directory.
|
|
49
49
|
|
|
50
|
+
**Monorepo:** When the skill tree entry has a `package` field, write the
|
|
51
|
+
SKILL.md into that package's skills directory (e.g.
|
|
52
|
+
`packages/client/skills/core/SKILL.md`), not a shared root.
|
|
53
|
+
|
|
50
54
|
1. **Skill name** — format `library-group/skill-name` (e.g. `tanstack-query/core`,
|
|
51
55
|
`tanstack-router/loaders`, `db/core/live-queries`)
|
|
52
56
|
2. **Skill description** — what the skill covers and when an agent should load it
|
|
@@ -77,6 +81,11 @@ skill-tree-generator for the full spec of each type.
|
|
|
77
81
|
|
|
78
82
|
## Step 2 — Extract content from sources
|
|
79
83
|
|
|
84
|
+
**Line budget:** Each SKILL.md must stay under 500 lines. Before writing,
|
|
85
|
+
estimate the content size. If a skill has 5+ failure modes, 3+ primary
|
|
86
|
+
patterns, and subsystem details, proactively plan reference files during
|
|
87
|
+
extraction — don't wait until the skill exceeds the limit.
|
|
88
|
+
|
|
80
89
|
Read through the source documentation. Extract only what a coding agent
|
|
81
90
|
cannot already know:
|
|
82
91
|
|
|
@@ -67,7 +67,7 @@ discovery. This produces lower-fidelity output than the full
|
|
|
67
67
|
skill-domain-discovery skill — prefer running that when time permits.
|
|
68
68
|
|
|
69
69
|
1. Build a concept inventory (every export, config key, constraint, warning)
|
|
70
|
-
2. Group into
|
|
70
|
+
2. Group into capability domains using work-oriented names (let library complexity drive the count — 2–3 for focused libraries, more for large frameworks)
|
|
71
71
|
3. Enumerate 10–20 task-focused skills from the intersection of domains
|
|
72
72
|
and developer tasks
|
|
73
73
|
4. Extract 3+ failure modes per skill (plausible, silent, grounded)
|
|
@@ -106,6 +106,7 @@ skills:
|
|
|
106
106
|
type: 'core | sub-skill | framework | lifecycle | composition | security'
|
|
107
107
|
domain: '[domain slug]'
|
|
108
108
|
path: 'skills/[path]/SKILL.md'
|
|
109
|
+
package: '[package directory, e.g. packages/client]' # monorepo only — which package this skill belongs to
|
|
109
110
|
description: '[1–2 sentence agent-facing routing key]'
|
|
110
111
|
requires:
|
|
111
112
|
- '[other skill slugs]' # omit if none
|
|
@@ -118,6 +119,11 @@ skills:
|
|
|
118
119
|
- 'references/[file].md' # omit if none
|
|
119
120
|
```
|
|
120
121
|
|
|
122
|
+
**Monorepo layout:** For monorepos, each skill's `path` is relative to its
|
|
123
|
+
package directory (e.g. `packages/client/skills/core/SKILL.md`). Set the
|
|
124
|
+
`package` field so generate-skill knows where to write the file. The domain
|
|
125
|
+
map artifacts stay at the repo root.
|
|
126
|
+
|
|
121
127
|
### Step 1 — Plan the file tree
|
|
122
128
|
|
|
123
129
|
From the domain map, each entry in the `skills` list becomes a SKILL.md
|
package/package.json
CHANGED