@tanstack/intent 0.0.19 → 0.0.21

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.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  //#region src/cli.d.ts
3
- declare const USAGE = "TanStack Intent CLI\n\nUsage:\n intent list [--json] Discover intent-enabled packages\n intent meta [name] List meta-skills, or print one by name\n intent validate [<dir>] Validate skill files (default: skills/)\n intent install Print a skill that guides your coding agent to set up skill-to-task mappings\n intent scaffold Print maintainer scaffold prompt\n intent add-library-bin Generate bin/intent.{js,mjs} bridge file\n intent edit-package-json Wire package.json (files, bin) for skill publishing\n intent setup-github-actions Copy CI workflow templates to .github/workflows/\n intent stale [dir] [--json] Check skills for staleness";
3
+ declare const USAGE = "TanStack Intent CLI\n\nUsage:\n intent list [--json] Discover intent-enabled packages\n intent meta [name] List meta-skills, or print one by name\n intent validate [<dir>] Validate skill files (default: skills/)\n intent install Print a skill that guides your coding agent to set up skill-to-task mappings\n intent scaffold Print maintainer scaffold prompt\n intent edit-package-json Wire package.json (files, keywords) for skill publishing\n intent setup-github-actions Copy CI workflow templates to .github/workflows/\n intent stale [dir] [--json] Check skills for staleness";
4
4
  declare function main(argv?: Array<string>): Promise<number>;
5
5
  //#endregion
6
6
  export { USAGE, main };
package/dist/cli.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as INSTALL_PROMPT } from "./install-prompt-C0M-U3WZ.mjs";
3
- import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
4
4
  import { dirname, join, relative, sep } from "node:path";
5
- import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { fileURLToPath } from "node:url";
6
6
 
7
7
  //#region src/cli.ts
8
8
  function getMetaDir() {
@@ -18,7 +18,7 @@ function isCliFailure(value) {
18
18
  return !!value && typeof value === "object" && "message" in value && typeof value.message === "string" && "exitCode" in value && typeof value.exitCode === "number";
19
19
  }
20
20
  async function scanIntentsOrFail() {
21
- const { scanForIntents } = await import("./scanner-B1UvuEBQ.mjs");
21
+ const { scanForIntents } = await import("./scanner-RWHFrJ_C.mjs");
22
22
  try {
23
23
  return await scanForIntents();
24
24
  } catch (err) {
@@ -113,7 +113,7 @@ async function cmdList(args) {
113
113
  printWarnings(result.warnings);
114
114
  }
115
115
  async function cmdMeta(args) {
116
- const { parseFrontmatter } = await import("./utils-XSyO19J6.mjs");
116
+ const { parseFrontmatter } = await import("./utils-D7OKi0Rn.mjs");
117
117
  const metaDir = getMetaDir();
118
118
  if (!existsSync(metaDir)) fail("Meta-skills directory not found.");
119
119
  if (args.length > 0) {
@@ -155,15 +155,27 @@ function collectPackagingWarnings(root) {
155
155
  }
156
156
  const warnings = [];
157
157
  if (!pkgJson.devDependencies?.["@tanstack/intent"]) warnings.push("@tanstack/intent is not in devDependencies");
158
- if (!pkgJson.bin?.intent) warnings.push("Missing \"bin\": { \"intent\": ... } entry in package.json");
159
- const shimJs = join(root, "bin", "intent.js");
160
- const shimMjs = join(root, "bin", "intent.mjs");
161
- if (!existsSync(shimJs) && !existsSync(shimMjs)) warnings.push("No bin/intent.js or bin/intent.mjs shim found (run: npx @tanstack/intent add-library-bin)");
158
+ const keywords = pkgJson.keywords;
159
+ if (!Array.isArray(keywords) || !keywords.includes("tanstack-intent")) warnings.push("Missing \"tanstack-intent\" in keywords array");
162
160
  const files = pkgJson.files;
163
161
  if (Array.isArray(files)) {
164
162
  if (!files.includes("skills")) warnings.push("\"skills\" is not in the \"files\" array — skills won't be published");
165
- if (!files.includes("bin")) warnings.push("\"bin\" is not in the \"files\" array — shim won't be published");
166
- if (!files.includes("!skills/_artifacts")) warnings.push("\"!skills/_artifacts\" is not in the \"files\" array — artifacts will be published unnecessarily");
163
+ if (!(() => {
164
+ let dir = join(root, "..");
165
+ for (let i = 0; i < 5; i++) {
166
+ const parentPkg = join(dir, "package.json");
167
+ if (existsSync(parentPkg)) try {
168
+ const parent = JSON.parse(readFileSync(parentPkg, "utf8"));
169
+ return Array.isArray(parent.workspaces) || parent.workspaces?.packages;
170
+ } catch {
171
+ return false;
172
+ }
173
+ const next = dirname(dir);
174
+ if (next === dir) break;
175
+ dir = next;
176
+ }
177
+ return false;
178
+ })() && !files.includes("!skills/_artifacts")) warnings.push("\"!skills/_artifacts\" is not in the \"files\" array — artifacts will be published unnecessarily");
167
179
  }
168
180
  return warnings;
169
181
  }
@@ -186,7 +198,7 @@ function readPackageName(root) {
186
198
  }
187
199
  async function resolveStaleTargets(targetDir) {
188
200
  const resolvedRoot = targetDir ? join(process.cwd(), targetDir) : process.cwd();
189
- const { checkStaleness } = await import("./staleness-CWWuoPop.mjs");
201
+ const { checkStaleness } = await import("./staleness-Dr5-5wj5.mjs");
190
202
  if (existsSync(join(resolvedRoot, "skills"))) return { reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))] };
191
203
  const { findPackagesWithSkills, findWorkspaceRoot } = await import("./setup.mjs");
192
204
  const workspaceRoot = findWorkspaceRoot(resolvedRoot);
@@ -198,7 +210,7 @@ async function resolveStaleTargets(targetDir) {
198
210
  return { reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))) };
