Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/keyword-based-detection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/intent': patch
---

Replace bin.intent detection with tanstack-intent keyword check for package discovery. Remove the `add-library-bin` command and bin shim generation system — packages are now identified by having `"tanstack-intent"` in their keywords array, which was already required for registry discovery. Also fix `collectPackagingWarnings` to skip the `!skills/_artifacts` warning for monorepo packages.
1 change: 0 additions & 1 deletion docs/cli/intent-scaffold.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ The prompt also includes a post-generation checklist:
- Commit generated `skills/` and `skills/_artifacts/`
- Ensure `@tanstack/intent` is in `devDependencies`
- Run setup commands as needed:
- `npx @tanstack/intent@latest add-library-bin`
- `npx @tanstack/intent@latest edit-package-json`
- `npx @tanstack/intent@latest setup-github-actions`

Expand Down
19 changes: 6 additions & 13 deletions docs/cli/intent-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,25 @@ title: setup commands
id: intent-setup
---

Intent exposes setup as three separate commands.
Intent exposes setup as two separate commands.

```bash
npx @tanstack/intent@latest add-library-bin
npx @tanstack/intent@latest edit-package-json
npx @tanstack/intent@latest setup-github-actions
```

## Commands

- `add-library-bin`: create a package-local `intent` shim in `bin/`
- `edit-package-json`: add or normalize `package.json` entries needed to publish skills
- `setup-github-actions`: copy workflow templates to `.github/workflows`

## What each command changes

- `add-library-bin`
- Creates `bin/intent.js` when `package.json.type` is `module`, otherwise `bin/intent.mjs`
- If either shim already exists, command skips creation
- Shim imports `@tanstack/intent/intent-library`
- `edit-package-json`
- Requires a valid `package.json` in current directory
- Ensures `bin.intent` points to `./bin/intent.<ext>`
- Ensures `keywords` includes `tanstack-intent`
- Ensures `files` includes required publish entries
- Preserves existing indentation and existing `bin` entries
- Converts string shorthand `bin` to object when needed
- Preserves existing indentation
- `setup-github-actions`
- Copies templates from `@tanstack/intent/meta/templates/workflows` to `.github/workflows`
- Applies variable substitution for `PACKAGE_NAME`, `REPO`, `DOCS_PATH`, `SRC_PATH`
Expand All @@ -38,8 +31,8 @@ npx @tanstack/intent@latest setup-github-actions

`edit-package-json` enforces different `files` sets based on package location:

- Monorepo package: `skills`, `bin`
- Non-monorepo package: `skills`, `bin`, `!skills/_artifacts`
- Monorepo package: `skills`
- Non-monorepo package: `skills`, `!skills/_artifacts`

## Common errors

Expand All @@ -48,7 +41,7 @@ npx @tanstack/intent@latest setup-github-actions

## Notes

- `add-library-bin` and `setup-github-actions` skip existing files
- `setup-github-actions` skips existing files

## Related

Expand Down
4 changes: 1 addition & 3 deletions docs/cli/intent-validate.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ If `<dir>/_artifacts` exists, it also validates artifacts:
Packaging warnings are always computed from `package.json` in the current working directory:

- `@tanstack/intent` missing from `devDependencies`
- Missing `bin.intent` entry
- Missing shim (`bin/intent.js` or `bin/intent.mjs`)
- Missing `tanstack-intent` in keywords array
- Missing `files` entries when `files` array exists:
- `skills`
- `bin`
- `!skills/_artifacts`

Warnings are informational; they are printed on both pass and fail paths.
Expand Down
12 changes: 2 additions & 10 deletions docs/getting-started/quick-start-maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ Or run commands without installing:
npx @tanstack/intent@latest scaffold
```

> [!WARNING]
> When using `npx` or `bunx`, always include `@latest`. Intent-enabled libraries ship a local `intent` binary shim, and without `@latest`, your package manager may resolve to that shim instead of the real CLI.
---

## Initial Setup (With Agent)
Expand Down Expand Up @@ -101,9 +98,6 @@ Artifacts enforce a consistent skill structure across versions, making it easier
Run these commands to prepare your package for skill publishing:

```bash
# Generate the bin shim that consumers use for discovery
npx @tanstack/intent@latest add-library-bin

# Update package.json with required fields
npx @tanstack/intent@latest edit-package-json

Expand All @@ -113,11 +107,9 @@ npx @tanstack/intent@latest setup-github-actions

**What these do:**

- `add-library-bin` creates `bin/intent.js` or `bin/intent.mjs` — a shim that lets consumers run `npx your-package intent` to access Intent CLI features
- `edit-package-json` adds:
- `intent` field in package.json with version, repo, and docs metadata
- `bin.intent` entry pointing to the shim
- `files` array entries for `skills/` and `bin/`
- `tanstack-intent` keyword (used for package detection and registry discovery)
- `files` array entries for `skills/`
- For single packages: also adds `!skills/_artifacts` to exclude artifacts from npm
- For monorepos: skips the artifacts exclusion (artifacts live at repo root)
- `setup-github-actions` copies workflow templates to `.github/workflows/` for automated validation and staleness checking
Expand Down
2 changes: 1 addition & 1 deletion packages/intent/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/intent",
"version": "0.0.19",
"version": "0.0.20",
"description": "Ship compositional knowledge for AI coding agents alongside your npm packages",
"license": "MIT",
"type": "module",
Expand Down
68 changes: 35 additions & 33 deletions packages/intent/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,9 @@ function collectPackagingWarnings(root: string): Array<string> {
warnings.push('@tanstack/intent is not in devDependencies')
}

