@tanstack/intent 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,16 +50,16 @@ npx intent setup
50
50
 
51
51
  ## CLI Commands
52
52
 
53
- | Command | Description |
54
- | ------------------------ | ------------------------------------------------ |
55
- | `intent init` | Inject intent discovery into agent config files |
56
- | `intent list [--json]` | Discover intent-enabled packages |
57
- | `intent meta` | List meta-skills for library maintainers |
58
- | `intent scaffold` | Print the guided skill generation prompt |
59
- | `intent validate [dir]` | Validate SKILL.md files |
60
- | `intent setup` | Copy CI/Oz workflow templates |
61
- | `intent stale [--json]` | Check skills for version drift |
62
- | `intent feedback` | Submit skill feedback |
53
+ | Command | Description |
54
+ | ----------------------- | ----------------------------------------------- |
55
+ | `intent init` | Inject intent discovery into agent config files |
56
+ | `intent list [--json]` | Discover intent-enabled packages |
57
+ | `intent meta` | List meta-skills for library maintainers |
58
+ | `intent scaffold` | Print the guided skill generation prompt |
59
+ | `intent validate [dir]` | Validate SKILL.md files |
60
+ | `intent setup` | Copy CI/Oz workflow templates |
61
+ | `intent stale [--json]` | Check skills for version drift |
62
+ | `intent feedback` | Submit skill feedback |
63
63
 
64
64
  ## License
65
65
 
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
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-BwCyu1Jq.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";
@@ -12,6 +12,55 @@ import { fileURLToPath } from "node:url";
12
12
  function getMetaDir() {
13
13
  return join(dirname(fileURLToPath(import.meta.url)), "..", "meta");
14
14
  }
15
+ function padColumn(text, width) {
16
+ return text.length >= width ? text + " " : text.padEnd(width);
17
+ }
18
+ function printTable(headers, rows) {
19
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)) + 2);
20
+ const headerLine = headers.map((h, i) => padColumn(h, widths[i])).join("");
21
+ const separator = widths.map((w) => "─".repeat(w)).join("");
22
+ console.log(headerLine);
23
+ console.log(separator);
24
+ for (const row of rows) console.log(row.map((cell, i) => padColumn(cell, widths[i])).join(""));
25
+ }
26
+ function printSkillTree(skills, opts) {
27
+ const roots = [];
28
+ const children = /* @__PURE__ */ new Map();
29
+ for (const skill of skills) {
30
+ const slashIdx = skill.name.indexOf("/");
31
+ if (slashIdx === -1) roots.push(skill.name);
32
+ else {
33
+ const parent = skill.name.slice(0, slashIdx);
34
+ if (!children.has(parent)) children.set(parent, []);
35
+ children.get(parent).push(skill);
36
+ }
37
+ }
38
+ if (roots.length === 0) {
39
+ for (const skill of skills) if (!roots.includes(skill.name)) roots.push(skill.name);
40
+ }
41
+ for (const rootName of roots) {
42
+ const rootSkill = skills.find((s) => s.name === rootName);
43
+ if (!rootSkill) continue;
44
+ printSkillLine(rootName, rootSkill, 4, opts);
45
+ for (const sub of children.get(rootName) ?? []) printSkillLine(sub.name.slice(sub.name.indexOf("/") + 1), sub, 6, opts);
46
+ }
47
+ }
48
+ function printSkillLine(displayName, skill, indent, opts) {
49
+ const nameStr = " ".repeat(indent) + displayName;
50
+ const padding = " ".repeat(Math.max(2, opts.nameWidth - nameStr.length));
51
+ const typeCol = opts.showTypes ? (skill.type ? `[${skill.type}]` : "").padEnd(14) : "";
52
+ console.log(`${nameStr}${padding}${typeCol}${skill.description}`);
53
+ }
54
+ function computeSkillNameWidth(allPackageSkills) {
55
+ let max = 0;
56
+ for (const skills of allPackageSkills) for (const s of skills) {
57
+ const slashIdx = s.name.indexOf("/");
58
+ const displayName = slashIdx === -1 ? s.name : s.name.slice(slashIdx + 1);
59
+ const indent = slashIdx === -1 ? 4 : 6;
60
+ max = Math.max(max, indent + displayName.length);
61
+ }
62
+ return max + 2;
63
+ }
15
64
  async function cmdList(args) {
16
65
  const jsonOutput = args.includes("--json");
17
66
  let result;
@@ -33,14 +82,28 @@ async function cmdList(args) {
33
82
  }
34
83
  return;
35
84
  }