199
211
  }
200
212
  async function cmdValidate(args) {
201
- const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-XSyO19J6.mjs")]);
213
+ const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-D7OKi0Rn.mjs")]);
202
214
  const targetDir = args[0] ?? "skills";
203
215
  const skillsDir = join(process.cwd(), targetDir);
204
216
  const packageRoot = resolvePackageRoot(skillsDir);
@@ -361,11 +373,10 @@ This produces: individual SKILL.md files.
361
373
 
362
374
  1. Run \`intent validate\` in each package directory
363
375
  2. Commit skills/ and artifacts
364
- 3. For each publishable package, run: \`npx @tanstack/intent add-library-bin\`
365
- 4. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
366
- 5. Ensure each package has \`@tanstack/intent\` as a devDependency
367
- 6. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
368
- 7. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
376
+ 3. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
377
+ 4. Ensure each package has \`@tanstack/intent\` as a devDependency
378
+ 5. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
379
+ 6. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
369
380
  `;
370
381
  console.log(prompt);
371
382
  }
@@ -377,8 +388,7 @@ Usage:
377
388
  intent validate [<dir>] Validate skill files (default: skills/)
378
389
  intent install Print a skill that guides your coding agent to set up skill-to-task mappings
379
390
  intent scaffold Print maintainer scaffold prompt
380
- intent add-library-bin Generate bin/intent.{js,mjs} bridge file
381
- intent edit-package-json Wire package.json (files, bin) for skill publishing
391
+ intent edit-package-json Wire package.json (files, keywords) for skill publishing
382
392
  intent setup-github-actions Copy CI workflow templates to .github/workflows/
383
393
  intent stale [dir] [--json] Check skills for staleness`;
384
394
  const HELP_BY_COMMAND = {
@@ -415,12 +425,9 @@ Examples:
415
425
  intent stale
416
426
  intent stale packages/query
417
427
  intent stale --json`,
418
- "add-library-bin": `intent add-library-bin
419
-
420
- Generate bin/intent.{js,mjs} bridge files for publishable packages.`,
421
428
  "edit-package-json": `intent edit-package-json
422
429
 
423
- Update package.json files so skills and shims are published.`,
430
+ Update package.json files so skills are published.`,
424
431
  "setup-github-actions": `intent setup-github-actions
425
432
 