const bin = pkgJson.bin as Record<string, string> | undefined
if (!bin?.intent) {
warnings.push('Missing "bin": { "intent": ... } entry in package.json')
}

const shimJs = join(root, 'bin', 'intent.js')
const shimMjs = join(root, 'bin', 'intent.mjs')
if (!existsSync(shimJs) && !existsSync(shimMjs)) {
warnings.push(
'No bin/intent.js or bin/intent.mjs shim found (run: npx @tanstack/intent add-library-bin)',
)
const keywords = pkgJson.keywords
if (!Array.isArray(keywords) || !keywords.includes('tanstack-intent')) {
warnings.push('Missing "tanstack-intent" in keywords array')
}

const files = pkgJson.files as Array<string> | undefined
Expand All @@ -264,12 +256,32 @@ function collectPackagingWarnings(root: string): Array<string> {
'"skills" is not in the "files" array — skills won\'t be published',
)
}
if (!files.includes('bin')) {
warnings.push(
'"bin" is not in the "files" array — shim won\'t be published',
)
}
if (!files.includes('!skills/_artifacts')) {

// Only warn about !skills/_artifacts for non-monorepo packages.
// In monorepos, artifacts live at the repo root, so the negation
// pattern is intentionally omitted by edit-package-json.
const isMonorepoPkg = (() => {
let dir = join(root, '..')
for (let i = 0; i < 5; i++) {
const parentPkg = join(dir, 'package.json')
if (existsSync(parentPkg)) {
try {
const parent = JSON.parse(readFileSync(parentPkg, 'utf8'))
return (
Array.isArray(parent.workspaces) || parent.workspaces?.packages
)
} catch {
return false
}
}
const next = dirname(dir)
if (next === dir) break
dir = next
}
return false
})()

if (!isMonorepoPkg && !files.includes('!skills/_artifacts')) {
warnings.push(
'"!skills/_artifacts" is not in the "files" array — artifacts will be published unnecessarily',
)
Expand Down Expand Up @@ -557,11 +569,10 @@ This produces: individual SKILL.md files.

1. Run \`intent validate\` in each package directory
2. Commit skills/ and artifacts
3. For each publishable package, run: \`npx @tanstack/intent add-library-bin\`
4. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
5. Ensure each package has \`@tanstack/intent\` as a devDependency
6. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
7. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
3. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
4. Ensure each package has \`@tanstack/intent\` as a devDependency
5. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
6. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
`

console.log(prompt)
Expand All @@ -579,8 +590,7 @@ Usage:
intent validate [<dir>] Validate skill files (default: skills/)
intent install Print a skill that guides your coding agent to set up skill-to-task mappings
intent scaffold Print maintainer scaffold prompt
intent add-library-bin Generate bin/intent.{js,mjs} bridge file
intent edit-package-json Wire package.json (files, bin) for skill publishing
intent edit-package-json Wire package.json (files, keywords) for skill publishing
intent setup-github-actions Copy CI workflow templates to .github/workflows/
intent stale [dir] [--json] Check skills for staleness`

Expand Down Expand Up @@ -618,12 +628,9 @@ Examples:
intent stale
intent stale packages/query
intent stale --json`,
'add-library-bin': `intent add-library-bin

Generate bin/intent.{js,mjs} bridge files for publishable packages.`,
'edit-package-json': `intent edit-package-json

Update package.json files so skills and shims are published.`,
Update package.json files so skills are published.`,
'setup-github-actions': `intent setup-github-actions

Copy Intent CI workflow templates into .github/workflows/.`,
Expand Down Expand Up @@ -719,11 +726,6 @@ export async function main(argv: Array<string> = process.argv.slice(2)) {
}
return 0
}
case 'add-library-bin': {
const { runAddLibraryBinAll } = await import('./setup.js')
runAddLibraryBinAll(process.cwd())
return 0
}
case 'edit-package-json': {
const { runEditPackageJsonAll } = await import('./setup.js')
runEditPackageJsonAll(process.cwd())
Expand Down
7 changes: 1 addition & 6 deletions packages/intent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@ export {
parseFrontmatter,
resolveDepDir,
} from './utils.js'
export {
runAddLibraryBin,
runEditPackageJson,
runSetupGithubActions,
} from './setup.js'
export { runEditPackageJson, runSetupGithubActions } from './setup.js'
export type {
AddLibraryBinResult,
EditPackageJsonResult,
SetupGithubActionsResult,
} from './setup.js'
Expand Down
20 changes: 16 additions & 4 deletions packages/intent/src/library-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,22 @@ function findHomeDir(scriptPath: string): string | null {
}
}

function hasIntentBin(pkg: Record<string, unknown>): boolean {
function isIntentPackage(pkg: Record<string, unknown>): boolean {
const keywords = pkg.keywords
if (Array.isArray(keywords) && keywords.includes('tanstack-intent')) {
return true
}
// Legacy fallback: packages published before the keyword-based detection
// change may only have bin.intent. Keep this until a breaking release.
const bin = pkg.bin
if (!bin || typeof bin !== 'object') return false
return 'intent' in (bin as Record<string, unknown>)
if (
bin &&
typeof bin === 'object' &&
'intent' in (bin as Record<string, unknown>)
) {
return true
}
return false
}

function discoverSkills(skillsDir: string): Array<SkillEntry> {
Expand Down Expand Up @@ -134,7 +146,7 @@ export async function scanLibrary(
const depDir = resolveDepDir(depName, dir)
if (!depDir) continue
const depPkg = readPkgJson(depDir)
if (depPkg && hasIntentBin(depPkg)) {
if (depPkg && isIntentPackage(depPkg)) {
processPackage(depName, depDir)
}
}
Expand Down
Loading
Loading