36
- console.log(`Intent-enabled packages (${result.packages.length} found):\n`);
85
+ const totalSkills = result.packages.reduce((sum, p) => sum + p.skills.length, 0);
86
+ console.log(`\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`);
87
+ printTable([
88
+ "PACKAGE",
89
+ "VERSION",
90
+ "SKILLS",
91
+ "REQUIRES"
92
+ ], result.packages.map((pkg) => [
93
+ pkg.name,
94
+ pkg.version,
95
+ String(pkg.skills.length),
96
+ pkg.intent.requires?.join(", ") || "–"
97
+ ]));
98
+ const nameWidth = computeSkillNameWidth(result.packages.map((p) => p.skills));
99
+ const showTypes = result.packages.some((p) => p.skills.some((s) => s.type));
100
+ console.log(`\nSkills:\n`);
37
101
  for (const pkg of result.packages) {
38
- const reqStr = pkg.intent.requires?.length ? ` (requires: ${pkg.intent.requires.join(", ")})` : "";
39
- console.log(`${pkg.name} v${pkg.version}${reqStr}`);
40
- for (const skill of pkg.skills) {
41
- const desc = skill.description ? ` ${skill.description}` : "";
42
- console.log(` ${skill.name.padEnd(32)}${desc}`);
43
- }
102
+ console.log(` ${pkg.name}`);
103
+ printSkillTree(pkg.skills, {
104
+ nameWidth,
105
+ showTypes
106
+ });
44
107
  console.log();
45
108
  }
