@tanstack/intent 0.0.14 → 0.0.20
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 +42 -5
- package/dist/cli.d.mts +6 -1
- package/dist/cli.mjs +253 -170
- package/dist/display-CuCDLPP_.mjs +3 -0
- package/dist/index.d.mts +10 -11
- package/dist/index.mjs +37 -14
- package/dist/install-prompt-C0M-U3WZ.mjs +59 -0
- package/dist/intent-library.mjs +5 -49
- package/dist/{library-scanner-B1tmOzwf.mjs → library-scanner-DBOEhfm8.mjs} +4 -5
- package/dist/library-scanner.d.mts +5 -5
- package/dist/library-scanner.mjs +2 -2
- package/dist/scanner-BHPl60jH.mjs +5 -0
- package/dist/scanner-DVepyEwz.mjs +365 -0
- package/dist/setup-B-zdCBu4.d.mts +36 -0
- package/dist/setup-mGV2dZrq.mjs +367 -0
- package/dist/setup.d.mts +2 -2
- package/dist/setup.mjs +3 -2
- package/dist/{staleness-DJfMKH62.mjs → staleness-DZKvsLVq.mjs} +24 -3
- package/dist/staleness-Dr5-5wj5.mjs +4 -0
- package/dist/{types-BmnI8kFB.d.mts → types-ddLtccfV.d.mts} +30 -7
- package/dist/utils-BfjM1mQe.mjs +152 -0
- package/dist/utils-D7OKi0Rn.mjs +3 -0
- package/meta/domain-discovery/SKILL.md +95 -20
- package/meta/feedback-collection/SKILL.md +20 -1
- package/meta/generate-skill/SKILL.md +56 -5
- package/meta/templates/workflows/check-skills.yml +4 -4
- package/meta/templates/workflows/{notify-playbooks.yml → notify-intent.yml} +4 -4
- package/meta/tree-generator/SKILL.md +2 -2
- package/package.json +9 -5
- package/dist/scanner-CECGXgox.mjs +0 -4
- package/dist/scanner-CY40iozO.mjs +0 -218
- package/dist/setup-CANkTz55.d.mts +0 -18
- package/dist/setup-Nif1-nhS.mjs +0 -211
- package/dist/staleness-C1h7RuZ9.mjs +0 -4
- package/dist/utils-CDJzAdjD.mjs +0 -79
- /package/dist/{display-D_XzuGnu.mjs → display-DhsUxNJW.mjs} +0 -0
package/README.md
CHANGED
|
@@ -10,9 +10,9 @@ Docs target humans who browse. Types check individual API calls but can't encode
|
|
|
10
10
|
|
|
11
11
|
The ecosystem already moves toward agent-readable knowledge — Cursor rules, CLAUDE.md files, skills directories. But delivery is stuck in copy-paste: hunt for a community-maintained rules file, paste it into your config, repeat for every tool. No versioning, no update path, no staleness signal.
|
|
12
12
|
|
|
13
|
-
## Skills: versioned knowledge in
|
|
13
|
+
## Skills: versioned knowledge in your package manager
|
|
14
14
|
|
|
15
|
-
A skill is a short, versioned document that tells agents how to use a specific capability of your library — correct patterns, common mistakes, and when to apply them. Skills ship inside your
|
|
15
|
+
A skill is a short, versioned document that tells agents how to use a specific capability of your library — correct patterns, common mistakes, and when to apply them. Skills ship inside your package and travel with the tool via your normal package manager update flow — not the model's training cutoff, not community-maintained rules files, not prompt snippets in READMEs. Versioned knowledge the maintainer owns, updated when the package updates.
|
|
16
16
|
|
|
17
17
|
Each skill declares its source docs. When those docs change, the CLI flags the skill for review. One source of truth, one derived artifact that stays in sync.
|
|
18
18
|
|
|
@@ -20,6 +20,18 @@ The [Agent Skills spec](https://agentskills.io) is an open standard already adop
|
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
|
+
### Command runners
|
|
24
|
+
|
|
25
|
+
Use whichever command runner matches your environment:
|
|
26
|
+
|
|
27
|
+
| Tool | Pattern |
|
|
28
|
+
| ---- | -------------------------------------------- |
|
|
29
|
+
| npm | `npx @tanstack/intent@latest <command>` |
|
|
30
|
+
| pnpm | `pnpm dlx @tanstack/intent@latest <command>` |
|
|
31
|
+
| bun | `bunx @tanstack/intent@latest <command>` |
|
|
32
|
+
|
|
33
|
+
If you use Deno, support is best-effort today via `npm:` interop with `node_modules` enabled. First-class Deno runtime support is not implemented yet.
|
|
34
|
+
|
|
23
35
|
### For library consumers
|
|
24
36
|
|
|
25
37
|
Set up skill-to-task mappings in your project's agent config files (CLAUDE.md, .cursorrules, etc.):
|
|
@@ -28,7 +40,7 @@ Set up skill-to-task mappings in your project's agent config files (CLAUDE.md, .
|
|
|
28
40
|
npx @tanstack/intent@latest install
|
|
29
41
|
```
|
|
30
42
|
|
|
31
|
-
No per-library setup. No hunting for rules files. Install the package, run `npx @tanstack/intent@latest install
|
|
43
|
+
No per-library setup. No hunting for rules files. Install the package, run `npx @tanstack/intent@latest install` through your preferred command runner, and the agent understands the tool. Update the package, and skills update too.
|
|
32
44
|
|
|
33
45
|
List available skills from installed packages:
|
|
34
46
|
|
|
@@ -52,23 +64,48 @@ Validate your skill files:
|
|
|
52
64
|
npx @tanstack/intent@latest validate
|
|
53
65
|
```
|
|
54
66
|
|
|
67
|
+
In a monorepo, you can validate a package from the repo root:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx @tanstack/intent@latest validate packages/router/skills
|
|
71
|
+
```
|
|
72
|
+
|
|
55
73
|
Check for skills that have fallen behind their sources:
|
|
56
74
|
|
|
57
75
|
```bash
|
|
58
76
|
npx @tanstack/intent@latest stale
|
|
59
77
|
```
|
|
60
78
|
|
|
79
|
+
From a monorepo root, `intent stale` checks every workspace package that ships skills. To scope it to one package, pass a directory like `intent stale packages/router`.
|
|
80
|
+
|
|
61
81
|
Copy CI workflow templates into your repo so validation and staleness checks run on every push:
|
|
62
82
|
|
|
63
83
|
```bash
|
|
64
84
|
npx @tanstack/intent@latest setup-github-actions
|
|
65
85
|
```
|
|
66
86
|
|
|
87
|
+
## Compatibility
|
|
88
|
+
|
|
89
|
+
| Environment | Status | Notes |
|
|
90
|
+
| -------------- | ----------- | -------------------------------------------------- |
|
|
91
|
+
| Node.js + npm | Supported | Use `npx @tanstack/intent@latest <command>` |
|
|
92
|
+
| Node.js + pnpm | Supported | Use `pnpm dlx @tanstack/intent@latest <command>` |
|
|
93
|
+
| Node.js + Bun | Supported | Use `bunx @tanstack/intent@latest <command>` |
|
|
94
|
+
| Deno | Best-effort | Requires `npm:` interop and `node_modules` support |
|
|
95
|
+
| Yarn PnP | Unsupported | `@tanstack/intent` scans `node_modules` |
|
|
96
|
+
|
|
97
|
+
## Monorepos
|
|
98
|
+
|
|
99
|
+
- Run `npx @tanstack/intent@latest setup-github-actions` from either the repo root or a package directory. Intent detects the workspace root and writes workflows to the repo-level `.github/workflows/` directory.
|
|
100
|
+
- Generated workflows are monorepo-aware: validation loops over workspace packages with skills, staleness checks run from the workspace root, and notify workflows watch package `src/` and docs paths.
|
|
101
|
+
- Run `npx @tanstack/intent@latest validate packages/<pkg>/skills` from the repo root to validate one package without root-level packaging warnings.
|
|
102
|
+
- Run `npx @tanstack/intent@latest stale` from the repo root to check all workspace packages with skills, or `intent stale packages/<pkg>` to check one package.
|
|
103
|
+
|
|
67
104
|
## Keeping skills current
|
|
68
105
|
|
|
69
106
|
The real risk with any derived artifact is staleness. `npx @tanstack/intent@latest stale` flags skills whose source docs have changed, and CI templates catch drift before it ships.
|
|
70
107
|
|
|
71
|
-
The feedback loop runs both directions. `npx @tanstack/intent@latest feedback` lets users submit structured reports when a skill produces wrong output — which skill, which version, what broke. That context flows back to the maintainer, and the fix ships to everyone on the next
|
|
108
|
+
The feedback loop runs both directions. `npx @tanstack/intent@latest feedback` lets users submit structured reports when a skill produces wrong output — which skill, which version, what broke. That context flows back to the maintainer, and the fix ships to everyone on the next package update. Every support interaction produces an artifact that prevents the same class of problem for all future users — not just the one who reported it.
|
|
72
109
|
|
|
73
110
|
## CLI Commands
|
|
74
111
|
|
|
@@ -80,7 +117,7 @@ The feedback loop runs both directions. `npx @tanstack/intent@latest feedback` l
|
|
|
80
117
|
| `npx @tanstack/intent@latest scaffold` | Print the guided skill generation prompt |
|
|
81
118
|
| `npx @tanstack/intent@latest validate [dir]` | Validate SKILL.md files |
|
|
82
119
|
| `npx @tanstack/intent@latest setup-github-actions` | Copy CI templates into your repo |
|
|
83
|
-
| `npx @tanstack/intent@latest stale [--json]`
|
|
120
|
+
| `npx @tanstack/intent@latest stale [dir] [--json]` | Check skills for version drift |
|
|
84
121
|
| `npx @tanstack/intent@latest feedback` | Submit skill feedback |
|
|
85
122
|
|
|
86
123
|
## License
|
package/dist/cli.d.mts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
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";
|
|
4
|
+
declare function main(argv?: Array<string>): Promise<number>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { USAGE, main };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,39 +1,88 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-D_XzuGnu.mjs";
|
|
5
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { t as INSTALL_PROMPT } from "./install-prompt-C0M-U3WZ.mjs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
6
4
|
import { dirname, join, relative, sep } from "node:path";
|
|
7
|
-
import { parse } from "yaml";
|
|
8
5
|
import { fileURLToPath } from "node:url";
|
|
9
6
|
|
|
10
7
|
//#region src/cli.ts
|
|
11
8
|
function getMetaDir() {
|
|
12
9
|
return join(dirname(fileURLToPath(import.meta.url)), "..", "meta");
|
|
13
10
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
function fail(message, exitCode = 1) {
|
|
12
|
+
throw {
|
|
13
|
+
message,
|
|
14
|
+
exitCode
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function isCliFailure(value) {
|
|
18
|
+
return !!value && typeof value === "object" && "message" in value && typeof value.message === "string" && "exitCode" in value && typeof value.exitCode === "number";
|
|
19
|
+
}
|
|
20
|
+
async function scanIntentsOrFail() {
|
|
21
|
+
const { scanForIntents } = await import("./scanner-BHPl60jH.mjs");
|
|
17
22
|
try {
|
|
18
|
-
|
|
23
|
+
return await scanForIntents();
|
|
19
24
|
} catch (err) {
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
fail(err.message);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function printWarnings(warnings) {
|
|
29
|
+
if (warnings.length === 0) return;
|
|
30
|
+
console.log("Warnings:");
|
|
31
|
+
for (const warning of warnings) console.log(` ⚠ ${warning}`);
|
|
32
|
+
}
|
|
33
|
+
function formatScanCoverage(result) {
|
|
34
|
+
const coverage = [];
|
|
35
|
+
if (result.nodeModules.local.scanned) coverage.push("project node_modules");
|
|
36
|
+
if (result.nodeModules.global.scanned) coverage.push("global node_modules");
|
|
37
|
+
return coverage.join(", ");
|
|
38
|
+
}
|
|
39
|
+
function printVersionConflicts(result) {
|
|
40
|
+
if (result.conflicts.length === 0) return;
|
|
41
|
+
console.log("\nVersion conflicts:\n");
|
|
42
|
+
for (const conflict of result.conflicts) {
|
|
43
|
+
console.log(` ${conflict.packageName} -> using ${conflict.chosen.version}`);
|
|
44
|
+
console.log(` chosen: ${conflict.chosen.packageRoot}`);
|
|
45
|
+
for (const variant of conflict.variants) {
|
|
46
|
+
if (variant.packageRoot === conflict.chosen.packageRoot) continue;
|
|
47
|
+
console.log(` also found: ${variant.version} at ${variant.packageRoot}`);
|
|
48
|
+
}
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function buildValidationFailure(errors, warnings) {
|
|
53
|
+
const lines = [
|
|
54
|
+
"",
|
|
55
|
+
`❌ Validation failed with ${errors.length} error(s):`,
|
|
56
|
+
""
|
|
57
|
+
];
|
|
58
|
+
for (const { file, message } of errors) lines.push(` ${file}: ${message}`);
|
|
59
|
+
if (warnings.length > 0) {
|
|
60
|
+
lines.push("", "⚠ Packaging warnings:");
|
|
61
|
+
for (const warning of warnings) lines.push(` ${warning}`);
|
|
22
62
|
}
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
async function cmdList(args) {
|
|
66
|
+
const { computeSkillNameWidth, printSkillTree, printTable } = await import("./display-CuCDLPP_.mjs");
|
|
67
|
+
const jsonOutput = args.includes("--json");
|
|
68
|
+
const result = await scanIntentsOrFail();
|
|
23
69
|
if (jsonOutput) {
|
|
24
70
|
console.log(JSON.stringify(result, null, 2));
|
|
25
71
|
return;
|
|
26
72
|
}
|
|
73
|
+
const scanCoverage = formatScanCoverage(result);
|
|
27
74
|
if (result.packages.length === 0) {
|
|
28
75
|
console.log("No intent-enabled packages found.");
|
|
76
|
+
if (scanCoverage) console.log(`Scanned: ${scanCoverage}`);
|
|
29
77
|
if (result.warnings.length > 0) {
|
|
30
|
-
console.log(
|
|
31
|
-
|
|
78
|
+
console.log();
|
|
79
|
+
printWarnings(result.warnings);
|
|
32
80
|
}
|
|
33
81
|
return;
|
|
34
82
|
}
|
|
35
83
|
const totalSkills = result.packages.reduce((sum, p) => sum + p.skills.length, 0);
|
|
36
84
|
console.log(`\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`);
|
|
85
|
+
if (scanCoverage) console.log(`Scanned: ${scanCoverage}${result.nodeModules.global.scanned ? " (local packages take precedence)" : ""}\n`);
|
|
37
86
|
printTable([
|
|
38
87
|
"PACKAGE",
|
|
39
88
|
"VERSION",
|
|
@@ -45,6 +94,7 @@ async function cmdList(args) {
|
|
|
45
94
|
String(pkg.skills.length),
|
|
46
95
|
pkg.intent.requires?.join(", ") || "–"
|
|
47
96
|
]));
|
|
97
|
+
printVersionConflicts(result);
|
|
48
98
|
const nameWidth = computeSkillNameWidth(result.packages.map((p) => p.skills));
|
|
49
99
|
const showTypes = result.packages.some((p) => p.skills.some((s) => s.type));
|
|
50
100
|
console.log(`\nSkills:\n`);
|
|
@@ -60,35 +110,21 @@ async function cmdList(args) {
|
|
|
60
110
|
console.log(` Submit feedback on skill usage to help maintainers improve the skills.`);
|
|
61
111
|
console.log(` Load: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md`);
|
|
62
112
|
console.log();
|
|
63
|
-
|
|
64
|
-
console.log(`Warnings:`);
|
|
65
|
-
for (const w of result.warnings) console.log(` ⚠ ${w}`);
|
|
66
|
-
}
|
|
113
|
+
printWarnings(result.warnings);
|
|
67
114
|
}
|
|
68
|
-
function cmdMeta(args) {
|
|
115
|
+
async function cmdMeta(args) {
|
|
116
|
+
const { parseFrontmatter } = await import("./utils-D7OKi0Rn.mjs");
|
|
69
117
|
const metaDir = getMetaDir();
|
|
70
|
-
if (!existsSync(metaDir))
|
|
71
|
-
console.error("Meta-skills directory not found.");
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
118
|
+
if (!existsSync(metaDir)) fail("Meta-skills directory not found.");
|
|
74
119
|
if (args.length > 0) {
|
|
75
120
|
const name = args[0];
|
|
76
|
-
if (name.includes("..") || name.includes("/") || name.includes("\\")) {
|
|
77
|
-
console.error(`Invalid meta-skill name: "${name}"`);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
121
|
+
if (name.includes("..") || name.includes("/") || name.includes("\\")) fail(`Invalid meta-skill name: "${name}"`);
|
|
80
122
|
const skillFile = join(metaDir, name, "SKILL.md");
|
|
81
|
-
if (!existsSync(skillFile)) {
|
|
82
|
-
console.error(`Meta-skill "${name}" not found.`);
|
|
83
|
-
console.error(`Run \`npx @tanstack/intent meta\` to list available meta-skills.`);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
123
|
+
if (!existsSync(skillFile)) fail(`Meta-skill "${name}" not found. Run \`intent meta\` to list available meta-skills.`);
|
|
86
124
|
try {
|
|
87
125
|
console.log(readFileSync(skillFile, "utf8"));
|
|
88
126
|
} catch (err) {
|
|
89
|
-
|
|
90
|
-
console.error(`Failed to read meta-skill "${name}": ${msg}`);
|
|
91
|
-
process.exit(1);
|
|
127
|
+
fail(`Failed to read meta-skill "${name}": ${err instanceof Error ? err.message : String(err)}`);
|
|
92
128
|
}
|
|
93
129
|
return;
|
|
94
130
|
}
|
|
@@ -131,19 +167,45 @@ function collectPackagingWarnings(root) {
|
|
|
131
167
|
}
|
|
132
168
|
return warnings;
|
|
133
169
|
}
|
|
134
|
-
function
|
|
170
|
+
function resolvePackageRoot(startDir) {
|
|
171
|
+
let dir = startDir;
|
|
172
|
+
while (true) {
|
|
173
|
+
if (existsSync(join(dir, "package.json"))) return dir;
|
|
174
|
+
const next = dirname(dir);
|
|
175
|
+
if (next === dir) return startDir;
|
|
176
|
+
dir = next;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function readPackageName(root) {
|
|
180
|
+
try {
|
|
181
|
+
const pkgJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
182
|
+
return typeof pkgJson.name === "string" ? pkgJson.name : relative(process.cwd(), root) || "unknown";
|
|
183
|
+
} catch {
|
|
184
|
+
return relative(process.cwd(), root) || "unknown";
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function resolveStaleTargets(targetDir) {
|
|
188
|
+
const resolvedRoot = targetDir ? join(process.cwd(), targetDir) : process.cwd();
|
|
189
|
+
const { checkStaleness } = await import("./staleness-Dr5-5wj5.mjs");
|
|
190
|
+
if (existsSync(join(resolvedRoot, "skills"))) return { reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))] };
|
|
191
|
+
const { findPackagesWithSkills, findWorkspaceRoot } = await import("./setup.mjs");
|
|
192
|
+
const workspaceRoot = findWorkspaceRoot(resolvedRoot);
|
|
193
|
+
if (workspaceRoot) {
|
|
194
|
+
const packageDirs = findPackagesWithSkills(workspaceRoot);
|
|
195
|
+
if (packageDirs.length > 0) return { reports: await Promise.all(packageDirs.map((packageDir) => checkStaleness(packageDir, readPackageName(packageDir)))) };
|
|
196
|
+
}
|
|
197
|
+
const staleResult = await scanIntentsOrFail();
|
|
198
|
+
return { reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))) };
|
|
199
|
+
}
|
|
200
|
+
async function cmdValidate(args) {
|
|
201
|
+
const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-D7OKi0Rn.mjs")]);
|
|
135
202
|
const targetDir = args[0] ?? "skills";
|
|
136
203
|
const skillsDir = join(process.cwd(), targetDir);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
process.exit(1);
|
|
140
|
-
}
|
|
204
|
+
const packageRoot = resolvePackageRoot(skillsDir);
|
|
205
|
+
if (!existsSync(skillsDir)) fail(`Skills directory not found: ${skillsDir}`);
|
|
141
206
|
const errors = [];
|
|
142
207
|
const skillFiles = findSkillFiles(skillsDir);
|
|
143
|
-
if (skillFiles.length === 0)
|
|
144
|
-
console.error("No SKILL.md files found");
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
208
|
+
if (skillFiles.length === 0) fail("No SKILL.md files found");
|
|
147
209
|
for (const filePath of skillFiles) {
|
|
148
210
|
const rel = relative(process.cwd(), filePath);
|
|
149
211
|
const content = readFileSync(filePath, "utf8");
|
|
@@ -164,7 +226,7 @@ function cmdValidate(args) {
|
|
|
164
226
|
}
|
|
165
227
|
let fm;
|
|
166
228
|
try {
|
|
167
|
-
fm =
|
|
229
|
+
fm = parseYaml(match[1]);
|
|
168
230
|
} catch {
|
|
169
231
|
errors.push({
|
|
170
232
|
file: rel,
|
|
@@ -224,7 +286,7 @@ function cmdValidate(args) {
|
|
|
224
286
|
continue;
|
|
225
287
|
}
|
|
226
288
|
if (fileName.endsWith(".yaml")) try {
|
|
227
|
-
|
|
289
|
+
parseYaml(content);
|
|
228
290
|
} catch {
|
|
229
291
|
errors.push({
|
|
230
292
|
file: relative(process.cwd(), artifactPath),
|
|
@@ -232,20 +294,11 @@ function cmdValidate(args) {
|
|
|
232
294
|
});
|
|
233
295
|
}
|
|
234
296
|
}
|
|
235
|
-
const warnings = collectPackagingWarnings(
|
|
236
|
-
|
|
237
|
-
if (warnings.length === 0) return;
|
|
238
|
-
log(`\n⚠ Packaging warnings:`);
|
|
239
|
-
for (const w of warnings) log(` ${w}`);
|
|
240
|
-
};
|
|
241
|
-
if (errors.length > 0) {
|
|
242
|
-
console.error(`\n❌ Validation failed with ${errors.length} error(s):\n`);
|
|
243
|
-
for (const { file, message } of errors) console.error(` ${file}: ${message}`);
|
|
244
|
-
printWarnings(console.error);
|
|
245
|
-
process.exit(1);
|
|
246
|
-
}
|
|
297
|
+
const warnings = collectPackagingWarnings(packageRoot);
|
|
298
|
+
if (errors.length > 0) fail(buildValidationFailure(errors, warnings));
|
|
247
299
|
console.log(`✅ Validated ${skillFiles.length} skill files — all passed`);
|
|
248
|
-
|
|
300
|
+
if (warnings.length > 0) console.log();
|
|
301
|
+
printWarnings(warnings);
|
|
249
302
|
}
|
|
250
303
|
function cmdScaffold() {
|
|
251
304
|
const metaDir = getMetaDir();
|
|
@@ -306,7 +359,7 @@ This produces: individual SKILL.md files.
|
|
|
306
359
|
|
|
307
360
|
## After all skills are generated
|
|
308
361
|
|
|
309
|
-
1. Run \`
|
|
362
|
+
1. Run \`intent validate\` in each package directory
|
|
310
363
|
2. Commit skills/ and artifacts
|
|
311
364
|
3. For each publishable package, run: \`npx @tanstack/intent add-library-bin\`
|
|
312
365
|
4. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
|
|
@@ -327,122 +380,152 @@ Usage:
|
|
|
327
380
|
intent add-library-bin Generate bin/intent.{js,mjs} bridge file
|
|
328
381
|
intent edit-package-json Wire package.json (files, bin) for skill publishing
|
|
329
382
|
intent setup-github-actions Copy CI workflow templates to .github/workflows/
|
|
330
|
-
intent stale
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
case "stale": {
|
|
395
|
-
const { checkStaleness } = await import("./staleness-C1h7RuZ9.mjs");
|
|
396
|
-
const { scanForIntents: scanStale } = await import("./scanner-CECGXgox.mjs");
|
|
397
|
-
let staleResult;
|
|
398
|
-
try {
|
|
399
|
-
staleResult = await scanStale();
|
|
400
|
-
} catch (err) {
|
|
401
|
-
console.error(err.message);
|
|
402
|
-
process.exit(1);
|
|
383
|
+
intent stale [dir] [--json] Check skills for staleness`;
|
|
384
|
+
const HELP_BY_COMMAND = {
|
|
385
|
+
list: `${USAGE}
|
|
386
|
+
|
|
387
|
+
Examples:
|
|
388
|
+
intent list
|
|
389
|
+
intent list --json`,
|
|
390
|
+
meta: `intent meta [name]
|
|
391
|
+
|
|
392
|
+
List shipped meta-skills, or print a single meta-skill by name.
|
|
393
|
+
|
|
394
|
+
Examples:
|
|
395
|
+
intent meta
|
|
396
|
+
intent meta domain-discovery`,
|
|
397
|
+
validate: `intent validate [dir]
|
|
398
|
+
|
|
399
|
+
Validate SKILL.md files in the target directory.
|
|
400
|
+
|
|
401
|
+
Examples:
|
|
402
|
+
intent validate
|
|
403
|
+
intent validate packages/query/skills`,
|
|
404
|
+
install: `intent install
|
|
405
|
+
|
|
406
|
+
Print the install prompt used to set up skill-to-task mappings.`,
|
|
407
|
+
scaffold: `intent scaffold
|
|
408
|
+
|
|
409
|
+
Print the guided maintainer prompt for generating skills.`,
|
|
410
|
+
stale: `intent stale [dir] [--json]
|
|
411
|
+
|
|
412
|
+
Check installed skills for version and source drift.
|
|
413
|
+
|
|
414
|
+
Examples:
|
|
415
|
+
intent stale
|
|
416
|
+
intent stale packages/query
|
|
417
|
+
intent stale --json`,
|
|
418
|
+
"add-library-bin": `intent add-library-bin
|
|
419
|
+
|
|
420
|
+
Generate bin/intent.{js,mjs} bridge files for publishable packages.`,
|
|
421
|
+
"edit-package-json": `intent edit-package-json
|
|
422
|
+
|
|
423
|
+
Update package.json files so skills and shims are published.`,
|
|
424
|
+
"setup-github-actions": `intent setup-github-actions
|
|
425
|
+
|
|
426
|
+
Copy Intent CI workflow templates into .github/workflows/.`
|
|
427
|
+
};
|
|
428
|
+
function isHelpFlag(arg) {
|
|
429
|
+
return arg === "-h" || arg === "--help";
|
|
430
|
+
}
|
|
431
|
+
function printHelp(command) {
|
|
432
|
+
if (!command) {
|
|
433
|
+
console.log(`${USAGE}
|
|
434
|
+
|
|
435
|
+
Run \`intent help <command>\` for details on a specific command.`);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
console.log(HELP_BY_COMMAND[command] ?? USAGE);
|
|
439
|
+
}
|
|
440
|
+
async function main(argv = process.argv.slice(2)) {
|
|
441
|
+
const command = argv[0];
|
|
442
|
+
const commandArgs = argv.slice(1);
|
|
443
|
+
try {
|
|
444
|
+
if (!command || isHelpFlag(command)) {
|
|
445
|
+
printHelp();
|
|
446
|
+
return 0;
|
|
403
447
|
}
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
|
|
448
|
+
if (command === "help") {
|
|
449
|
+
printHelp(commandArgs[0]);
|
|
450
|
+
return 0;
|
|
407
451
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return
|
|
411
|
-
}));
|
|
412
|
-
if (jsonStale) {
|
|
413
|
-
console.log(JSON.stringify(reports, null, 2));
|
|
414
|
-
break;
|
|
452
|
+
if (isHelpFlag(commandArgs[0])) {
|
|
453
|
+
printHelp(command);
|
|
454
|
+
return 0;
|
|
415
455
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
456
|
+
switch (command) {
|
|
457
|
+
case "list":
|
|
458
|
+
await cmdList(commandArgs);
|
|
459
|
+
return 0;
|
|
460
|
+
case "meta":
|
|
461
|
+
await cmdMeta(commandArgs);
|
|
462
|
+
return 0;
|
|
463
|
+
case "validate":
|
|
464
|
+
await cmdValidate(commandArgs);
|
|
465
|
+
return 0;
|
|
466
|
+
case "install":
|
|
467
|
+
console.log(INSTALL_PROMPT);
|
|
468
|
+
return 0;
|
|
469
|
+
case "scaffold":
|
|
470
|
+
cmdScaffold();
|
|
471
|
+
return 0;
|
|
472
|
+
case "stale": {
|
|
473
|
+
const jsonStale = commandArgs.includes("--json");
|
|
474
|
+
const { reports } = await resolveStaleTargets(commandArgs.find((arg) => !arg.startsWith("-")));
|
|
475
|
+
if (reports.length === 0) {
|
|
476
|
+
console.log("No intent-enabled packages found.");
|
|
477
|
+
return 0;
|
|
478
|
+
}
|
|
479
|
+
if (jsonStale) {
|
|
480
|
+
console.log(JSON.stringify(reports, null, 2));
|
|
481
|
+
return 0;
|
|
482
|
+
}
|
|
483
|
+
for (const report of reports) {
|
|
484
|
+
const driftLabel = report.versionDrift ? ` [${report.versionDrift} drift]` : "";
|
|
485
|
+
const vLabel = report.skillVersion && report.currentVersion ? ` (${report.skillVersion} → ${report.currentVersion})` : "";
|
|
486
|
+
console.log(`${report.library}${vLabel}${driftLabel}`);
|
|
487
|
+
const stale = report.skills.filter((s) => s.needsReview);
|
|
488
|
+
if (stale.length === 0) console.log(" All skills up-to-date");
|
|
489
|
+
else for (const skill of stale) console.log(` ⚠ ${skill.name}: ${skill.reasons.join(", ")}`);
|
|
490
|
+
console.log();
|
|
491
|
+
}
|
|
492
|
+
return 0;
|
|
493
|
+
}
|
|
494
|
+
case "add-library-bin": {
|
|
495
|
+
const { runAddLibraryBinAll } = await import("./setup.mjs");
|
|
496
|
+
runAddLibraryBinAll(process.cwd());
|
|
497
|
+
return 0;
|
|
498
|
+
}
|
|
499
|
+
case "edit-package-json": {
|
|
500
|
+
const { runEditPackageJsonAll } = await import("./setup.mjs");
|
|
501
|
+
runEditPackageJsonAll(process.cwd());
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
case "setup-github-actions": {
|
|
505
|
+
const { runSetupGithubActions } = await import("./setup.mjs");
|
|
506
|
+
runSetupGithubActions(process.cwd(), getMetaDir());
|
|
507
|
+
return 0;
|
|
508
|
+
}
|
|
509
|
+
default:
|
|
510
|
+
printHelp();
|
|
511
|
+
return command ? 1 : 0;
|
|
424
512
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
case "edit-package-json": {
|
|
433
|
-
const { runEditPackageJson } = await import("./setup.mjs");
|
|
434
|
-
runEditPackageJson(process.cwd());
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
case "setup-github-actions": {
|
|
438
|
-
const { runSetupGithubActions } = await import("./setup.mjs");
|
|
439
|
-
runSetupGithubActions(process.cwd(), getMetaDir());
|
|
440
|
-
break;
|
|
513
|
+
} catch (err) {
|
|
514
|
+
if (isCliFailure(err)) {
|
|
515
|
+
console.error(err.message);
|
|
516
|
+
return err.exitCode;
|
|
517
|
+
}
|
|
518
|
+
throw err;
|
|
441
519
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
520
|
+
}
|
|
521
|
+
let isMain = false;
|
|
522
|
+
try {
|
|
523
|
+
isMain = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(process.argv[1]);
|
|
524
|
+
} catch {}
|
|
525
|
+
if (isMain) {
|
|
526
|
+
const exitCode = await main();
|
|
527
|
+
process.exit(exitCode);
|
|
445
528
|
}
|
|
446
529
|
|
|
447
530
|
//#endregion
|
|
448
|
-
export {
|
|
531
|
+
export { USAGE, main };
|