426
433
  Copy Intent CI workflow templates into .github/workflows/.`
@@ -491,11 +498,6 @@ async function main(argv = process.argv.slice(2)) {
491
498
  }
492
499
  return 0;
493
500
  }
494
- case "add-library-bin": {
495
- const { runAddLibraryBinAll } = await import("./setup.mjs");
496
- runAddLibraryBinAll(process.cwd());
497
- return 0;
498
- }
499
501
  case "edit-package-json": {
500
502
  const { runEditPackageJsonAll } = await import("./setup.mjs");
501
503
  runEditPackageJsonAll(process.cwd());
@@ -518,7 +520,11 @@ async function main(argv = process.argv.slice(2)) {
518
520
  throw err;
519
521
  }
520
522
  }
521
- if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) {
523
+ let isMain = false;
524
+ try {
525
+ isMain = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(process.argv[1]);
526
+ } catch {}
527
+ if (isMain) {
522
528
  const exitCode = await main();
523
529
  process.exit(exitCode);
524
530
  }
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
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-ddLtccfV.mjs";
2
- import { c as runAddLibraryBin, f as runSetupGithubActions, i as SetupGithubActionsResult, n as EditPackageJsonResult, t as AddLibraryBinResult, u as runEditPackageJson } from "./setup-6m3IfxyO.mjs";
2
+ import { c as runEditPackageJson, r as SetupGithubActionsResult, t as EditPackageJsonResult, u as runSetupGithubActions } from "./setup-BNBVotfR.mjs";
3
3
 
4
4
  //#region src/scanner.d.ts
5
5
  declare function scanForIntents(root?: string): Promise<ScanResult>;
@@ -45,15 +45,14 @@ declare function findSkillFiles(dir: string): Array<string>;
45
45
  */
46
46
  declare function getDeps(pkgJson: Record<string, unknown>, includeDevDeps?: boolean): Array<string>;
47
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.
48
+ * Resolve the directory of a dependency by name. Tries createRequire first
49
+ * (handles pnpm symlinks), then falls back to walking up node_modules
50
+ * directories (handles packages with export maps that block ./package.json).
52
51
  */
53
- declare function resolveDepDir(depName: string, parentDir: string, parentName: string, nodeModulesDirs: string | Array<string>): string | null;
52
+ declare function resolveDepDir(depName: string, parentDir: string): string | null;
54
53
  /**
55
54
  * Parse YAML frontmatter from a file. Returns null if no frontmatter or on error.
56
55
  */
57
56
  declare function parseFrontmatter(filePath: string): Record<string, unknown> | null;
58
57
  //#endregion
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 };
58
+ export { 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, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { a as parseFrontmatter, n as findSkillFiles, o as resolveDepDir, r as getDeps } from "./utils-DY1eH2E_.mjs";
2
- import { t as scanForIntents } from "./scanner-f82qRq7h.mjs";
3
- import { t as checkStaleness } from "./staleness-D_ZiK4Tf.mjs";
4
- import { c as runSetupGithubActions, i as runAddLibraryBin, o as runEditPackageJson } from "./setup-CncHbQlb.mjs";
1
+ import { a as parseFrontmatter, n as findSkillFiles, o as resolveDepDir, r as getDeps } from "./utils-BfjM1mQe.mjs";
2
+ import { a as runEditPackageJson, s as runSetupGithubActions } from "./setup-J7F7DIP2.mjs";
3
+ import { t as scanForIntents } from "./scanner-SHzOJKcz.mjs";
4
+ import { t as checkStaleness } from "./staleness-DZKvsLVq.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";
@@ -269,4 +269,4 @@ function submitMetaFeedback(payload, opts) {
269
269
  }
270
270
 
271
271
  //#endregion
272
- export { checkStaleness, containsSecrets, findSkillFiles, getDeps, hasGhCli, metaToMarkdown, parseFrontmatter, resolveDepDir, resolveFrequency, runAddLibraryBin, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
272
+ export { checkStaleness, containsSecrets, findSkillFiles, getDeps, hasGhCli, metaToMarkdown, parseFrontmatter, resolveDepDir, resolveFrequency, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import "./utils-DY1eH2E_.mjs";
2
+ import "./utils-BfjM1mQe.mjs";
3
3
  import { t as INSTALL_PROMPT } from "./install-prompt-C0M-U3WZ.mjs";
4
4
  import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-DhsUxNJW.mjs";
5
- import { t as scanLibrary } from "./library-scanner-CU0OozQE.mjs";
5
+ import { t as scanLibrary } from "./library-scanner-CU3ZHPYU.mjs";
6
6
 
7
7
  //#region src/intent-library.ts
8
8
  async function cmdList() {
@@ -1,4 +1,4 @@
1
- import { a as parseFrontmatter, o as resolveDepDir, r as getDeps } from "./utils-DY1eH2E_.mjs";
1
+ import { a as parseFrontmatter, o as resolveDepDir, r as getDeps } from "./utils-BfjM1mQe.mjs";
2
2
  import { existsSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { dirname, join, relative, sep } from "node:path";
4
4
 
@@ -19,10 +19,12 @@ function findHomeDir(scriptPath) {
19
19
  dir = parent;
20
20
  }
21
21
  }
22
- function hasIntentBin(pkg) {
22
+ function isIntentPackage(pkg) {
23
+ const keywords = pkg.keywords;
24
+ if (Array.isArray(keywords) && keywords.includes("tanstack-intent")) return true;
23
25
  const bin = pkg.bin;
24
- if (!bin || typeof bin !== "object") return false;
25
- return "intent" in bin;
26
+ if (bin && typeof bin === "object" && "intent" in bin) return true;
27
+ return false;
26
28
  }
27
29
  function discoverSkills(skillsDir) {
28
30
  const skills = [];
@@ -57,8 +59,7 @@ function discoverSkills(skillsDir) {
57
59
  walk(skillsDir);
58
60
  return skills;
59
61
  }
60
- async function scanLibrary(scriptPath, projectRoot) {
61
- const nodeModulesDir = join(projectRoot ?? process.cwd(), "node_modules");
62
+ async function scanLibrary(scriptPath, _projectRoot) {
62
63
  const packages = [];
63
64
  const warnings = [];
64
65
  const visited = /* @__PURE__ */ new Set();
@@ -89,10 +90,10 @@ async function scanLibrary(scriptPath, projectRoot) {
89
90
  skills: existsSync(skillsDir) ? discoverSkills(skillsDir) : []
90
91
  });
91
92
  for (const depName of getDeps(pkg)) {
92
- const depDir = resolveDepDir(depName, dir, name, nodeModulesDir);
93
+ const depDir = resolveDepDir(depName, dir);
93
94
  if (!depDir) continue;
94
95
  const depPkg = readPkgJson(depDir);
95
- if (depPkg && hasIntentBin(depPkg)) processPackage(depName, depDir);
96
+ if (depPkg && isIntentPackage(depPkg)) processPackage(depName, depDir);
96
97
  }
97
98
  }
98
99
  processPackage(homeName, homeDir);
@@ -11,6 +11,6 @@ interface LibraryScanResult {
11
11
  packages: Array<LibraryPackage>;
12
12
  warnings: Array<string>;
13
13
  }
14
- declare function scanLibrary(scriptPath: string, projectRoot?: string): Promise<LibraryScanResult>;
14
+ declare function scanLibrary(scriptPath: string, _projectRoot?: string): Promise<LibraryScanResult>;
15
15
  //#endregion
16
16
  export { LibraryPackage, LibraryScanResult, scanLibrary };
@@ -1,4 +1,4 @@
1
- import "./utils-DY1eH2E_.mjs";
2
- import { t as scanLibrary } from "./library-scanner-CU0OozQE.mjs";
1
+ import "./utils-BfjM1mQe.mjs";
2
+ import { t as scanLibrary } from "./library-scanner-CU3ZHPYU.mjs";
3
3
 
4
4
  export { scanLibrary };
@@ -0,0 +1,5 @@
1
+ import "./utils-BfjM1mQe.mjs";
2
+ import "./setup-J7F7DIP2.mjs";
3
+ import { t as scanForIntents } from "./scanner-SHzOJKcz.mjs";
4
+
5
+ export { scanForIntents };
@@ -1,4 +1,5 @@
1
- import { a as parseFrontmatter, i as listNodeModulesPackageDirs, o as resolveDepDir, r as getDeps, t as detectGlobalNodeModules } from "./utils-DY1eH2E_.mjs";
1
+ import { a as parseFrontmatter, i as listNodeModulesPackageDirs, o as resolveDepDir, r as getDeps, t as detectGlobalNodeModules } from "./utils-BfjM1mQe.mjs";
2
+ import { i as resolveWorkspacePackages, n as findWorkspaceRoot, r as readWorkspacePatterns } from "./setup-J7F7DIP2.mjs";
2
3
  import { existsSync, readFileSync, readdirSync } from "node:fs";
3
4
  import { join, relative, sep } from "node:path";
4
5
 
@@ -6,10 +7,15 @@ import { join, relative, sep } from "node:path";
6
7
  function detectPackageManager(root) {
7
8
  if (existsSync(join(root, ".pnp.cjs")) || existsSync(join(root, ".pnp.js"))) throw new Error("Yarn PnP is not yet supported. Add `nodeLinker: node-modules` to your .yarnrc.yml to use intent.");
8
9
  if (existsSync(join(root, "deno.json")) && !existsSync(join(root, "node_modules"))) throw new Error("Deno without node_modules is not yet supported. Add `\"nodeModulesDir\": \"auto\"` to your deno.json to use intent.");
