@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 CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DjkEPBxu.mjs";
3
- import { t as scanForIntents } from "./scanner-CpsJAHXT.mjs";
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
- function tryCopyToClipboard(text) {
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 for their skills root path.
256
- - Default: skills/
257
- - If they choose a different path, replace "skills/" in all output paths below.
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 (exact paths):
262
- - skills/_artifacts/domain_map.yaml
263
- - skills/_artifacts/skill_spec.md
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: skills/_artifacts/domain_map.yaml + skills/_artifacts/skill_spec.md
268
- - Output file (exact path):
269
- - skills/_artifacts/skill_tree.yaml
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: skills/_artifacts/skill_tree.yaml
273
- - Output files (exact path pattern):
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 ask if you should send it as a GitHub issue to TanStack/intent.
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 skills/_artifacts/ (artifacts are repo-only)
289
- - Exclude skills/_artifacts/ from package publishing
290
- - Add README snippet: If you use an AI agent, run npx intent init
291
- `;
292
- console.log("🚀 Intent Scaffold Prompt");
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] [--oz] [--all] Copy CI/Oz templates into your repo
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-DEzzXm9j.mjs");
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-DyhsrqQ5.mjs");
343
- const { scanForIntents: scanStale } = await import("./scanner-BuWPDJ4P.mjs");
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-FIUBOL0g.mjs");
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(`Open a GitHub Discussion at https://github.com/${META_FEEDBACK_REPO}/discussions/new?category=Feedback`);
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 discussion) ---");
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-DKreHfB1.mjs";
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-kbQfN_is.mjs";
2
- import { n as runSetup } from "./setup-N5dttGp_.mjs";
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-DjkEPBxu.mjs";
2
- import { t as scanForIntents } from "./scanner-CpsJAHXT.mjs";
3
- import { t as checkStaleness } from "./staleness-CnomT9Hm.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-DKreHfB1.mjs";
5
- import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-DNxmjQfU.mjs";
6
- import { t as runSetup } from "./setup-CNGz26qL.mjs";
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-DNxmjQfU.mjs";
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) {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./utils-DjkEPBxu.mjs";
3
- import { t as scanLibrary } from "./library-scanner-BrznE00j.mjs";
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-DjkEPBxu.mjs";
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, { withFileTypes: true });
40
+ entries = readdirSync(dir, {
41
+ withFileTypes: true,
42
+ encoding: "utf8"
43
+ });
41
44
  } catch {
42
45
  return;
43
46
  }
@@ -1,4 +1,4 @@
1
- import { l as SkillEntry } from "./types-kbQfN_is.mjs";
1
+ import { l as SkillEntry } from "./types-B20LP96b.mjs";
2
2
 
3
3
  //#region src/library-scanner.d.ts
4
4
  interface LibraryPackage {
@@ -1,4 +1,4 @@
1
- import "./utils-DjkEPBxu.mjs";
2
- import { t as scanLibrary } from "./library-scanner-BrznE00j.mjs";
1
+ import "./utils-DH3jY3CI.mjs";
2
+ import { t as scanLibrary } from "./library-scanner-D0aP7is_.mjs";
3
3
 
4
4
  export { scanLibrary };
@@ -0,0 +1,4 @@
1
+ import "./utils-DH3jY3CI.mjs";
2
+ import { t as scanForIntents } from "./scanner-OmHt14bs.mjs";
3
+
4
+ export { scanForIntents };
@@ -1,4 +1,4 @@
1
- import { n as parseFrontmatter } from "./utils-DjkEPBxu.mjs";
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(pkgName, intent) {
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
- function discoverSkills(skillsDir, baseName) {
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, { withFileTypes: true });
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, { withFileTypes: true });
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, { withFileTypes: true });
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 missing or invalid "intent" field in package.json`);
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 && !doOz && !doShim;
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.oz.length === 0 && result.shim === null && result.skipped.length === 0) console.log("No templates directory found. Is @tanstack/intent installed?");
105
- else if (result.workflows.length > 0 || result.oz.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}`);
@@ -1,7 +1,6 @@
1
1
  //#region src/setup.d.ts
2
2
  interface SetupResult {
3
3
  workflows: string[];
4
- oz: string[];
5
4
  skipped: string[];
6
5
  shim: string | null;
7
6
  }
package/dist/setup.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as runSetup, t as SetupResult } from "./setup-N5dttGp_.mjs";
1
+ import { n as runSetup, t as SetupResult } from "./setup-D2Bwubpw.mjs";
2
2
  export { SetupResult, runSetup };
package/dist/setup.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { t as runSetup } from "./setup-CNGz26qL.mjs";
1
+ import { t as runSetup } from "./setup-BvrZZLsA.mjs";
2
2
 
3
3
  export { runSetup };
@@ -0,0 +1,4 @@
1
+ import "./utils-DH3jY3CI.mjs";
2
+ import { t as checkStaleness } from "./staleness-lP6B0O4z.mjs";
3
+
4
+ export { checkStaleness };
@@ -1,4 +1,4 @@
1
- import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DjkEPBxu.mjs";
1
+ import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DH3jY3CI.mjs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join, relative, sep } from "node:path";
4
4
 
@@ -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 = 'oz' | 'claude-code' | 'cursor' | 'copilot' | 'codex' | 'other';
51
+ type AgentName = 'claude-code' | 'cursor' | 'copilot' | 'codex' | 'other';
52
52
  interface MetaFeedbackPayload {
53
53
  metaSkill: MetaSkillName;
54
54
  library: string;
@@ -27,7 +27,7 @@ function parseFrontmatter(filePath) {
27
27
  return null;
28
28
  }
29
29
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
30
- if (!match) return null;
30
+ if (!match?.[1]) return null;
31
31
  try {
32
32
  return parse(match[1]);
33
33
  } catch {
@@ -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 — Note initial impressions
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
- Target 4–7 domains. These are conceptual groupings, not the final skills.
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 4–7 capability domains using work-oriented names
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/intent",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Ship compositional knowledge for AI coding agents alongside your npm packages",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,4 +0,0 @@
1
- import "./utils-DjkEPBxu.mjs";
2
- import { t as scanForIntents } from "./scanner-CpsJAHXT.mjs";
3
-
4
- export { scanForIntents };
@@ -1,4 +0,0 @@
1
- import "./utils-DjkEPBxu.mjs";
2
- import { t as checkStaleness } from "./staleness-CnomT9Hm.mjs";
3
-
4
- export { checkStaleness };