46
109
  if (result.warnings.length > 0) {
@@ -276,8 +339,8 @@ switch (command) {
276
339
  cmdScaffold();
277
340
  break;
278
341
  case "stale": {
279
- const { checkStaleness } = await import("./staleness-DyhsrqQ5.mjs");
280
- const { scanForIntents: scanStale } = await import("./scanner-BuWPDJ4P.mjs");
342
+ const { checkStaleness } = await import("./staleness-B5gUj7FR.mjs");
343
+ const { scanForIntents: scanStale } = await import("./scanner-fAWJUn6Q.mjs");
281
344
  let staleResult;
282
345
  try {
283
346
  staleResult = await scanStale();
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
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";
1
+ import { n as parseFrontmatter, t as findSkillFiles } from "./utils-DH3jY3CI.mjs";
2
+ import { t as scanForIntents } from "./scanner-BwCyu1Jq.mjs";
3
+ import { t as checkStaleness } from "./staleness-lP6B0O4z.mjs";
4
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
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
6
  import { t as runSetup } from "./setup-CNGz26qL.mjs";
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./utils-DjkEPBxu.mjs";
3
- import { t as scanLibrary } from "./library-scanner-BrznE00j.mjs";
4
- import { spawnSync } from "node:child_process";
5
- import { release } from "node:os";
2
+ import "./utils-DH3jY3CI.mjs";
3
+ import { t as scanLibrary } from "./library-scanner-D0aP7is_.mjs";
6
4
 
7
5
  //#region src/intent-library.ts
8
6
  async function cmdList() {
@@ -37,18 +35,7 @@ async function cmdList() {
37
35
  }
38
36
  }
39
37
  function cmdInstall() {
40
- function tryCopyToClipboard(text) {
41
- const platform = process.platform;
42
- const isWsl = platform === "linux" && (Boolean(process.env.WSL_DISTRO_NAME) || Boolean(process.env.WSL_INTEROP) || release().toLowerCase().includes("microsoft"));
43
- const tryCommand = (command$1, args = []) => {
44
- return spawnSync(command$1, args, { input: text }).status === 0;
45
- };
46
- if (platform === "darwin") return tryCommand("pbcopy");
47
- if (platform === "win32") return tryCommand("clip");
48
- if (isWsl) return tryCommand("clip.exe");
49
- return tryCommand("wl-copy") || tryCommand("xclip", ["-selection", "clipboard"]) || tryCommand("xsel", ["--clipboard", "--input"]);
50
- }
51
- const prompt = `You are an AI assistant helping a developer set up skill-to-task mappings for their project.
38
+ console.log(`You are an AI assistant helping a developer set up skill-to-task mappings for their project.
52
39
 
53
40
  Follow these steps in order:
54
41
 
@@ -93,18 +80,14 @@ skills:
93
80
  - Use the user's own words for task descriptions
94
81
  - Include the exact path from \`intent list\` output so agents can load it directly
95
82
  - Keep entries concise — this block is read on every agent task
96
- - Preserve all content outside the block tags unchanged`;
97
- console.log("🚀 Intent Install");
98
- console.log("✨ Copy the prompt below into your AI agent:\n");
99
- console.log(prompt);
100
- if (tryCopyToClipboard(prompt)) console.log("\n✅ Copied prompt to clipboard");
101
- else console.log("\n⚠ Tip: Manually copy the prompt above into your agent");
83
+ - Preserve all content outside the block tags unchanged`);
102
84
  }
103
85
  const USAGE = `TanStack Intent
104
86
 
105
87
  Usage:
106
88
  intent list List all available skills from this library and its dependencies
107
- intent install Set up skill-to-task mappings in your agent config`;
89
+ intent install Print a skill that guides your coding agent to scan the project
90
+ and set up skill-to-task mappings in your agent config`;
108
91
  const command = process.argv[2];
109
92
  switch (command) {
110
93
  case "list":
@@ -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 "./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 };
@@ -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,15 @@ function validateIntentField(pkgName, intent) {
26
26
  requires
27
27
  };
28
28
  }
29
- function discoverSkills(skillsDir, baseName) {
29
+ function discoverSkills(skillsDir, _baseName) {
30
30
  const skills = [];
31
31
  function walk(dir) {
32
32
  let entries;
33
33
  try {
34
- entries = readdirSync(dir, { withFileTypes: true });
34
+ entries = readdirSync(dir, {
35
+ withFileTypes: true,
36
+ encoding: "utf8"
37
+ });
35
38
  } catch {
36
39
  return;
37
40
  }
@@ -86,7 +89,10 @@ async function scanForIntents(root) {
86
89
  const packageDirs = [];
87
90
  let topEntries;
88
91
  try {
89
- topEntries = readdirSync(nodeModulesDir, { withFileTypes: true });
92
+ topEntries = readdirSync(nodeModulesDir, {
93
+ withFileTypes: true,
94
+ encoding: "utf8"
95
+ });
90
96
  } catch {
91
97
  return {
92
98
  packageManager,
@@ -100,7 +106,10 @@ async function scanForIntents(root) {
100
106
  if (entry.name.startsWith("@")) {
101
107
  let scopedEntries;
102
108
  try {
103
- scopedEntries = readdirSync(dirPath, { withFileTypes: true });
109
+ scopedEntries = readdirSync(dirPath, {
110
+ withFileTypes: true,
111
+ encoding: "utf8"
112
+ });
104
113
  } catch {
105
114
  continue;
106
115
  }
@@ -0,0 +1,4 @@
1
+ import "./utils-DH3jY3CI.mjs";
2
+ import { t as scanForIntents } from "./scanner-BwCyu1Jq.mjs";
3
+
4
+ export { scanForIntents };
@@ -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
 
@@ -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 {
@@ -64,7 +64,7 @@ Log (but do not group yet):
64
64
  - What the library does in one sentence
65
65
  - The core abstractions a developer interacts with
66
66
  - Which frameworks it supports
67
- - Any existing skill files, agent configs, or playbooks
67
+ - Any existing skill files, agent configs, or intents
68
68
  - Whether the library is a monorepo and which packages matter
69
69
 
70
70
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/intent",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Ship compositional knowledge for AI coding agents alongside your npm packages",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsdown src/index.ts src/cli.ts src/setup.ts src/intent-library.ts src/library-scanner.ts --format esm --dts",
36
- "test:lib": "vitest run"
36
+ "test:lib": "vitest run",
37
+ "test:types": "tsc --noEmit"
37
38
  }
38
39
  }
@@ -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 };