9
- if (existsSync(join(root, "pnpm-lock.yaml"))) return "pnpm";
10
- if (existsSync(join(root, "bun.lockb")) || existsSync(join(root, "bun.lock"))) return "bun";
11
- if (existsSync(join(root, "yarn.lock"))) return "yarn";
12
- if (existsSync(join(root, "package-lock.json"))) return "npm";
10
+ const dirsToCheck = [root];
11
+ const wsRoot = findWorkspaceRoot(root);
12
+ if (wsRoot && wsRoot !== root) dirsToCheck.push(wsRoot);
13
+ for (const dir of dirsToCheck) {
14
+ if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm";
15
+ if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock"))) return "bun";
16
+ if (existsSync(join(dir, "yarn.lock"))) return "yarn";
17
+ if (existsSync(join(dir, "package-lock.json"))) return "npm";
18
+ }
13
19
  return "unknown";
14
20
  }
15
21
  function validateIntentField(_pkgName, intent) {
@@ -186,7 +192,6 @@ async function scanForIntents(root) {
186
192
  source: explicitGlobalNodeModules ? "INTENT_GLOBAL_NODE_MODULES" : void 0
187
193
  }
188
194
  };
189
- const resolutionRoots = [nodeModulesDir];
190
195
  const packageIndexes = /* @__PURE__ */ new Map();
191
196
  const packageJsonCache = /* @__PURE__ */ new Map();
192
197
  const packageVariants = /* @__PURE__ */ new Map();
@@ -209,7 +214,6 @@ async function scanForIntents(root) {
209
214
  nodeModules.global.detected = Boolean(detected.path);
210
215
  nodeModules.global.exists = detected.path ? existsSync(detected.path) : false;
211
216
  }
212
- if (nodeModules.global.exists && nodeModules.global.path && nodeModules.global.path !== nodeModulesDir && !resolutionRoots.includes(nodeModules.global.path)) resolutionRoots.push(nodeModules.global.path);
213
217
  }
214
218
  function readPkgJson(dirPath) {
215
219
  if (packageJsonCache.has(dirPath)) return packageJsonCache.get(dirPath) ?? null;
@@ -280,7 +284,7 @@ async function scanForIntents(root) {
280
284
  return;
281
285
  }
282
286
  for (const depName of getDeps(pkgJson)) {
283
- const depDir = resolveDepDir(depName, pkgDir, pkgName, resolutionRoots);
287
+ const depDir = resolveDepDir(depName, pkgDir);
284
288
  if (!depDir || walkVisited.has(depDir)) continue;
285
289
  tryRegister(depDir, depName);
286
290
  walkDeps(depDir, depName);
@@ -297,11 +301,34 @@ async function scanForIntents(root) {
297
301
  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)}`);
298
302
  }
299
303
  if (!projectPkg) return;
300
- for (const depName of getDeps(projectPkg, true)) {
301
- const depDir = resolveDepDir(depName, projectRoot, depName, resolutionRoots);
302
- if (depDir && !walkVisited.has(depDir)) walkDeps(depDir, depName);
304
+ walkDepsFromPkgJson(projectPkg, projectRoot, true);
305
+ }
306
+ /** Resolve and walk deps listed in a package.json. */
307
+ function walkDepsFromPkgJson(pkgJson, fromDir, includeDevDeps = false) {
308
+ for (const depName of getDeps(pkgJson, includeDevDeps)) {
309
+ const depDir = resolveDepDir(depName, fromDir);
310
+ if (depDir && !walkVisited.has(depDir)) {
311
+ tryRegister(depDir, depName);
312
+ walkDeps(depDir, depName);
313
+ }
314
+ }
315
+ }
316
+ /**
317
+ * In monorepos, discover workspace packages and walk their deps.
318
+ * Handles pnpm monorepos (workspace-specific node_modules) and ensures
319
+ * transitive skills packages are found through workspace package dependencies.
320
+ */
321
+ function walkWorkspacePackages() {
322
+ const workspacePatterns = readWorkspacePatterns(projectRoot);
323
+ if (!workspacePatterns) return;
324
+ for (const wsDir of resolveWorkspacePackages(projectRoot, workspacePatterns)) {
325
+ const wsNodeModules = join(wsDir, "node_modules");
326
+ if (existsSync(wsNodeModules)) for (const dirPath of listNodeModulesPackageDirs(wsNodeModules)) tryRegister(dirPath, "unknown");
327
+ const wsPkg = readPkgJson(wsDir);
328
+ if (wsPkg) walkDepsFromPkgJson(wsPkg, wsDir);
303
329
  }
304
330
  }
331
+ walkWorkspacePackages();
305
332
  walkKnownPackages();
306
333
  walkProjectDeps();
307
334
  if (explicitGlobalNodeModules || packages.length === 0 || !nodeModules.local.exists) {
@@ -1,8 +1,4 @@
1
1
  //#region src/setup.d.ts
2
- interface AddLibraryBinResult {
3
- shim: string | null;
4
- skipped: string | null;
5
- }
6
2
  interface EditPackageJsonResult {
7
3
  added: Array<string>;
8
4
  alreadyPresent: Array<string>;
@@ -15,16 +11,20 @@ interface MonorepoResult<T> {
15
11
  package: string;
16
12
  result: T;
17
13
  }
18
- declare function runAddLibraryBin(root: string): AddLibraryBinResult;
19
14
  declare function runEditPackageJson(root: string): EditPackageJsonResult;
20
15
  declare function readWorkspacePatterns(root: string): Array<string> | null;
16
+ /**
17
+ * Resolve workspace glob patterns to actual package directories.
18
+ * Handles simple patterns like "packages/*" and "packages/**".
19
+ * Each resolved directory must contain a package.json.
20
+ */
21
+ declare function resolveWorkspacePackages(root: string, patterns: Array<string>): Array<string>;
21
22
  declare function findWorkspaceRoot(start: string): string | null;
22
23
  /**
23
24
  * Find workspace packages that contain at least one SKILL.md file.
24
25
  */
25
26
  declare function findPackagesWithSkills(root: string): Array<string>;
26
27
  declare function runEditPackageJsonAll(root: string): Array<MonorepoResult<EditPackageJsonResult>> | EditPackageJsonResult;
27
- declare function runAddLibraryBinAll(root: string): Array<MonorepoResult<AddLibraryBinResult>> | AddLibraryBinResult;
28
28
  declare function runSetupGithubActions(root: string, metaDir: string): SetupGithubActionsResult;
29
29
  //#endregion
30
- export { findPackagesWithSkills as a, runAddLibraryBin as c, runEditPackageJsonAll as d, runSetupGithubActions as f, SetupGithubActionsResult as i, runAddLibraryBinAll as l, EditPackageJsonResult as n, findWorkspaceRoot as o, MonorepoResult as r, readWorkspacePatterns as s, AddLibraryBinResult as t, runEditPackageJson as u };
30
+ export { findWorkspaceRoot as a, runEditPackageJson as c, findPackagesWithSkills as i, runEditPackageJsonAll as l, MonorepoResult as n, readWorkspacePatterns as o, SetupGithubActionsResult as r, resolveWorkspacePackages as s, EditPackageJsonResult as t, runSetupGithubActions as u };
@@ -1,4 +1,4 @@
1
- import { n as findSkillFiles } from "./utils-DY1eH2E_.mjs";
1
+ import { n as findSkillFiles } from "./utils-BfjM1mQe.mjs";
2
2
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
3
  import { basename, join, relative } from "node:path";
4
4
  import { parse } from "yaml";
@@ -86,64 +86,6 @@ function copyTemplates(srcDir, destDir, vars) {
86
86
  skipped
87
87
  };
88
88
  }
89
- function getShimContent(ext) {
90
- return `#!/usr/bin/env node
91
- // Auto-generated by @tanstack/intent setup
92
- // Exposes the intent end-user CLI for consumers of this library.
93
- // Commit this file, then add to your package.json:
94
- // "bin": { "intent": "./bin/intent.${ext}" }
95
- try {
96
- await import('@tanstack/intent/intent-library')
97
- } catch (e) {
98
- if (e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND') {
99
- console.error('@tanstack/intent is not installed.')
100
- console.error('')
101
- console.error('Install it as a dev dependency:')
102
- console.error(' npm add -D @tanstack/intent')
103
- console.error('')
104
- console.error('Or run directly:')
105
- console.error(' npx @tanstack/intent@latest list')
106
- process.exit(1)
107
- }
108
- throw e
109
- }
110
- `;
111
- }
112
- function detectShimExtension(root) {
113
- try {
114
- if (JSON.parse(readFileSync(join(root, "package.json"), "utf8")).type === "module") return "js";
115
- } catch (err) {
116
- if (!(err && typeof err === "object" && "code" in err && err.code === "ENOENT")) console.error(`Warning: could not read package.json: ${err instanceof Error ? err.message : err}`);
117
- }
118
- return "mjs";
119
- }
120
- function findExistingShim(root) {
121
- const shimJs = join(root, "bin", "intent.js");
122
- if (existsSync(shimJs)) return shimJs;
123
- const shimMjs = join(root, "bin", "intent.mjs");
124
- if (existsSync(shimMjs)) return shimMjs;
125
- return null;
126
- }
127
- function runAddLibraryBin(root) {
128
- const result = {
129
- shim: null,
130
- skipped: null
131
- };
132
- const existingShim = findExistingShim(root);
133
- if (existingShim) {
134
- result.skipped = existingShim;
135
- console.log(` Already exists: ${existingShim}`);
136
- return result;
137
- }
138
- const ext = detectShimExtension(root);
139
- const shimPath = join(root, "bin", `intent.${ext}`);
140
- mkdirSync(join(root, "bin"), { recursive: true });
141
- writeFileSync(shimPath, getShimContent(ext));
142
- result.shim = shimPath;
143
- console.log(`✓ Generated intent shim: ${shimPath}`);
144
- console.log(`\n Run \`npx @tanstack/intent edit-package-json\` to wire package.json.`);
145
- return result;
146
- }
147
89
  function runEditPackageJson(root) {
148
90
  const result = {
149
91
  added: [],
@@ -168,10 +110,10 @@ function runEditPackageJson(root) {
168
110
  const indentSize = indentMatch?.[1] ? indentMatch[1].length : 2;
169
111
  if (!Array.isArray(pkg.keywords)) pkg.keywords = [];
170
112
  const keywords = pkg.keywords;
171
- for (const kw of ["tanstack-intent"]) if (keywords.includes(kw)) result.alreadyPresent.push(`keywords: "${kw}"`);
113
+ if (keywords.includes("tanstack-intent")) result.alreadyPresent.push("keywords: \"tanstack-intent\"");
172
114
  else {
173
- keywords.push(kw);
174
- result.added.push(`keywords: "${kw}"`);
115
+ keywords.push("tanstack-intent");
116
+ result.added.push("keywords: \"tanstack-intent\"");
175
117
  }
176
118
  if (!Array.isArray(pkg.files)) pkg.files = [];
177
119
  const files = pkg.files;
@@ -191,39 +133,12 @@ function runEditPackageJson(root) {
191
133
  dir = next;
192
134
  }
193
135
  return false;
194
- })() ? ["skills", "bin"] : [
195
- "skills",
196
- "bin",
197
- "!skills/_artifacts"
198
- ];
136
+ })() ? ["skills"] : ["skills", "!skills/_artifacts"];
199
137
  for (const entry of requiredFiles) if (files.includes(entry)) result.alreadyPresent.push(`files: "${entry}"`);
200
138
  else {
201
139
  files.push(entry);
202
140
  result.added.push(`files: "${entry}"`);
203
141
  }
204
- const existingShim = findExistingShim(root);
205
- let ext;
206
- if (existingShim) ext = existingShim.endsWith(".mjs") ? "mjs" : "js";
207
- else ext = pkg.type === "module" ? "js" : "mjs";
208
- const shimRelative = `./bin/intent.${ext}`;
209
- if (typeof pkg.bin === "object" && pkg.bin !== null) {
210
- const binObj = pkg.bin;
211
- if (binObj.intent) result.alreadyPresent.push(`bin.intent`);
212
- else {
213
- binObj.intent = shimRelative;
214
- result.added.push(`bin.intent: "${shimRelative}"`);
215
- }
216
- } else if (!pkg.bin) {
217
- pkg.bin = { intent: shimRelative };
218
- result.added.push(`bin.intent: "${shimRelative}"`);
219
- } else if (typeof pkg.bin === "string") {
220
- const pkgName = typeof pkg.name === "string" ? pkg.name.replace(/^@[^/]+\//, "") : "unknown";
221
- pkg.bin = {
222
- [pkgName]: pkg.bin,
223
- intent: shimRelative
224
- };
225
- result.added.push(`bin.intent: "${shimRelative}" (converted bin from string to object)`);
226
- }
227
142
  writeFileSync(pkgPath, JSON.stringify(pkg, null, indentSize) + "\n");
228
143
  for (const a of result.added) console.log(`✓ Added ${a}`);
229
144
  for (const a of result.alreadyPresent) console.log(` Already present: ${a}`);
@@ -258,12 +173,19 @@ function resolveWorkspacePackages(root, patterns) {
258
173
  const baseDir = join(root, pattern.replace(/\/\*\*?(\/\*)?$/, ""));
259
174
  if (!existsSync(baseDir)) continue;
260
175
  if (pattern.includes("**")) collectPackageDirs(baseDir, dirs);
261
- else if (pattern.endsWith("/*")) for (const entry of readdirSync(baseDir, { withFileTypes: true })) {
262
- if (!entry.isDirectory()) continue;
263
- const dir = join(baseDir, entry.name);
264
- if (existsSync(join(dir, "package.json"))) dirs.push(dir);
265
- }
266
- else {
176
+ else if (pattern.endsWith("/*")) {
177
+ let entries;
178
+ try {
179
+ entries = readdirSync(baseDir, { withFileTypes: true });
180
+ } catch {
181
+ continue;
182
+ }
183
+ for (const entry of entries) {
184
+ if (!entry.isDirectory()) continue;
185
+ const dir = join(baseDir, entry.name);
186
+ if (existsSync(join(dir, "package.json"))) dirs.push(dir);
187
+ }
188
+ } else {
267
189
  const dir = join(root, pattern);
268
190
  if (existsSync(join(dir, "package.json"))) dirs.push(dir);
269
191
  }
@@ -330,9 +252,6 @@ function runForEachPackage(root, runOne) {
330
252
  function runEditPackageJsonAll(root) {
331
253
  return runForEachPackage(root, runEditPackageJson);
332
254
  }
333
- function runAddLibraryBinAll(root) {
334
- return runForEachPackage(root, runAddLibraryBin);
335
- }
336
255
  function runSetupGithubActions(root, metaDir) {
337
256
  const workspaceRoot = findWorkspaceRoot(root) ?? root;
338
257
  const packageDirs = findPackagesWithSkills(workspaceRoot);
@@ -357,4 +276,4 @@ function runSetupGithubActions(root, metaDir) {
357
276
  }
358
277
 
359
278
  //#endregion
360
- export { runAddLibraryBinAll as a, runSetupGithubActions as c, runAddLibraryBin as i, findWorkspaceRoot as n, runEditPackageJson as o, readWorkspacePatterns as r, runEditPackageJsonAll as s, findPackagesWithSkills as t };
279
+ export { runEditPackageJson as a, resolveWorkspacePackages as i, findWorkspaceRoot as n, runEditPackageJsonAll as o, readWorkspacePatterns as r, runSetupGithubActions as s, findPackagesWithSkills as t };
package/dist/setup.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as findPackagesWithSkills, c as runAddLibraryBin, d as runEditPackageJsonAll, f as runSetupGithubActions, i as SetupGithubActionsResult, l as runAddLibraryBinAll, n as EditPackageJsonResult, o as findWorkspaceRoot, r as MonorepoResult, s as readWorkspacePatterns, t as AddLibraryBinResult, u as runEditPackageJson } from "./setup-6m3IfxyO.mjs";
2
- export { AddLibraryBinResult, EditPackageJsonResult, MonorepoResult, SetupGithubActionsResult, findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, runAddLibraryBin, runAddLibraryBinAll, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
1
+ import { a as findWorkspaceRoot, c as runEditPackageJson, i as findPackagesWithSkills, l as runEditPackageJsonAll, n as MonorepoResult, o as readWorkspacePatterns, r as SetupGithubActionsResult, s as resolveWorkspacePackages, t as EditPackageJsonResult, u as runSetupGithubActions } from "./setup-BNBVotfR.mjs";
2
+ export { EditPackageJsonResult, MonorepoResult, SetupGithubActionsResult, findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, resolveWorkspacePackages, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
package/dist/setup.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import "./utils-DY1eH2E_.mjs";
2
- import { a as runAddLibraryBinAll, c as runSetupGithubActions, i as runAddLibraryBin, n as findWorkspaceRoot, o as runEditPackageJson, r as readWorkspacePatterns, s as runEditPackageJsonAll, t as findPackagesWithSkills } from "./setup-CncHbQlb.mjs";
1
+ import "./utils-BfjM1mQe.mjs";
2
+ import { a as runEditPackageJson, i as resolveWorkspacePackages, n as findWorkspaceRoot, o as runEditPackageJsonAll, r as readWorkspacePatterns, s as runSetupGithubActions, t as findPackagesWithSkills } from "./setup-J7F7DIP2.mjs";
3
3
 
4
- export { findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, runAddLibraryBin, runAddLibraryBinAll, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
4
+ export { findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, resolveWorkspacePackages, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
@@ -1,4 +1,4 @@
1
- import { a as parseFrontmatter, n as findSkillFiles } from "./utils-DY1eH2E_.mjs";
1
+ import { a as parseFrontmatter, n as findSkillFiles } from "./utils-BfjM1mQe.mjs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join, relative, sep } from "node:path";
4
4
 
@@ -0,0 +1,4 @@
1
+ import "./utils-BfjM1mQe.mjs";
2
+ import { t as checkStaleness } from "./staleness-DZKvsLVq.mjs";
3
+
4
+ export { checkStaleness };
@@ -1,4 +1,5 @@
1
- import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
1
+ import { createRequire } from "node:module";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
3
  import { dirname, join } from "node:path";
3
4
  import { execFileSync } from "node:child_process";
4
5
  import { parse } from "yaml";
@@ -107,30 +108,24 @@ function detectGlobalNodeModules(packageManager) {
107
108
  return { path: null };
108
109
  }
109
110
  /**
110
- * Resolve the directory of a dependency by name. First checks the top-level
111
- * node_modules (hoisted layout — npm, yarn, bun), then resolves through the
112
- * parent package's real path to handle pnpm's virtual store layout where
113
- * transitive deps are siblings in the .pnpm virtual store node_modules.
111
+ * Resolve the directory of a dependency by name. Tries createRequire first
112
+ * (handles pnpm symlinks), then falls back to walking up node_modules
113
+ * directories (handles packages with export maps that block ./package.json).
114
114
  */
115
- function resolveDepDir(depName, parentDir, parentName, nodeModulesDirs) {
116
- if (!parentName) return null;
117
- const roots = Array.isArray(nodeModulesDirs) ? nodeModulesDirs : [nodeModulesDirs];
118
- for (const nodeModulesDir of roots) {
119
- const topLevel = join(nodeModulesDir, depName);
120
- if (existsSync(join(topLevel, "package.json"))) return topLevel;
121
- }
122
- const nestedNodeModules = join(parentDir, "node_modules", depName);
123
- if (existsSync(join(nestedNodeModules, "package.json"))) return nestedNodeModules;
115
+ function resolveDepDir(depName, parentDir) {
124
116
  try {
125
- const realParent = realpathSync(parentDir);
126
- const segments = parentName.split("/").length;
127
- let nmDir = realParent;
128
- for (let i = 0; i < segments; i++) nmDir = dirname(nmDir);
129
- const nested = join(nmDir, depName);
130
- if (existsSync(join(nested, "package.json"))) return nested;
117
+ return dirname(createRequire(join(parentDir, "package.json")).resolve(join(depName, "package.json")));
131
118
  } catch (err) {
132
119
  const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
133
- if (code !== "ENOENT" && code !== "ENOTDIR") console.warn(`Warning: could not resolve ${depName} from ${parentDir}: ${err instanceof Error ? err.message : String(err)}`);
120
+ if (code && code !== "MODULE_NOT_FOUND" && code !== "ERR_PACKAGE_PATH_NOT_EXPORTED") console.warn(`Warning: could not resolve ${depName} from ${parentDir}: ${err instanceof Error ? err.message : String(err)}`);
121
+ }
122
+ let dir = parentDir;
123
+ while (true) {
124
+ const candidate = join(dir, "node_modules", depName);
125
+ if (existsSync(join(candidate, "package.json"))) return candidate;
126
+ const parent = dirname(dir);
127
+ if (parent === dir) break;
128
+ dir = parent;
134
129
  }
135
130
  return null;
136
131
  }
@@ -1,3 +1,3 @@
1
- import { a as parseFrontmatter, i as listNodeModulesPackageDirs, n as findSkillFiles, o as resolveDepDir, r as getDeps, t as detectGlobalNodeModules } from "./utils-DY1eH2E_.mjs";
1
+ import { a as parseFrontmatter, i as listNodeModulesPackageDirs, n as findSkillFiles, o as resolveDepDir, r as getDeps, t as detectGlobalNodeModules } from "./utils-BfjM1mQe.mjs";
2
2
 
3
3
  export { detectGlobalNodeModules, findSkillFiles, getDeps, listNodeModulesPackageDirs, parseFrontmatter, resolveDepDir };
@@ -1,11 +1,10 @@
1
1
  # notify-intent.yml — Drop this into your library repo's .github/workflows/
2
2
  #
3
- # Fires a repository_dispatch event to TanStack/intent whenever docs or
4
- # source files change on merge to main. This triggers the skill staleness
5
- # check workflow in the intent repo.
3
+ # Fires a repository_dispatch event whenever docs or source files change
4
+ # on merge to main. This triggers the skill staleness check workflow.
6
5
  #
7
6
  # Requirements:
8
- # - A fine-grained PAT with contents:write on TanStack/intent stored
7
+ # - A fine-grained PAT with contents:write on this repository stored
9
8
  # as the INTENT_NOTIFY_TOKEN repository secret.
10
9
  #
11
10
  # Template variables (replaced by `intent setup`):
@@ -13,7 +12,7 @@
13
12
  # {{DOCS_PATH}} — e.g. docs/**
14
13
  # {{SRC_PATH}} — e.g. packages/query-core/src/**
15
14
 
16
- name: Notify Intent
15
+ name: Trigger Skill Review
17
16
 
18
17
  on:
19
18
  push:
@@ -24,7 +23,7 @@ on:
24
23
 
25
24
  jobs:
26
25
  notify:
27
- name: Notify TanStack Intent
26
+ name: Trigger Skill Review
28
27
  runs-on: ubuntu-latest
29
28
  steps:
30
29
  - name: Checkout
@@ -42,7 +41,7 @@ jobs:
42
41
  uses: peter-evans/repository-dispatch@v3
43
42
  with:
44
43
  token: ${{ secrets.INTENT_NOTIFY_TOKEN }}
45
- repository: TanStack/intent
44
+ repository: ${{ github.repository }}
46
45
  event-type: skill-check
47
46
  client-payload: |
48
47
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/intent",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Ship compositional knowledge for AI coding agents alongside your npm packages",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,12 +30,15 @@
30
30
  "yaml": "^2.7.0"
31
31
  },
32
32
  "devDependencies": {
33
- "tsdown": "^0.19.0"
33
+ "@verdaccio/node-api": "6.0.0-6-next.76",
34
+ "tsdown": "^0.19.0",
35
+ "verdaccio": "^6.3.2"
34
36
  },
35
37
  "scripts": {
36
38
  "prepack": "npm run build",
37
39
  "build": "tsdown src/index.ts src/cli.ts src/setup.ts src/intent-library.ts src/library-scanner.ts --format esm --dts",
38
- "test:lib": "vitest run",
40
+ "test:lib": "vitest run --exclude 'tests/integration/**'",
41
+ "test:integration": "vitest run tests/integration/",
39
42
  "test:types": "tsc --noEmit"
40
43
  }
41
44
  }
@@ -1,4 +0,0 @@
1
- import "./utils-DY1eH2E_.mjs";
2
- import { t as scanForIntents } from "./scanner-f82qRq7h.mjs";
3
-
4
- export { scanForIntents };
@@ -1,4 +0,0 @@
1
- import "./utils-DY1eH2E_.mjs";
2
- import { t as checkStaleness } from "./staleness-D_ZiK4Tf.mjs";
3
-
4
- export { checkStaleness };